001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2013 GRANITE DATA SERVICES S.A.S.
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    
021    package org.granite.messaging.jmf.codec.std.impl;
022    
023    import java.io.IOException;
024    import java.io.OutputStream;
025    import java.lang.reflect.Array;
026    
027    import org.granite.messaging.jmf.CodecRegistry;
028    import org.granite.messaging.jmf.DumpContext;
029    import org.granite.messaging.jmf.InputContext;
030    import org.granite.messaging.jmf.JMFEncodingException;
031    import org.granite.messaging.jmf.OutputContext;
032    import org.granite.messaging.jmf.codec.StandardCodec;
033    import org.granite.messaging.jmf.codec.std.ArrayCodec;
034    import org.granite.messaging.jmf.codec.std.IntegerCodec;
035    import org.granite.messaging.jmf.codec.std.LongCodec;
036    
037    /**
038     * @author Franck WOLFF
039     */
040    public class ArrayCodecImpl extends AbstractIntegerStringCodec<Object> implements ArrayCodec {
041            
042            public int getObjectType() {
043                    return JMF_ARRAY;
044            }
045    
046            public boolean canEncode(Object v) {
047                    return v.getClass().isArray();
048            }
049    
050            public void encode(OutputContext ctx, Object v) throws IOException {
051                    int dimensions = getArrayDimensions(v);
052                    Class<?> componentType = getComponentType(v);
053                    
054                    int jmfComponentType = ctx.getSharedContext().getCodecRegistry().jmfTypeOfPrimitiveClass(componentType);
055                    if (jmfComponentType != -1)
056                            writePrimitiveArray(ctx, v, jmfComponentType, dimensions, true);
057                    else
058                            writeObjectArray(ctx, v, dimensions, true);
059            }
060            
061            public Object decode(InputContext ctx, int parameterizedJmfType) throws IOException, ClassNotFoundException {
062                    final CodecRegistry codecRegistry = ctx.getSharedContext().getCodecRegistry();
063                    
064                    int jmfType = codecRegistry.extractJmfType(parameterizedJmfType);
065                    
066                    if (jmfType != JMF_ARRAY)
067                            throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
068    
069                    Object v = null;
070                    
071                    int indexOrLength = readIntData(ctx, (parameterizedJmfType >> 4) & 0x03, false);
072                    if ((parameterizedJmfType & 0x80) != 0)
073                            v = ctx.getSharedObject(indexOrLength);
074                    else {
075                            int dimensions = ((parameterizedJmfType & 0x40) == 0 ? 0 : ctx.safeRead());
076                            int parameterizedJmfComponentType = ctx.safeRead();
077                            int jmfComponentType = codecRegistry.extractJmfType(parameterizedJmfComponentType);
078                            
079                            Class<?> componentType = codecRegistry.primitiveClassOfJmfType(jmfComponentType);
080                            
081                            if (componentType != null)
082                                    v = readPrimitiveArray(ctx, componentType, jmfComponentType, indexOrLength, dimensions);
083                            else
084                                    v = readObjectArray(ctx, parameterizedJmfComponentType, indexOrLength, dimensions);
085                    }
086                    
087                    return v;
088            }
089            
090            public void dump(DumpContext ctx, int parameterizedJmfType) throws IOException {
091                    final CodecRegistry codecRegistry = ctx.getSharedContext().getCodecRegistry();
092    
093                    int jmfType = codecRegistry.extractJmfType(parameterizedJmfType);
094                    
095                    if (jmfType != JMF_ARRAY)
096                            throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
097                    
098                    int indexOrLength = readIntData(ctx, (parameterizedJmfType >> 4) & 0x03, false);
099                    if ((parameterizedJmfType & 0x80) != 0)
100                            ctx.indentPrintLn("<" + ctx.getSharedObject(indexOrLength) + "@" + indexOrLength + ">");
101                    else {
102                            int dimensions = ((parameterizedJmfType & 0x40) == 0 ? 0 : ctx.safeRead());
103                            int parameterizedJmfComponentType = ctx.safeRead();
104                            int jmfComponentType = codecRegistry.extractJmfType(parameterizedJmfComponentType);
105                            
106                            Class<?> componentType = codecRegistry.primitiveClassOfJmfType(jmfComponentType);
107                            
108                            if (componentType != null)
109                                    dumpPrimitiveArray(ctx, componentType, jmfComponentType, indexOrLength, dimensions);
110                            else
111                                    dumpObjectArray(ctx, parameterizedJmfComponentType, indexOrLength, dimensions);
112                    }
113            }
114    
115            protected void writeObjectArray(OutputContext ctx, Object v, int dimensions, boolean writeDimensions) throws IOException {
116                    final OutputStream os = ctx.getOutputStream();
117                    
118                    if (v == null)
119                            os.write(JMF_NULL);
120                    else {
121                            int indexOfStoredObject = ctx.indexOfStoredObjects(v);
122                            if (indexOfStoredObject >= 0) {
123                                    IntegerComponents ics = intComponents(indexOfStoredObject);
124                                    ctx.getOutputStream().write(0x80 | (ics.length << 4) | JMF_ARRAY);
125                                    writeIntData(ctx, ics);
126                            }
127                            else {
128                                    ctx.addToStoredObjects(v);
129                                    
130                                    if (dimensions == 0)
131                                            writeObjectArray(ctx, v);
132                                    else {
133                                            int length = Array.getLength(v);
134                                            
135                                            IntegerComponents ics = intComponents(length);
136                                            if (writeDimensions) {
137                                                    os.write(0x40 | (ics.length << 4) | JMF_ARRAY);
138                                                    writeIntData(ctx, ics);
139                                                    os.write(dimensions);
140                                            }
141                                            else {
142                                                    os.write((ics.length << 4) | JMF_ARRAY);
143                                                    writeIntData(ctx, ics);
144                                            }
145                                            
146                                            Class<?> componentType = getComponentType(v);
147                                            String className = ctx.getAlias(componentType.getName());
148                                            writeString(ctx, className, JMF_STRING_TYPE_HANDLER);
149                                            
150                                            int subDimensions = dimensions - 1;
151                                            for (int index = 0; index < length; index++)
152                                                    writeObjectArray(ctx, Array.get(v, index), subDimensions, false);
153                                    }
154                            }
155                    }
156            }
157            
158            protected void writeObjectArray(OutputContext ctx, Object v) throws IOException {
159                    final OutputStream os = ctx.getOutputStream();
160    
161                    int length = Array.getLength(v);
162                    Class<?> componentType = v.getClass().getComponentType();
163                    String className = ctx.getAlias(componentType.getName());
164                    
165                    IntegerComponents ics = intComponents(length);
166                    os.write((ics.length << 4) | JMF_ARRAY);
167                    writeIntData(ctx, ics);
168    
169                    writeString(ctx, className, JMF_STRING_TYPE_HANDLER);
170                    for (int index = 0; index < length; index++)
171                            ctx.writeObject(Array.get(v, index));
172            }
173            
174            protected void writePrimitiveArray(OutputContext ctx, Object v, int jmfComponentType, int dimensions, boolean writeDimensionsAndType) throws IOException {
175                    final OutputStream os = ctx.getOutputStream();
176    
177                    if (v == null)
178                            os.write(JMF_NULL);
179                    else {
180                            int indexOfStoredObject = ctx.indexOfStoredObjects(v);
181                            if (indexOfStoredObject >= 0) {
182                                    IntegerComponents ics = intComponents(indexOfStoredObject);
183                                    ctx.getOutputStream().write(0x80 | (ics.length << 4) | JMF_ARRAY);
184                                    writeIntData(ctx, ics);
185                            }
186                            else {
187                                    ctx.addToStoredObjects(v);
188                                    if (dimensions == 0)
189                                            writePrimitiveArray(ctx, v, jmfComponentType, writeDimensionsAndType);
190                                    else {
191                                            int length = Array.getLength(v);
192                                            
193                                            IntegerComponents ics = intComponents(length);
194                                            if (writeDimensionsAndType) {
195                                                    os.write(0x40 | (ics.length << 4) | JMF_ARRAY);
196                                                    writeIntData(ctx, ics);
197                                                    os.write(dimensions);
198                                                    os.write(jmfComponentType);
199                                            }
200                                            else {
201                                                    os.write((ics.length << 4) | JMF_ARRAY);
202                                                    writeIntData(ctx, ics);
203                                            }
204                                            
205                                            int subDimensions = dimensions - 1;
206                                            for (int index = 0; index < length; index++)
207                                                    writePrimitiveArray(ctx, Array.get(v, index), jmfComponentType, subDimensions, false);
208                                    }
209                            }
210                    }
211            }
212            
213            protected void writePrimitiveArray(OutputContext ctx, Object v, int jmfComponentType, boolean writeType) throws IOException {
214                    final OutputStream os = ctx.getOutputStream();
215    
216                    final int length = Array.getLength(v);
217                    
218                    IntegerComponents ics = intComponents(length);
219                    os.write((ics.length << 4) | JMF_ARRAY);
220                    writeIntData(ctx, ics);
221                    
222                    if (writeType)
223                            os.write(jmfComponentType);
224                    
225                    if (length == 0)
226                            return;
227                    
228                    switch (jmfComponentType) {
229                            case JMF_BOOLEAN: {
230                                    byte[] bytes = new byte[lengthOfBooleanArray(length)];
231                                    int i = 0, j = 0;
232                                    for (boolean b : (boolean[])v) {
233                                            if (b)
234                                                    bytes[i] |= 0x80 >> j;
235                                            j++;
236                                            if (j >= 8) {
237                                                    j = 0;
238                                                    i++;
239                                            }
240                                    }
241                                    os.write(bytes);
242                                    break;
243                            }
244                            
245                            case JMF_CHARACTER: {
246                                    char[] a = (char[])v;
247                                    for (char c : a) {
248                                            os.write(c >> 8);
249                                            os.write(c);
250                                    }
251                                    break;
252                            }
253                            
254                            case JMF_BYTE: {
255                                    os.write((byte[])v);
256                                    break;
257                            }
258                            
259                            case JMF_SHORT: {
260                                    short[] a = (short[])v;
261                                    for (short s : a) {
262                                            os.write(s >> 8);
263                                            os.write(s);
264                                    }
265                                    break;
266                            }
267                            
268                            case JMF_INTEGER: {
269                                    IntegerCodec integerCodec = ctx.getSharedContext().getCodecRegistry().getIntegerCodec();
270                                    int[] a = (int[])v;
271                                    for (int i : a)
272                                            integerCodec.writeVariableInt(ctx, i);
273                                    break;
274                            }
275                            
276                            case JMF_LONG: {
277                                    LongCodec longCodec = ctx.getSharedContext().getCodecRegistry().getLongCodec();
278                                    long[] a = (long[])v;
279                                    for (long l : a)
280                                            longCodec.writeVariableLong(ctx, l);
281                                    break;
282                            }
283                            
284                            case JMF_FLOAT: {
285                                    float[] a = (float[])v;
286                                    for (float f : a) {
287                                            int bits = Float.floatToIntBits(f);
288                                            os.write(bits);
289                                            os.write(bits >> 8);
290                                            os.write(bits >> 16);
291                                            os.write(bits >> 24);
292                                            
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                                                    a[i] = FloatCodecImpl.readFloatData(ctx, jmfComponentType);
568                                            v = a;
569                                            break;
570                                    }
571                                    
572                                    case JMF_DOUBLE: {
573                                            double[] a = new double[length];
574                                            for (int i = 0; i < length; i++)
575                                                    a[i] = DoubleCodecImpl.readDoubleData(ctx, jmfComponentType);
576                                            v = a;
577                                            break;
578                                    }
579                                    
580                                    default:
581                                            throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
582                            }
583                    }
584                    
585                    ctx.addSharedObject(v);
586                    
587                    return v;
588            }
589            
590            protected void dumpPrimitiveArray(DumpContext ctx, Class<?> componentType, int jmfComponentType, int length) throws IOException {
591    
592                    String v = newDumpPrimitiveArray(jmfComponentType, length, 0);
593                    int indexOfStoredObject = ctx.addSharedObject(v);
594                    ctx.indentPrint(v + "@" + indexOfStoredObject + ": {");
595                    
596                    switch (jmfComponentType) {
597                            case JMF_BOOLEAN: {
598                                    int nb = lengthOfBooleanArray(length);
599                                    for (int i = 0; i < nb; i++) {
600                                            int b = ctx.safeRead();
601                                            for (int j = 0; j < 8; j++) {
602                                                    int index = (i * 8) + j;
603                                                    if (index >= length)
604                                                            break;
605                                                    if (index > 0)
606                                                            ctx.print(", ");
607                                                    ctx.print(String.valueOf(((b & (0x80 >> j)) != 0)));
608                                            }
609                                    }
610                                    break;
611                            }
612                            
613                            case JMF_CHARACTER: {
614                                    for (int i = 0; i < length; i++) {
615                                            if (i > 0)
616                                                    ctx.print(", ");
617                                            ctx.print(String.valueOf((char)((ctx.safeRead() << 8) | ctx.safeRead())));
618                                    }
619                                    break;
620                            }
621                            
622                            case JMF_BYTE: {
623                                    for (int i = 0; i < length; i++) {
624                                            if (i > 0)
625                                                    ctx.print(", ");
626                                            ctx.print(String.valueOf((byte)ctx.safeRead()));
627                                    }
628                                    break;
629                            }
630                            
631                            case JMF_SHORT: {
632                                    for (int i = 0; i < length; i++) {
633                                            if (i > 0)
634                                                    ctx.print(", ");
635                                            ctx.print(String.valueOf((short)(ctx.safeRead() << 8) | ctx.safeRead()));
636                                    }
637                                    break;
638                            }
639                            
640                            case JMF_INTEGER: {
641                                    IntegerCodec integerCodec = ctx.getSharedContext().getCodecRegistry().getIntegerCodec();
642                                    for (int i = 0; i < length; i++) {
643                                            if (i > 0)
644                                                    ctx.print(", ");
645                                            ctx.print(String.valueOf(integerCodec.readVariableInt(ctx)));
646                                    }
647                                    break;
648                            }
649                            
650                            case JMF_LONG: {
651                                    LongCodec longCodec = ctx.getSharedContext().getCodecRegistry().getLongCodec();
652                                    for (int i = 0; i < length; i++) {
653                                            if (i > 0)
654                                                    ctx.print(", ");
655                                            ctx.print(String.valueOf(longCodec.readVariableLong(ctx)));
656                                    }
657                                    break;
658                            }
659                            
660                            case JMF_FLOAT: {
661                                    for (int i = 0; i < length; i++) {
662                                            if (i > 0)
663                                                    ctx.print(", ");
664                                            ctx.print(String.valueOf(FloatCodecImpl.readFloatData(ctx, jmfComponentType)));
665                                    }
666                                    break;
667                            }
668                            
669                            case JMF_DOUBLE: {
670                                    for (int i = 0; i < length; i++) {
671                                            if (i > 0)
672                                                    ctx.print(", ");
673                                            ctx.print(String.valueOf(DoubleCodecImpl.readDoubleData(ctx, jmfComponentType)));
674                                    }
675                                    break;
676                            }
677                            
678                            default:
679                                    throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
680                    }
681    
682                    ctx.noIndentPrintLn("}");
683            }
684            
685            protected String newDumpPrimitiveArray(int jmfComponentType, int length, int dimensions) throws IOException {
686                    StringBuilder sb = new StringBuilder();
687                    
688                    switch (jmfComponentType) {
689                            case JMF_BOOLEAN: sb.append("boolean"); break;
690                            case JMF_CHARACTER: sb.append("char"); break;
691                            case JMF_BYTE: sb.append("byte"); break;
692                            case JMF_SHORT: sb.append("short"); break;
693                            case JMF_INTEGER: sb.append("int"); break;
694                            case JMF_LONG: sb.append("long"); break;
695                            case JMF_FLOAT: sb.append("float"); break;
696                            case JMF_DOUBLE: sb.append("double"); break;
697                            default: throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
698                    }
699                    
700                    sb.append('[').append(length).append(']');
701                    
702                    for (int i = 0; i < dimensions; i++)
703                            sb.append("[]");
704                    
705                    return sb.toString();
706            }
707            
708            protected Object newArray(Class<?> type, int length, int dimensions) {
709                    int[] ld = new int[dimensions + 1];
710                    ld[0] = length;
711                    return Array.newInstance(type, ld);
712            }
713            
714            protected int lengthOfBooleanArray(int nb) {
715                    return (nb / 8) + (nb % 8 != 0 ? 1 : 0);
716            }
717    }