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
021package org.granite.messaging.jmf.codec.std.impl;
022
023import java.io.IOException;
024import java.io.OutputStream;
025import java.lang.reflect.Array;
026
027import org.granite.messaging.jmf.CodecRegistry;
028import org.granite.messaging.jmf.DumpContext;
029import org.granite.messaging.jmf.InputContext;
030import org.granite.messaging.jmf.JMFEncodingException;
031import org.granite.messaging.jmf.OutputContext;
032import org.granite.messaging.jmf.codec.StandardCodec;
033import org.granite.messaging.jmf.codec.std.ArrayCodec;
034import org.granite.messaging.jmf.codec.std.IntegerCodec;
035import org.granite.messaging.jmf.codec.std.LongCodec;
036
037/**
038 * @author Franck WOLFF
039 */
040public 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}