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 */
022package org.granite.messaging.jmf.codec.std.impl;
023
024import java.io.IOException;
025import java.io.OutputStream;
026import java.lang.reflect.Array;
027
028import org.granite.messaging.jmf.CodecRegistry;
029import org.granite.messaging.jmf.DumpContext;
030import org.granite.messaging.jmf.InputContext;
031import org.granite.messaging.jmf.JMFEncodingException;
032import org.granite.messaging.jmf.OutputContext;
033import org.granite.messaging.jmf.codec.StandardCodec;
034import org.granite.messaging.jmf.codec.std.ArrayCodec;
035import org.granite.messaging.jmf.codec.std.IntegerCodec;
036import org.granite.messaging.jmf.codec.std.LongCodec;
037
038/**
039 * @author Franck WOLFF
040 */
041public 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                                }
295                                break;
296                        }
297                        
298                        case JMF_DOUBLE: {
299                                double[] a = (double[])v;
300                                for (double d : a) {
301                                        long bits = Double.doubleToLongBits(d);
302                                        os.write((int)bits);
303                                        os.write((int)(bits >> 8));
304                                        os.write((int)(bits >> 16));
305                                        os.write((int)(bits >> 24));
306                                        os.write((int)(bits >> 32));
307                                        os.write((int)(bits >> 40));
308                                        os.write((int)(bits >> 48));
309                                        os.write((int)(bits >> 56));
310                                }
311                                break;
312                        }
313                        
314                        default:
315                                throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
316                }
317        }
318        
319        protected int getArrayDimensions(Object v) {
320                return v.getClass().getName().lastIndexOf('[');
321        }
322        
323        protected Class<?> getComponentType(Object v) {
324                Class<?> componentType = v.getClass().getComponentType();
325                while (componentType.isArray())
326                        componentType = componentType.getComponentType();
327                return componentType;
328        }
329        
330        protected Object readObjectArray(InputContext ctx, int parameterizedJmfComponentType, int length, int dimensions) throws IOException, ClassNotFoundException {
331                Object v =  null;
332                
333                String componentTypeName = readString(ctx, parameterizedJmfComponentType, JMF_STRING_TYPE_HANDLER);
334                componentTypeName = ctx.getAlias(componentTypeName);
335                Class<?> componentType = ctx.getSharedContext().getReflection().loadClass(componentTypeName);
336                
337                if (dimensions == 0)
338                        v = readObjectArray(ctx, componentType, length);
339                else {
340                        v = newArray(componentType, length, dimensions);
341                        ctx.addSharedObject(v);
342                        
343                        int subDimensions = dimensions - 1;
344                        for (int index = 0; index < length; index++) {
345                                int subParameterizedJmfType = ctx.safeRead();
346                                int subJmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(subParameterizedJmfType);
347
348                                if (subJmfType == JMF_NULL)
349                                        Array.set(v, index, null);
350                                else if (subJmfType == JMF_ARRAY) {
351                                        int subLengthOrIndex = readIntData(ctx, (subParameterizedJmfType >> 4) & 0x03, false);
352                                        if ((subParameterizedJmfType & 0x80) != 0)
353                                                Array.set(v, index, ctx.getSharedObject(subLengthOrIndex));
354                                        else {
355                                                int subParameterizedJmfComponentType = ctx.safeRead();
356                                                Array.set(v, index, readObjectArray(ctx, subParameterizedJmfComponentType, subLengthOrIndex, subDimensions));
357                                        }
358                                }
359                                else
360                                        newBadTypeJMFEncodingException(subJmfType, subParameterizedJmfType);
361                        }
362                }
363                
364                return v;
365        }
366        
367        protected void dumpObjectArray(DumpContext ctx, int parameterizedJmfComponentType, int length, int dimensions) throws IOException {
368                String componentTypeName = readString(ctx, parameterizedJmfComponentType, JMF_STRING_TYPE_HANDLER);
369                
370                if (dimensions == 0)
371                        dumpObjectArray(ctx, componentTypeName, length);
372                else {
373                        String v = newDumpObjectArray(componentTypeName, length, dimensions);
374                        int indexOfStoredObject = ctx.addSharedObject(v);
375                        ctx.indentPrintLn(v + "@" + indexOfStoredObject + ": {");
376                        ctx.incrIndent(1);
377                        
378                        int subDimensions = dimensions - 1;
379                        for (int index = 0; index < length; index++) {
380                                int subParameterizedJmfType = ctx.safeRead();
381                                int subJmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(subParameterizedJmfType);
382
383                                if (subJmfType == JMF_NULL)
384                                        ctx.indentPrintLn("null");
385                                else if (subJmfType == JMF_ARRAY) {
386                                        int subLengthOrIndex = readIntData(ctx, (subParameterizedJmfType >> 4) & 0x03, false);
387                                        if ((subParameterizedJmfType & 0x80) != 0)
388                                                ctx.indentPrintLn("<" + ctx.getSharedObject(subLengthOrIndex) + "@" + subLengthOrIndex + ">");
389                                        else {
390                                                int subParameterizedJmfComponentType = ctx.safeRead();
391                                                dumpObjectArray(ctx, subParameterizedJmfComponentType, subLengthOrIndex, subDimensions);
392                                        }
393                                }
394                                else
395                                        newBadTypeJMFEncodingException(subJmfType, subParameterizedJmfType);
396                        }
397
398                        ctx.incrIndent(-1);
399                        ctx.indentPrintLn("}");
400                }
401        }
402        
403        protected Object readObjectArray(InputContext ctx, Class<?> componentType, int length) throws IOException, ClassNotFoundException {
404                Object v = Array.newInstance(componentType, length);
405                ctx.addSharedObject(v);
406                
407                for (int index = 0; index < length; index++)
408                        Array.set(v, index, ctx.readObject());
409                
410                return v;
411        }
412        
413        protected void dumpObjectArray(DumpContext ctx, String componentTypeName, int length) throws IOException {
414                String v = newDumpObjectArray(componentTypeName, length, 0);
415                int indexOfStoredObject = ctx.addSharedObject(v);
416                ctx.indentPrintLn(v + "@" + indexOfStoredObject + ": {");
417                ctx.incrIndent(1);
418                
419                for (int index = 0; index < length; index++) {
420                        int parameterizedJmfType = ctx.safeRead();
421                        int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType);
422                        StandardCodec<?> codec = ctx.getSharedContext().getCodecRegistry().getCodec(jmfType);
423                        
424                        if (codec == null)
425                                throw new JMFEncodingException("No codec for JMF type: " + jmfType);
426                        
427                        codec.dump(ctx, parameterizedJmfType);
428                }
429
430                ctx.incrIndent(-1);
431                ctx.indentPrintLn("}");
432        }
433        
434        protected String newDumpObjectArray(String componentTypeName, int length, int dimensions) {
435                StringBuilder sb = new StringBuilder(componentTypeName);
436                
437                sb.append('[').append(length).append(']');
438                
439                for (int i = 0; i < dimensions; i++)
440                        sb.append("[]");
441                
442                return sb.toString();
443                
444        }
445        
446        protected Object readPrimitiveArray(InputContext ctx, Class<?> componentType, int jmfComponentType, int length, int dimensions) throws IOException {
447                Object v =  null;
448                
449                if (dimensions == 0)
450                        v = readPrimitiveArray(ctx, componentType, jmfComponentType, length);
451                else {
452                        v = newArray(componentType, length, dimensions);
453                        ctx.addSharedObject(v);
454                        
455                        int subDimensions = dimensions - 1;
456                        for (int index = 0; index < length; index++) {
457                                int subArrayJmfType = ctx.safeRead();
458                                if (subArrayJmfType == JMF_NULL)
459                                        Array.set(v, index, null);
460                                else {
461                                        int subLengthOrIndex = readIntData(ctx, (subArrayJmfType >> 4) & 0x03, false);
462                                        if ((subArrayJmfType & 0x80) != 0)
463                                                Array.set(v, index, ctx.getSharedObject(subLengthOrIndex));
464                                        else
465                                                Array.set(v, index, readPrimitiveArray(ctx, componentType, jmfComponentType, subLengthOrIndex, subDimensions));
466                                }
467                        }
468                }
469                
470                return v;
471        }
472        
473        protected void dumpPrimitiveArray(DumpContext ctx, Class<?> componentType, int jmfComponentType, int length, int dimensions) throws IOException {
474                if (dimensions == 0)
475                        dumpPrimitiveArray(ctx, componentType, jmfComponentType, length);
476                else {
477                        String v = newDumpPrimitiveArray(jmfComponentType, length, dimensions);
478                        int indexOfStoredObject = ctx.addSharedObject(v);
479                        ctx.indentPrintLn(v + "@" + indexOfStoredObject + ": {");
480                        ctx.incrIndent(1);
481                        
482                        int subDimensions = dimensions - 1;
483                        for (int index = 0; index < length; index++) {
484                                int subArrayJmfType = ctx.safeRead();
485                                if (subArrayJmfType == JMF_NULL)
486                                        ctx.indentPrintLn("null");
487                                else {
488                                        int subLengthOrIndex = readIntData(ctx, (subArrayJmfType >> 4) & 0x03, false);
489                                        if ((subArrayJmfType & 0x80) != 0)
490                                                ctx.indentPrintLn("<" + ctx.getSharedObject(subLengthOrIndex) + "@" + subLengthOrIndex + ">");
491                                        else
492                                                dumpPrimitiveArray(ctx, componentType, jmfComponentType, subLengthOrIndex, subDimensions);
493                                }
494                        }
495                        
496                        ctx.incrIndent(-1);
497                        ctx.indentPrintLn("}");
498                }
499        }
500        
501        protected Object readPrimitiveArray(InputContext ctx, Class<?> componentType, int jmfComponentType, int length) throws IOException {
502                Object v = null;
503                
504                if (length == 0)
505                        v = Array.newInstance(componentType, length);
506                else {
507                        switch (jmfComponentType) {
508                                case JMF_BOOLEAN: {
509                                        boolean[] a = new boolean[length];
510                                        int nb = lengthOfBooleanArray(length);
511                                        for (int i = 0; i < nb; i++) {
512                                                int b = ctx.safeRead();
513                                                for (int j = 0; j < 8; j++) {
514                                                        int index = (i * 8) + j;
515                                                        if (index >= length)
516                                                                break;
517                                                        a[index] = ((b & (0x80 >> j)) != 0);
518                                                }
519                                        }
520                                        v = a;
521                                        break;
522                                }
523                                
524                                case JMF_CHARACTER: {
525                                        char[] a = new char[length];
526                                        for (int i = 0; i < length; i++)
527                                                a[i] = (char)((ctx.safeRead() << 8) | ctx.safeRead());
528                                        v = a;
529                                        break;
530                                }
531                                
532                                case JMF_BYTE: {
533                                        byte[] a = new byte[length];
534                                        ctx.safeReadFully(a);
535                                        v = a;
536                                        break;
537                                }
538                                
539                                case JMF_SHORT: {
540                                        short[] a = new short[length];
541                                        for (int i = 0; i < length; i++)
542                                                a[i] = (short)((ctx.safeRead() << 8) | ctx.safeRead());
543                                        v = a;
544                                        break;
545                                }
546                                
547                                case JMF_INTEGER: {
548                                        IntegerCodec integerCodec = ctx.getSharedContext().getCodecRegistry().getIntegerCodec();
549                                        int[] a = new int[length];
550                                        for (int i = 0; i < length; i++)
551                                                a[i] = integerCodec.readVariableInt(ctx);
552                                        v = a;
553                                        break;
554                                }
555                                
556                                case JMF_LONG: {
557                                        LongCodec longCodec = ctx.getSharedContext().getCodecRegistry().getLongCodec();
558                                        long[] a = new long[length];
559                                        for (int i = 0; i < length; i++)
560                                                a[i] = longCodec.readVariableLong(ctx);
561                                        v = a;
562                                        break;
563                                }
564                                
565                                case JMF_FLOAT: {
566                                        float[] a = new float[length];
567                                        for (int i = 0; i < length; i++)
568                                                a[i] = FloatCodecImpl.readFloatData(ctx, jmfComponentType);
569                                        v = a;
570                                        break;
571                                }
572                                
573                                case JMF_DOUBLE: {
574                                        double[] a = new double[length];
575                                        for (int i = 0; i < length; i++)
576                                                a[i] = DoubleCodecImpl.readDoubleData(ctx, jmfComponentType);
577                                        v = a;
578                                        break;
579                                }
580                                
581                                default:
582                                        throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
583                        }
584                }
585                
586                ctx.addSharedObject(v);
587                
588                return v;
589        }
590        
591        protected void dumpPrimitiveArray(DumpContext ctx, Class<?> componentType, int jmfComponentType, int length) throws IOException {
592
593                String v = newDumpPrimitiveArray(jmfComponentType, length, 0);
594                int indexOfStoredObject = ctx.addSharedObject(v);
595                ctx.indentPrint(v + "@" + indexOfStoredObject + ": {");
596                
597                switch (jmfComponentType) {
598                        case JMF_BOOLEAN: {
599                                int nb = lengthOfBooleanArray(length);
600                                for (int i = 0; i < nb; i++) {
601                                        int b = ctx.safeRead();
602                                        for (int j = 0; j < 8; j++) {
603                                                int index = (i * 8) + j;
604                                                if (index >= length)
605                                                        break;
606                                                if (index > 0)
607                                                        ctx.print(", ");
608                                                ctx.print(String.valueOf(((b & (0x80 >> j)) != 0)));
609                                        }
610                                }
611                                break;
612                        }
613                        
614                        case JMF_CHARACTER: {
615                                for (int i = 0; i < length; i++) {
616                                        if (i > 0)
617                                                ctx.print(", ");
618                                        ctx.print(String.valueOf((char)((ctx.safeRead() << 8) | ctx.safeRead())));
619                                }
620                                break;
621                        }
622                        
623                        case JMF_BYTE: {
624                                for (int i = 0; i < length; i++) {
625                                        if (i > 0)
626                                                ctx.print(", ");
627                                        ctx.print(String.valueOf((byte)ctx.safeRead()));
628                                }
629                                break;
630                        }
631                        
632                        case JMF_SHORT: {
633                                for (int i = 0; i < length; i++) {
634                                        if (i > 0)
635                                                ctx.print(", ");
636                                        ctx.print(String.valueOf((short)(ctx.safeRead() << 8) | ctx.safeRead()));
637                                }
638                                break;
639                        }
640                        
641                        case JMF_INTEGER: {
642                                IntegerCodec integerCodec = ctx.getSharedContext().getCodecRegistry().getIntegerCodec();
643                                for (int i = 0; i < length; i++) {
644                                        if (i > 0)
645                                                ctx.print(", ");
646                                        ctx.print(String.valueOf(integerCodec.readVariableInt(ctx)));
647                                }
648                                break;
649                        }
650                        
651                        case JMF_LONG: {
652                                LongCodec longCodec = ctx.getSharedContext().getCodecRegistry().getLongCodec();
653                                for (int i = 0; i < length; i++) {
654                                        if (i > 0)
655                                                ctx.print(", ");
656                                        ctx.print(String.valueOf(longCodec.readVariableLong(ctx)));
657                                }
658                                break;
659                        }
660                        
661                        case JMF_FLOAT: {
662                                for (int i = 0; i < length; i++) {
663                                        if (i > 0)
664                                                ctx.print(", ");
665                                        ctx.print(String.valueOf(FloatCodecImpl.readFloatData(ctx, jmfComponentType)));
666                                }
667                                break;
668                        }
669                        
670                        case JMF_DOUBLE: {
671                                for (int i = 0; i < length; i++) {
672                                        if (i > 0)
673                                                ctx.print(", ");
674                                        ctx.print(String.valueOf(DoubleCodecImpl.readDoubleData(ctx, jmfComponentType)));
675                                }
676                                break;
677                        }
678                        
679                        default:
680                                throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
681                }
682
683                ctx.noIndentPrintLn("}");
684        }
685        
686        protected String newDumpPrimitiveArray(int jmfComponentType, int length, int dimensions) throws IOException {
687                StringBuilder sb = new StringBuilder();
688                
689                switch (jmfComponentType) {
690                        case JMF_BOOLEAN: sb.append("boolean"); break;
691                        case JMF_CHARACTER: sb.append("char"); break;
692                        case JMF_BYTE: sb.append("byte"); break;
693                        case JMF_SHORT: sb.append("short"); break;
694                        case JMF_INTEGER: sb.append("int"); break;
695                        case JMF_LONG: sb.append("long"); break;
696                        case JMF_FLOAT: sb.append("float"); break;
697                        case JMF_DOUBLE: sb.append("double"); break;
698                        default: throw new JMFEncodingException("Unsupported primitive type: " + jmfComponentType);
699                }
700                
701                sb.append('[').append(length).append(']');
702                
703                for (int i = 0; i < dimensions; i++)
704                        sb.append("[]");
705                
706                return sb.toString();
707        }
708        
709        protected Object newArray(Class<?> type, int length, int dimensions) {
710                int[] ld = new int[dimensions + 1];
711                ld[0] = length;
712                return Array.newInstance(type, ld);
713        }
714        
715        protected int lengthOfBooleanArray(int nb) {
716                return (nb / 8) + (nb % 8 != 0 ? 1 : 0);
717        }
718}