001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004     *
005     *   This file is part of the Granite Data Services Platform.
006     *
007     *   Granite Data Services is free software; you can redistribute it and/or
008     *   modify it under the terms of the GNU Lesser General Public
009     *   License as published by the Free Software Foundation; either
010     *   version 2.1 of the License, or (at your option) any later version.
011     *
012     *   Granite Data Services is distributed in the hope that it will be useful,
013     *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015     *   General Public License for more details.
016     *
017     *   You should have received a copy of the GNU Lesser General Public
018     *   License along with this library; if not, write to the Free Software
019     *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020     *   USA, or see <http://www.gnu.org/licenses/>.
021     */
022    package org.granite.messaging.jmf.codec.std.impl;
023    
024    import java.io.IOException;
025    import java.io.OutputStream;
026    import java.lang.reflect.Array;
027    
028    import org.granite.messaging.jmf.CodecRegistry;
029    import org.granite.messaging.jmf.DumpContext;
030    import org.granite.messaging.jmf.InputContext;
031    import org.granite.messaging.jmf.JMFEncodingException;
032    import org.granite.messaging.jmf.OutputContext;
033    import org.granite.messaging.jmf.codec.StandardCodec;
034    import org.granite.messaging.jmf.codec.std.ArrayCodec;
035    import org.granite.messaging.jmf.codec.std.IntegerCodec;
036    import org.granite.messaging.jmf.codec.std.LongCodec;
037    
038    /**
039     * @author Franck WOLFF
040     */
041    public class ArrayCodecImpl extends AbstractIntegerStringCodec<Object> implements ArrayCodec {
042            
043            public int getObjectType() {
044                    return JMF_ARRAY;
045            }
046    
047            public boolean canEncode(Object v) {
048                    return v.getClass().isArray();
049            }
050    
051            public void encode(OutputContext ctx, Object v) throws IOException {
052                    int dimensions = getArrayDimensions(v);
053                    Class<?> componentType = getComponentType(v);
054                    
055                    int jmfComponentType = ctx.getSharedContext().getCodecRegistry().jmfTypeOfPrimitiveClass(componentType);
056                    if (jmfComponentType != -1)
057                            writePrimitiveArray(ctx, v, jmfComponentType, dimensions, true);
058                    else
059                            writeObjectArray(ctx, v, dimensions, true);
060            }
061            
062            public Object decode(InputContext ctx, int parameterizedJmfType) throws IOException, ClassNotFoundException {
063                    final CodecRegistry codecRegistry = ctx.getSharedContext().getCodecRegistry();
064                    
065                    int jmfType = codecRegistry.extractJmfType(parameterizedJmfType);
066                    
067                    if (jmfType != JMF_ARRAY)
068                            throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
069    
070                    Object v = null;
071                    
072                    int indexOrLength = readIntData(ctx, (parameterizedJmfType >> 4) & 0x03, false);
073                    if ((parameterizedJmfType & 0x80) != 0)
074                            v = ctx.getSharedObject(indexOrLength);
075                    else {
076                            int dimensions = ((parameterizedJmfType & 0x40) == 0 ? 0 : ctx.safeRead());
077                            int parameterizedJmfComponentType = ctx.safeRead();
078                            int jmfComponentType = codecRegistry.extractJmfType(parameterizedJmfComponentType);
079                            
080                            Class<?> componentType = codecRegistry.primitiveClassOfJmfType(jmfComponentType);
081                            
082                            if (componentType != null)
083                                    v = readPrimitiveArray(ctx, componentType, jmfComponentType, indexOrLength, dimensions);
084                            else
085                                    v = readObjectArray(ctx, parameterizedJmfComponentType, indexOrLength, dimensions);
086                    }
087                    
088                    return v;
089            }
090            
091            public void dump(DumpContext ctx, int parameterizedJmfType) throws IOException {
092                    final CodecRegistry codecRegistry = ctx.getSharedContext().getCodecRegistry();
093    
094                    int jmfType = codecRegistry.extractJmfType(parameterizedJmfType);
095                    
096                    if (jmfType != JMF_ARRAY)
097                            throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
098                    
099                    int indexOrLength = readIntData(ctx, (parameterizedJmfType >> 4) & 0x03, false);
100                    if ((parameterizedJmfType & 0x80) != 0)
101                            ctx.indentPrintLn("<" + ctx.getSharedObject(indexOrLength) + "@" + indexOrLength + ">");
102                    else {
103                            int dimensions = ((parameterizedJmfType & 0x40) == 0 ? 0 : ctx.safeRead());
104                            int parameterizedJmfComponentType = ctx.safeRead();
105                            int jmfComponentType = codecRegistry.extractJmfType(parameterizedJmfComponentType);
106                            
107                            Class<?> componentType = codecRegistry.primitiveClassOfJmfType(jmfComponentType);
108                            
109                            if (componentType != null)
110                                    dumpPrimitiveArray(ctx, componentType, jmfComponentType, indexOrLength, dimensions);
111                            else
112                                    dumpObjectArray(ctx, parameterizedJmfComponentType, indexOrLength, dimensions);
113                    }
114            }
115    
116            protected void writeObjectArray(OutputContext ctx, Object v, int dimensions, boolean writeDimensions) throws IOException {
117                    final OutputStream os = ctx.getOutputStream();
118                    
119                    if (v == null)
120                            os.write(JMF_NULL);
121                    else {
122                            int indexOfStoredObject = ctx.indexOfStoredObjects(v);
123                            if (indexOfStoredObject >= 0) {
124                                    IntegerComponents ics = intComponents(indexOfStoredObject);
125                                    ctx.getOutputStream().write(0x80 | (ics.length << 4) | JMF_ARRAY);
126                                    writeIntData(ctx, ics);
127                            }
128                            else {
129                                    ctx.addToStoredObjects(v);
130                                    
131                                    if (dimensions == 0)
132                                            writeObjectArray(ctx, v);
133                                    else {
134                                            int length = Array.getLength(v);
135                                            
136                                            IntegerComponents ics = intComponents(length);
137                                            if (writeDimensions) {
138                                                    os.write(0x40 | (ics.length << 4) | JMF_ARRAY);
139                                                    writeIntData(ctx, ics);
140                                                    os.write(dimensions);
141                                            }
142                                            else {
143                                                    os.write((ics.length << 4) | JMF_ARRAY);
144                                                    writeIntData(ctx, ics);
145                                            }
146                                            
147                                            Class<?> componentType = getComponentType(v);
148                                            String className = ctx.getAlias(componentType.getName());
149                                            writeString(ctx, className, JMF_STRING_TYPE_HANDLER);
150                                            
151                                            int subDimensions = dimensions - 1;
152                                            for (int index = 0; index < length; index++)
153                                                    writeObjectArray(ctx, Array.get(v, index), subDimensions, false);
154                                    }
155                            }
156                    }
157            }
158            
159            protected void writeObjectArray(OutputContext ctx, Object v) throws IOException {
160                    final OutputStream os = ctx.getOutputStream();
161    
162                    int length = Array.getLength(v);
163                    Class<?> componentType = v.getClass().getComponentType();
164                    String className = ctx.getAlias(componentType.getName());
165                    
166                    IntegerComponents ics = intComponents(length);
167                    os.write((ics.length << 4) | JMF_ARRAY);
168                    writeIntData(ctx, ics);
169    
170                    writeString(ctx, className, JMF_STRING_TYPE_HANDLER);
171                    for (int index = 0; index < length; index++)
172                            ctx.writeObject(Array.get(v, index));
173            }
174            
175            protected void writePrimitiveArray(OutputContext ctx, Object v, int jmfComponentType, int dimensions, boolean writeDimensionsAndType) throws IOException {
176                    final OutputStream os = ctx.getOutputStream();
177    
178                    if (v == null)
179                            os.write(JMF_NULL);
180                    else {
181                            int indexOfStoredObject = ctx.indexOfStoredObjects(v);
182                            if (indexOfStoredObject >= 0) {
183                                    IntegerComponents ics = intComponents(indexOfStoredObject);
184                                    ctx.getOutputStream().write(0x80 | (ics.length << 4) | JMF_ARRAY);
185                                    writeIntData(ctx, ics);
186                            }
187                            else {
188                                    ctx.addToStoredObjects(v);
189                                    if (dimensions == 0)
190                                            writePrimitiveArray(ctx, v, jmfComponentType, writeDimensionsAndType);
191                                    else {
192                                            int length = Array.getLength(v);
193                                            
194                                            IntegerComponents ics = intComponents(length);
195                                            if (writeDimensionsAndType) {
196                                                    os.write(0x40 | (ics.length << 4) | JMF_ARRAY);
197                                                    writeIntData(ctx, ics);
198                                                    os.write(dimensions);
199                                                    os.write(jmfComponentType);
200                                            }
201                                            else {
202                                                    os.write((ics.length << 4) | JMF_ARRAY);
203                                                    writeIntData(ctx, ics);
204                                            }
205                                            
206                                            int subDimensions = dimensions - 1;
207                                            for (int index = 0; index < length; index++)
208                                                    writePrimitiveArray(ctx, Array.get(v, index), jmfComponentType, subDimensions, false);
209                                    }
210                            }
211                    }
212            }
213            
214            protected void writePrimitiveArray(OutputContext ctx, Object v, int jmfComponentType, boolean writeType) throws IOException {
215                    final OutputStream os = ctx.getOutputStream();
216    
217                    final int length = Array.getLength(v);
218                    
219                    IntegerComponents ics = intComponents(length);
220                    os.write((ics.length << 4) | JMF_ARRAY);
221                    writeIntData(ctx, ics);
222                    
223                    if (writeType)
224                            os.write(jmfComponentType);
225                    
226                    if (length == 0)
227                            return;
228                    
229                    switch (jmfComponentType) {
230                            case JMF_BOOLEAN: {
231                                    byte[] bytes = new byte[lengthOfBooleanArray(length)];
232                                    int i = 0, j = 0;
233                                    for (boolean b : (boolean[])v) {
234                                            if (b)
235                                                    bytes[i] |= 0x80 >> j;
236                                            j++;
237                                            if (j >= 8) {
238                                                    j = 0;
239                                                    i++;
240                                            }
241                                    }
242                                    os.write(bytes);
243                                    break;
244                            }
245                            
246                            case JMF_CHARACTER: {
247                                    char[] a = (char[])v;
248                                    for (char c : a) {
249                                            os.write(c >> 8);
250                                            os.write(c);
251                                    }
252                                    break;
253                            }
254                            
255                            case JMF_BYTE: {
256                                    os.write((byte[])v);
257                                    break;
258                            }
259                            
260                            case JMF_SHORT: {
261                                    short[] a = (short[])v;
262                                    for (short s : a) {
263                                            os.write(s >> 8);
264                                            os.write(s);
265                                    }
266                                    break;
267                            }
268                            
269                            case JMF_INTEGER: {
270                                    IntegerCodec integerCodec = ctx.getSharedContext().getCodecRegistry().getIntegerCodec();
271                                    int[] a = (int[])v;
272                                    for (int i : a)
273                                            integerCodec.writeVariableInt(ctx, i);
274                                    break;
275                            }
276                            
277                            case JMF_LONG: {
278                                    LongCodec longCodec = ctx.getSharedContext().getCodecRegistry().getLongCodec();
279                                    long[] a = (long[])v;
280                                    for (long l : a)
281                                            longCodec.writeVariableLong(ctx, l);
282                                    break;
283                            }
284                            
285                            case JMF_FLOAT: {
286                                    float[] a = (float[])v;
287                                    for (float f : a) {
288                                            int bits = Float.floatToIntBits(f);
289                                            os.write(bits);
290                                            os.write(bits >> 8);
291                                            os.write(bits >> 16);
292                                            os.write(bits >> 24);
293                                    }
294                                    break;
295                            }
296                            
297                            case JMF_DOUBLE: {
298                                    double[] a = (double[])v;
299                                    for (double d : a) {
300                                            long bits = Double.doubleToLongBits(d);
301                                            os.write((int)bits);
302                                            os.write((int)(bits >> 8));
303                                            os.write((int)(bits >> 16));
304                                            os.write((int)(bits >> 24));
305                                            os.write((int)(bits >> 32));
306                                            os.write((int)(bits >> 40));
307                                            os.write((int)(bits >> 48));
308                                            os.write((int)(bits >> 56));
309                                    }
310                                    break;
311                            }
312                            
313                            default:
314                                    throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
315                    }
316            }
317            
318            protected int getArrayDimensions(Object v) {
319                    return v.getClass().getName().lastIndexOf('[');
320            }
321            
322            protected Class<?> getComponentType(Object v) {
323                    Class<?> componentType = v.getClass().getComponentType();
324                    while (componentType.isArray())
325                            componentType = componentType.getComponentType();
326                    return componentType;
327            }
328            
329            protected Object readObjectArray(InputContext ctx, int parameterizedJmfComponentType, int length, int dimensions) throws IOException, ClassNotFoundException {
330                    Object v =  null;
331                    
332                    String componentTypeName = readString(ctx, parameterizedJmfComponentType, JMF_STRING_TYPE_HANDLER);
333                    componentTypeName = ctx.getAlias(componentTypeName);
334                    Class<?> componentType = ctx.getSharedContext().getReflection().loadClass(componentTypeName);
335                    
336                    if (dimensions == 0)
337                            v = readObjectArray(ctx, componentType, length);
338                    else {
339                            v = newArray(componentType, length, dimensions);
340                            ctx.addSharedObject(v);
341                            
342                            int subDimensions = dimensions - 1;
343                            for (int index = 0; index < length; index++) {
344                                    int subParameterizedJmfType = ctx.safeRead();
345                                    int subJmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(subParameterizedJmfType);
346    
347                                    if (subJmfType == JMF_NULL)
348                                            Array.set(v, index, null);
349                                    else if (subJmfType == JMF_ARRAY) {
350                                            int subLengthOrIndex = readIntData(ctx, (subParameterizedJmfType >> 4) & 0x03, false);
351                                            if ((subParameterizedJmfType & 0x80) != 0)
352                                                    Array.set(v, index, ctx.getSharedObject(subLengthOrIndex));
353                                            else {
354                                                    int subParameterizedJmfComponentType = ctx.safeRead();
355                                                    Array.set(v, index, readObjectArray(ctx, subParameterizedJmfComponentType, subLengthOrIndex, subDimensions));
356                                            }
357                                    }
358                                    else
359                                            newBadTypeJMFEncodingException(subJmfType, subParameterizedJmfType);
360                            }
361                    }
362                    
363                    return v;
364            }
365            
366            protected void dumpObjectArray(DumpContext ctx, int parameterizedJmfComponentType, int length, int dimensions) throws IOException {
367                    String componentTypeName = readString(ctx, parameterizedJmfComponentType, JMF_STRING_TYPE_HANDLER);
368                    
369                    if (dimensions == 0)
370                            dumpObjectArray(ctx, componentTypeName, length);
371                    else {
372                            String v = newDumpObjectArray(componentTypeName, length, dimensions);
373                            int indexOfStoredObject = ctx.addSharedObject(v);
374                            ctx.indentPrintLn(v + "@" + indexOfStoredObject + ": {");
375                            ctx.incrIndent(1);
376                            
377                            int subDimensions = dimensions - 1;
378                            for (int index = 0; index < length; index++) {
379                                    int subParameterizedJmfType = ctx.safeRead();
380                                    int subJmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(subParameterizedJmfType);
381    
382                                    if (subJmfType == JMF_NULL)
383                                            ctx.indentPrintLn("null");
384                                    else if (subJmfType == JMF_ARRAY) {
385                                            int subLengthOrIndex = readIntData(ctx, (subParameterizedJmfType >> 4) & 0x03, false);
386                                            if ((subParameterizedJmfType & 0x80) != 0)
387                                                    ctx.indentPrintLn("<" + ctx.getSharedObject(subLengthOrIndex) + "@" + subLengthOrIndex + ">");
388                                            else {
389                                                    int subParameterizedJmfComponentType = ctx.safeRead();
390                                                    dumpObjectArray(ctx, subParameterizedJmfComponentType, subLengthOrIndex, subDimensions);
391                                            }
392                                    }
393                                    else
394                                            newBadTypeJMFEncodingException(subJmfType, subParameterizedJmfType);
395                            }
396    
397                            ctx.incrIndent(-1);
398                            ctx.indentPrintLn("}");
399                    }
400            }
401            
402            protected Object readObjectArray(InputContext ctx, Class<?> componentType, int length) throws IOException, ClassNotFoundException {
403                    Object v = Array.newInstance(componentType, length);
404                    ctx.addSharedObject(v);
405                    
406                    for (int index = 0; index < length; index++)
407                            Array.set(v, index, ctx.readObject());
408                    
409                    return v;
410            }
411            
412            protected void dumpObjectArray(DumpContext ctx, String componentTypeName, int length) throws IOException {
413                    String v = newDumpObjectArray(componentTypeName, length, 0);
414                    int indexOfStoredObject = ctx.addSharedObject(v);
415                    ctx.indentPrintLn(v + "@" + indexOfStoredObject + ": {");
416                    ctx.incrIndent(1);
417                    
418                    for (int index = 0; index < length; index++) {
419                            int parameterizedJmfType = ctx.safeRead();
420                            int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType);
421                            StandardCodec<?> codec = ctx.getSharedContext().getCodecRegistry().getCodec(jmfType);
422                            
423                            if (codec == null)
424                                    throw new JMFEncodingException("No codec for JMF type: " + jmfType);
425                            
426                            codec.dump(ctx, parameterizedJmfType);
427                    }
428    
429                    ctx.incrIndent(-1);
430                    ctx.indentPrintLn("}");
431            }
432            
433            protected String newDumpObjectArray(String componentTypeName, int length, int dimensions) {
434                    StringBuilder sb = new StringBuilder(componentTypeName);
435                    
436                    sb.append('[').append(length).append(']');
437                    
438                    for (int i = 0; i < dimensions; i++)
439                            sb.append("[]");
440                    
441                    return sb.toString();
442                    
443            }
444            
445            protected Object readPrimitiveArray(InputContext ctx, Class<?> componentType, int jmfComponentType, int length, int dimensions) throws IOException {
446                    Object v =  null;
447                    
448                    if (dimensions == 0)
449                            v = readPrimitiveArray(ctx, componentType, jmfComponentType, length);
450                    else {
451                            v = newArray(componentType, length, dimensions);
452                            ctx.addSharedObject(v);
453                            
454                            int subDimensions = dimensions - 1;
455                            for (int index = 0; index < length; index++) {
456                                    int subArrayJmfType = ctx.safeRead();
457                                    if (subArrayJmfType == JMF_NULL)
458                                            Array.set(v, index, null);
459                                    else {
460                                            int subLengthOrIndex = readIntData(ctx, (subArrayJmfType >> 4) & 0x03, false);
461                                            if ((subArrayJmfType & 0x80) != 0)
462                                                    Array.set(v, index, ctx.getSharedObject(subLengthOrIndex));
463                                            else
464                                                    Array.set(v, index, readPrimitiveArray(ctx, componentType, jmfComponentType, subLengthOrIndex, subDimensions));
465                                    }
466                            }
467                    }
468                    
469                    return v;
470            }
471            
472            protected void dumpPrimitiveArray(DumpContext ctx, Class<?> componentType, int jmfComponentType, int length, int dimensions) throws IOException {
473                    if (dimensions == 0)
474                            dumpPrimitiveArray(ctx, componentType, jmfComponentType, length);
475                    else {
476                            String v = newDumpPrimitiveArray(jmfComponentType, length, dimensions);
477                            int indexOfStoredObject = ctx.addSharedObject(v);
478                            ctx.indentPrintLn(v + "@" + indexOfStoredObject + ": {");
479                            ctx.incrIndent(1);
480                            
481                            int subDimensions = dimensions - 1;
482                            for (int index = 0; index < length; index++) {
483                                    int subArrayJmfType = ctx.safeRead();
484                                    if (subArrayJmfType == JMF_NULL)
485                                            ctx.indentPrintLn("null");
486                                    else {
487                                            int subLengthOrIndex = readIntData(ctx, (subArrayJmfType >> 4) & 0x03, false);
488                                            if ((subArrayJmfType & 0x80) != 0)
489                                                    ctx.indentPrintLn("<" + ctx.getSharedObject(subLengthOrIndex) + "@" + subLengthOrIndex + ">");
490                                            else
491                                                    dumpPrimitiveArray(ctx, componentType, jmfComponentType, subLengthOrIndex, subDimensions);
492                                    }
493                            }
494                            
495                            ctx.incrIndent(-1);
496                            ctx.indentPrintLn("}");
497                    }
498            }
499            
500            protected Object readPrimitiveArray(InputContext ctx, Class<?> componentType, int jmfComponentType, int length) throws IOException {
501                    Object v = null;
502                    
503                    if (length == 0)
504                            v = Array.newInstance(componentType, length);
505                    else {
506                            switch (jmfComponentType) {
507                                    case JMF_BOOLEAN: {
508                                            boolean[] a = new boolean[length];
509                                            int nb = lengthOfBooleanArray(length);
510                                            for (int i = 0; i < nb; i++) {
511                                                    int b = ctx.safeRead();
512                                                    for (int j = 0; j < 8; j++) {
513                                                            int index = (i * 8) + j;
514                                                            if (index >= length)
515                                                                    break;
516                                                            a[index] = ((b & (0x80 >> j)) != 0);
517                                                    }
518                                            }
519                                            v = a;
520                                            break;
521                                    }
522                                    
523                                    case JMF_CHARACTER: {
524                                            char[] a = new char[length];
525                                            for (int i = 0; i < length; i++)
526                                                    a[i] = (char)((ctx.safeRead() << 8) | ctx.safeRead());
527                                            v = a;
528                                            break;
529                                    }
530                                    
531                                    case JMF_BYTE: {
532                                            byte[] a = new byte[length];
533                                            ctx.safeReadFully(a);
534                                            v = a;
535                                            break;
536                                    }
537                                    
538                                    case JMF_SHORT: {
539                                            short[] a = new short[length];
540                                            for (int i = 0; i < length; i++)
541                                                    a[i] = (short)((ctx.safeRead() << 8) | ctx.safeRead());
542                                            v = a;
543                                            break;
544                                    }
545                                    
546                                    case JMF_INTEGER: {
547                                            IntegerCodec integerCodec = ctx.getSharedContext().getCodecRegistry().getIntegerCodec();
548                                            int[] a = new int[length];
549                                            for (int i = 0; i < length; i++)
550                                                    a[i] = integerCodec.readVariableInt(ctx);
551                                            v = a;
552                                            break;
553                                    }
554                                    
555                                    case JMF_LONG: {
556                                            LongCodec longCodec = ctx.getSharedContext().getCodecRegistry().getLongCodec();
557                                            long[] a = new long[length];
558                                            for (int i = 0; i < length; i++)
559                                                    a[i] = longCodec.readVariableLong(ctx);
560                                            v = a;
561                                            break;
562                                    }
563                                    
564                                    case JMF_FLOAT: {
565                                            float[] a = new float[length];
566                                            for (int i = 0; i < length; i++) {
567                                                    int bits = ctx.safeRead();
568                                                    bits |= ctx.safeRead() << 8;
569                                                    bits |= ctx.safeRead() << 16;
570                                                    bits |= ctx.safeRead() << 24;
571                                                    a[i] = Float.intBitsToFloat(bits);
572                                            }
573                                            v = a;
574                                            break;
575                                    }
576                                    
577                                    case JMF_DOUBLE: {
578                                            double[] a = new double[length];
579                                            for (int i = 0; i < length; i++) {
580                                                    long bits = ctx.safeRead();
581                                                    bits |= ((long)ctx.safeRead()) << 8;
582                                                    bits |= ((long)ctx.safeRead()) << 16;
583                                                    bits |= ((long)ctx.safeRead()) << 24;
584                                                    bits |= ((long)ctx.safeRead()) << 32;
585                                                    bits |= ((long)ctx.safeRead()) << 40;
586                                                    bits |= ((long)ctx.safeRead()) << 48;
587                                                    bits |= ((long)ctx.safeRead()) << 56;
588                                                    a[i] = Double.longBitsToDouble(bits);
589                                            }
590                                            v = a;
591                                            break;
592                                    }
593                                    
594                                    default:
595                                            throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
596                            }
597                    }
598                    
599                    ctx.addSharedObject(v);
600                    
601                    return v;
602            }
603            
604            protected void dumpPrimitiveArray(DumpContext ctx, Class<?> componentType, int jmfComponentType, int length) throws IOException {
605    
606                    String v = newDumpPrimitiveArray(jmfComponentType, length, 0);
607                    int indexOfStoredObject = ctx.addSharedObject(v);
608                    ctx.indentPrint(v + "@" + indexOfStoredObject + ": {");
609                    
610                    switch (jmfComponentType) {
611                            case JMF_BOOLEAN: {
612                                    int nb = lengthOfBooleanArray(length);
613                                    for (int i = 0; i < nb; i++) {
614                                            int b = ctx.safeRead();
615                                            for (int j = 0; j < 8; j++) {
616                                                    int index = (i * 8) + j;
617                                                    if (index >= length)
618                                                            break;
619                                                    if (index > 0)
620                                                            ctx.print(", ");
621                                                    ctx.print(String.valueOf(((b & (0x80 >> j)) != 0)));
622                                            }
623                                    }
624                                    break;
625                            }
626                            
627                            case JMF_CHARACTER: {
628                                    for (int i = 0; i < length; i++) {
629                                            if (i > 0)
630                                                    ctx.print(", ");
631                                            ctx.print(String.valueOf((char)((ctx.safeRead() << 8) | ctx.safeRead())));
632                                    }
633                                    break;
634                            }
635                            
636                            case JMF_BYTE: {
637                                    for (int i = 0; i < length; i++) {
638                                            if (i > 0)
639                                                    ctx.print(", ");
640                                            ctx.print(String.valueOf((byte)ctx.safeRead()));
641                                    }
642                                    break;
643                            }
644                            
645                            case JMF_SHORT: {
646                                    for (int i = 0; i < length; i++) {
647                                            if (i > 0)
648                                                    ctx.print(", ");
649                                            ctx.print(String.valueOf((short)(ctx.safeRead() << 8) | ctx.safeRead()));
650                                    }
651                                    break;
652                            }
653                            
654                            case JMF_INTEGER: {
655                                    IntegerCodec integerCodec = ctx.getSharedContext().getCodecRegistry().getIntegerCodec();
656                                    for (int i = 0; i < length; i++) {
657                                            if (i > 0)
658                                                    ctx.print(", ");
659                                            ctx.print(String.valueOf(integerCodec.readVariableInt(ctx)));
660                                    }
661                                    break;
662                            }
663                            
664                            case JMF_LONG: {
665                                    LongCodec longCodec = ctx.getSharedContext().getCodecRegistry().getLongCodec();
666                                    for (int i = 0; i < length; i++) {
667                                            if (i > 0)
668                                                    ctx.print(", ");
669                                            ctx.print(String.valueOf(longCodec.readVariableLong(ctx)));
670                                    }
671                                    break;
672                            }
673                            
674                            case JMF_FLOAT: {
675                                    for (int i = 0; i < length; i++) {
676                                            if (i > 0)
677                                                    ctx.print(", ");
678                                            ctx.print(String.valueOf(FloatCodecImpl.readFloatData(ctx, jmfComponentType)));
679                                    }
680                                    break;
681                            }
682                            
683                            case JMF_DOUBLE: {
684                                    for (int i = 0; i < length; i++) {
685                                            if (i > 0)
686                                                    ctx.print(", ");
687                                            ctx.print(String.valueOf(DoubleCodecImpl.readDoubleData(ctx, jmfComponentType)));
688                                    }
689                                    break;
690                            }
691                            
692                            default:
693                                    throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
694                    }
695    
696                    ctx.noIndentPrintLn("}");
697            }
698            
699            protected String newDumpPrimitiveArray(int jmfComponentType, int length, int dimensions) throws IOException {
700                    StringBuilder sb = new StringBuilder();
701                    
702                    switch (jmfComponentType) {
703                            case JMF_BOOLEAN: sb.append("boolean"); break;
704                            case JMF_CHARACTER: sb.append("char"); break;
705                            case JMF_BYTE: sb.append("byte"); break;
706                            case JMF_SHORT: sb.append("short"); break;
707                            case JMF_INTEGER: sb.append("int"); break;
708                            case JMF_LONG: sb.append("long"); break;
709                            case JMF_FLOAT: sb.append("float"); break;
710                            case JMF_DOUBLE: sb.append("double"); break;
711                            default: throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
712                    }
713                    
714                    sb.append('[').append(length).append(']');
715                    
716                    for (int i = 0; i < dimensions; i++)
717                            sb.append("[]");
718                    
719                    return sb.toString();
720            }
721            
722            protected Object newArray(Class<?> type, int length, int dimensions) {
723                    int[] ld = new int[dimensions + 1];
724                    ld[0] = length;
725                    return Array.newInstance(type, ld);
726            }
727            
728            protected int lengthOfBooleanArray(int nb) {
729                    return (nb / 8) + (nb % 8 != 0 ? 1 : 0);
730            }
731    }