1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package com.jme3.export.binary;
34
35import com.jme3.export.OutputCapsule;
36import com.jme3.export.Savable;
37import com.jme3.util.IntMap;
38import com.jme3.util.IntMap.Entry;
39import java.io.ByteArrayOutputStream;
40import java.io.IOException;
41import java.nio.ByteBuffer;
42import java.nio.FloatBuffer;
43import java.nio.IntBuffer;
44import java.nio.ShortBuffer;
45import java.util.ArrayList;
46import java.util.Arrays;
47import java.util.BitSet;
48import java.util.Map;
49
50/**
51 * @author Joshua Slack
52 */
53final class BinaryOutputCapsule implements OutputCapsule {
54
55    public static final int NULL_OBJECT = -1;
56    public static final int DEFAULT_OBJECT = -2;
57
58    public static byte[] NULL_BYTES = new byte[] { (byte) -1 };
59    public static byte[] DEFAULT_BYTES = new byte[] { (byte) -2 };
60
61    protected ByteArrayOutputStream baos;
62    protected byte[] bytes;
63    protected BinaryExporter exporter;
64    protected BinaryClassObject cObj;
65
66    public BinaryOutputCapsule(BinaryExporter exporter, BinaryClassObject bco) {
67        this.baos = new ByteArrayOutputStream();
68        this.exporter = exporter;
69        this.cObj = bco;
70    }
71
72    public void write(byte value, String name, byte defVal) throws IOException {
73        if (value == defVal)
74            return;
75        writeAlias(name, BinaryClassField.BYTE);
76        write(value);
77    }
78
79    public void write(byte[] value, String name, byte[] defVal)
80            throws IOException {
81        if (value == defVal)
82            return;
83        writeAlias(name, BinaryClassField.BYTE_1D);
84        write(value);
85    }
86
87    public void write(byte[][] value, String name, byte[][] defVal)
88            throws IOException {
89        if (value == defVal)
90            return;
91        writeAlias(name, BinaryClassField.BYTE_2D);
92        write(value);
93    }
94
95    public void write(int value, String name, int defVal) throws IOException {
96        if (value == defVal)
97            return;
98        writeAlias(name, BinaryClassField.INT);
99        write(value);
100    }
101
102    public void write(int[] value, String name, int[] defVal)
103            throws IOException {
104        if (value == defVal)
105            return;
106        writeAlias(name, BinaryClassField.INT_1D);
107        write(value);
108    }
109
110    public void write(int[][] value, String name, int[][] defVal)
111            throws IOException {
112        if (value == defVal)
113            return;
114        writeAlias(name, BinaryClassField.INT_2D);
115        write(value);
116    }
117
118    public void write(float value, String name, float defVal)
119            throws IOException {
120        if (value == defVal)
121            return;
122        writeAlias(name, BinaryClassField.FLOAT);
123        write(value);
124    }
125
126    public void write(float[] value, String name, float[] defVal)
127            throws IOException {
128        if (value == defVal)
129            return;
130        writeAlias(name, BinaryClassField.FLOAT_1D);
131        write(value);
132    }
133
134    public void write(float[][] value, String name, float[][] defVal)
135            throws IOException {
136        if (value == defVal)
137            return;
138        writeAlias(name, BinaryClassField.FLOAT_2D);
139        write(value);
140    }
141
142    public void write(double value, String name, double defVal)
143            throws IOException {
144        if (value == defVal)
145            return;
146        writeAlias(name, BinaryClassField.DOUBLE);
147        write(value);
148    }
149
150    public void write(double[] value, String name, double[] defVal)
151            throws IOException {
152        if (value == defVal)
153            return;
154        writeAlias(name, BinaryClassField.DOUBLE_1D);
155        write(value);
156    }
157
158    public void write(double[][] value, String name, double[][] defVal)
159            throws IOException {
160        if (value == defVal)
161            return;
162        writeAlias(name, BinaryClassField.DOUBLE_2D);
163        write(value);
164    }
165
166    public void write(long value, String name, long defVal) throws IOException {
167        if (value == defVal)
168            return;
169        writeAlias(name, BinaryClassField.LONG);
170        write(value);
171    }
172
173    public void write(long[] value, String name, long[] defVal)
174            throws IOException {
175        if (value == defVal)
176            return;
177        writeAlias(name, BinaryClassField.LONG_1D);
178        write(value);
179    }
180
181    public void write(long[][] value, String name, long[][] defVal)
182            throws IOException {
183        if (value == defVal)
184            return;
185        writeAlias(name, BinaryClassField.LONG_2D);
186        write(value);
187    }
188
189    public void write(short value, String name, short defVal)
190            throws IOException {
191        if (value == defVal)
192            return;
193        writeAlias(name, BinaryClassField.SHORT);
194        write(value);
195    }
196
197    public void write(short[] value, String name, short[] defVal)
198            throws IOException {
199        if (value == defVal)
200            return;
201        writeAlias(name, BinaryClassField.SHORT_1D);
202        write(value);
203    }
204
205    public void write(short[][] value, String name, short[][] defVal)
206            throws IOException {
207        if (value == defVal)
208            return;
209        writeAlias(name, BinaryClassField.SHORT_2D);
210        write(value);
211    }
212
213    public void write(boolean value, String name, boolean defVal)
214            throws IOException {
215        if (value == defVal)
216            return;
217        writeAlias(name, BinaryClassField.BOOLEAN);
218        write(value);
219    }
220
221    public void write(boolean[] value, String name, boolean[] defVal)
222            throws IOException {
223        if (value == defVal)
224            return;
225        writeAlias(name, BinaryClassField.BOOLEAN_1D);
226        write(value);
227    }
228
229    public void write(boolean[][] value, String name, boolean[][] defVal)
230            throws IOException {
231        if (value == defVal)
232            return;
233        writeAlias(name, BinaryClassField.BOOLEAN_2D);
234        write(value);
235    }
236
237    public void write(String value, String name, String defVal)
238            throws IOException {
239        if (value == null ? defVal == null : value.equals(defVal))
240            return;
241        writeAlias(name, BinaryClassField.STRING);
242        write(value);
243    }
244
245    public void write(String[] value, String name, String[] defVal)
246            throws IOException {
247        if (value == defVal)
248            return;
249        writeAlias(name, BinaryClassField.STRING_1D);
250        write(value);
251    }
252
253    public void write(String[][] value, String name, String[][] defVal)
254            throws IOException {
255        if (value == defVal)
256            return;
257        writeAlias(name, BinaryClassField.STRING_2D);
258        write(value);
259    }
260
261    public void write(BitSet value, String name, BitSet defVal)
262            throws IOException {
263        if (value == defVal)
264            return;
265        writeAlias(name, BinaryClassField.BITSET);
266        write(value);
267    }
268
269    public void write(Savable object, String name, Savable defVal)
270            throws IOException {
271        if (object == defVal)
272            return;
273        writeAlias(name, BinaryClassField.SAVABLE);
274        write(object);
275    }
276
277    public void write(Savable[] objects, String name, Savable[] defVal)
278            throws IOException {
279        if (objects == defVal)
280            return;
281        writeAlias(name, BinaryClassField.SAVABLE_1D);
282        write(objects);
283    }
284
285    public void write(Savable[][] objects, String name, Savable[][] defVal)
286            throws IOException {
287        if (objects == defVal)
288            return;
289        writeAlias(name, BinaryClassField.SAVABLE_2D);
290        write(objects);
291    }
292
293    public void write(FloatBuffer value, String name, FloatBuffer defVal)
294            throws IOException {
295        if (value == defVal)
296            return;
297        writeAlias(name, BinaryClassField.FLOATBUFFER);
298        write(value);
299    }
300
301    public void write(IntBuffer value, String name, IntBuffer defVal)
302            throws IOException {
303        if (value == defVal)
304            return;
305        writeAlias(name, BinaryClassField.INTBUFFER);
306        write(value);
307    }
308
309    public void write(ByteBuffer value, String name, ByteBuffer defVal)
310            throws IOException {
311        if (value == defVal)
312            return;
313        writeAlias(name, BinaryClassField.BYTEBUFFER);
314        write(value);
315    }
316
317    public void write(ShortBuffer value, String name, ShortBuffer defVal)
318            throws IOException {
319        if (value == defVal)
320            return;
321        writeAlias(name, BinaryClassField.SHORTBUFFER);
322        write(value);
323    }
324
325    public void writeFloatBufferArrayList(ArrayList<FloatBuffer> array,
326            String name, ArrayList<FloatBuffer> defVal) throws IOException {
327        if (array == defVal)
328            return;
329        writeAlias(name, BinaryClassField.FLOATBUFFER_ARRAYLIST);
330        writeFloatBufferArrayList(array);
331    }
332
333    public void writeByteBufferArrayList(ArrayList<ByteBuffer> array,
334            String name, ArrayList<ByteBuffer> defVal) throws IOException {
335        if (array == defVal)
336            return;
337        writeAlias(name, BinaryClassField.BYTEBUFFER_ARRAYLIST);
338        writeByteBufferArrayList(array);
339    }
340
341    public void writeSavableArrayList(ArrayList array, String name,
342            ArrayList defVal) throws IOException {
343        if (array == defVal)
344            return;
345        writeAlias(name, BinaryClassField.SAVABLE_ARRAYLIST);
346        writeSavableArrayList(array);
347    }
348
349    public void writeSavableArrayListArray(ArrayList[] array, String name,
350            ArrayList[] defVal) throws IOException {
351        if (array == defVal)
352            return;
353        writeAlias(name, BinaryClassField.SAVABLE_ARRAYLIST_1D);
354        writeSavableArrayListArray(array);
355    }
356
357    public void writeSavableArrayListArray2D(ArrayList[][] array, String name,
358            ArrayList[][] defVal) throws IOException {
359        if (array == defVal)
360            return;
361        writeAlias(name, BinaryClassField.SAVABLE_ARRAYLIST_2D);
362        writeSavableArrayListArray2D(array);
363    }
364
365    public void writeSavableMap(Map<? extends Savable, ? extends Savable> map,
366            String name, Map<? extends Savable, ? extends Savable> defVal)
367            throws IOException {
368        if (map == defVal)
369            return;
370        writeAlias(name, BinaryClassField.SAVABLE_MAP);
371        writeSavableMap(map);
372    }
373
374    public void writeStringSavableMap(Map<String, ? extends Savable> map,
375            String name, Map<String, ? extends Savable> defVal)
376            throws IOException {
377        if (map == defVal)
378            return;
379        writeAlias(name, BinaryClassField.STRING_SAVABLE_MAP);
380        writeStringSavableMap(map);
381    }
382
383    public void writeIntSavableMap(IntMap<? extends Savable> map,
384            String name, IntMap<? extends Savable> defVal)
385            throws IOException {
386        if (map == defVal)
387            return;
388        writeAlias(name, BinaryClassField.INT_SAVABLE_MAP);
389        writeIntSavableMap(map);
390    }
391
392    protected void writeAlias(String name, byte fieldType) throws IOException {
393        if (cObj.nameFields.get(name) == null)
394            generateAlias(name, fieldType);
395
396        byte alias = cObj.nameFields.get(name).alias;
397        write(alias);
398    }
399
400    // XXX: The generation of aliases is limited to 256 possible values.
401    // If we run into classes with more than 256 fields, we need to expand this.
402    // But I mean, come on...
403    protected void generateAlias(String name, byte type) {
404        byte alias = (byte) cObj.nameFields.size();
405        cObj.nameFields.put(name, new BinaryClassField(name, alias, type));
406    }
407
408    @Override
409    public boolean equals(Object arg0) {
410        if (!(arg0 instanceof BinaryOutputCapsule))
411            return false;
412
413        byte[] other = ((BinaryOutputCapsule) arg0).bytes;
414        if (bytes.length != other.length)
415            return false;
416        return Arrays.equals(bytes, other);
417    }
418
419    @Override
420    public int hashCode() {
421        int hash = 7;
422        hash = 23 * hash + Arrays.hashCode(this.bytes);
423        return hash;
424    }
425
426    public void finish() {
427        // renamed to finish as 'finalize' in java.lang.Object should not be
428        // overridden like this
429        // - finalize should not be called directly but is called by garbage
430        // collection!!!
431        bytes = baos.toByteArray();
432        baos = null;
433    }
434
435    // byte primitive
436
437    protected void write(byte value) throws IOException {
438        baos.write(value);
439    }
440
441    protected void writeForBuffer(byte value) throws IOException {
442        baos.write(value);
443    }
444
445    protected void write(byte[] value) throws IOException {
446        if (value == null) {
447            write(NULL_OBJECT);
448            return;
449        }
450        write(value.length);
451        baos.write(value);
452    }
453
454    protected void write(byte[][] value) throws IOException {
455        if (value == null) {
456            write(NULL_OBJECT);
457            return;
458        }
459        write(value.length);
460        for (int x = 0; x < value.length; x++)
461            write(value[x]);
462    }
463
464    // int primitive
465
466    protected void write(int value) throws IOException {
467        baos.write(deflate(ByteUtils.convertToBytes(value)));
468    }
469
470    protected void writeForBuffer(int value) throws IOException {
471        byte[] byteArray = new byte[4];
472        byteArray[0] = (byte) value;
473        byteArray[1] = (byte) (value >> 8);
474        byteArray[2] = (byte) (value >> 16);
475        byteArray[3] = (byte) (value >> 24);
476        baos.write(byteArray);
477    }
478
479    protected void write(int[] value) throws IOException {
480        if (value == null) {
481            write(NULL_OBJECT);
482            return;
483        }
484        write(value.length);
485        for (int x = 0; x < value.length; x++)
486            write(value[x]);
487    }
488
489    protected void write(int[][] value) throws IOException {
490        if (value == null) {
491            write(NULL_OBJECT);
492            return;
493        }
494        write(value.length);
495        for (int x = 0; x < value.length; x++)
496            write(value[x]);
497    }
498
499    // float primitive
500
501    protected void write(float value) throws IOException {
502        baos.write(ByteUtils.convertToBytes(value));
503    }
504
505    protected void writeForBuffer(float value) throws IOException {
506        int integer = Float.floatToIntBits(value);
507        writeForBuffer(integer);
508    }
509
510    protected void write(float[] value) throws IOException {
511        if (value == null) {
512            write(NULL_OBJECT);
513            return;
514        }
515        write(value.length);
516        for (int x = 0; x < value.length; x++)
517            write(value[x]);
518    }
519
520    protected void write(float[][] value) throws IOException {
521        if (value == null) {
522            write(NULL_OBJECT);
523            return;
524        }
525        write(value.length);
526        for (int x = 0; x < value.length; x++)
527            write(value[x]);
528    }
529
530    // double primitive
531
532    protected void write(double value) throws IOException {
533        baos.write(ByteUtils.convertToBytes(value));
534    }
535
536    protected void write(double[] value) throws IOException {
537        if (value == null) {
538            write(NULL_OBJECT);
539            return;
540        }
541        write(value.length);
542        for (int x = 0; x < value.length; x++)
543            write(value[x]);
544    }
545
546    protected void write(double[][] value) throws IOException {
547        if (value == null) {
548            write(NULL_OBJECT);
549            return;
550        }
551        write(value.length);
552        for (int x = 0; x < value.length; x++)
553            write(value[x]);
554    }
555
556    // long primitive
557
558    protected void write(long value) throws IOException {
559        baos.write(deflate(ByteUtils.convertToBytes(value)));
560    }
561
562    protected void write(long[] value) throws IOException {
563        if (value == null) {
564            write(NULL_OBJECT);
565            return;
566        }
567        write(value.length);
568        for (int x = 0; x < value.length; x++)
569            write(value[x]);
570    }
571
572    protected void write(long[][] value) throws IOException {
573        if (value == null) {
574            write(NULL_OBJECT);
575            return;
576        }
577        write(value.length);
578        for (int x = 0; x < value.length; x++)
579            write(value[x]);
580    }
581
582    // short primitive
583
584    protected void write(short value) throws IOException {
585        baos.write(ByteUtils.convertToBytes(value));
586    }
587
588    protected void writeForBuffer(short value) throws IOException {
589        byte[] byteArray = new byte[2];
590        byteArray[0] = (byte) value;
591        byteArray[1] = (byte) (value >> 8);
592        baos.write(byteArray);
593    }
594
595    protected void write(short[] value) throws IOException {
596        if (value == null) {
597            write(NULL_OBJECT);
598            return;
599        }
600        write(value.length);
601        for (int x = 0; x < value.length; x++)
602            write(value[x]);
603    }
604
605    protected void write(short[][] value) throws IOException {
606        if (value == null) {
607            write(NULL_OBJECT);
608            return;
609        }
610        write(value.length);
611        for (int x = 0; x < value.length; x++)
612            write(value[x]);
613    }
614
615    // boolean primitive
616
617    protected void write(boolean value) throws IOException {
618        baos.write(ByteUtils.convertToBytes(value));
619    }
620
621    protected void write(boolean[] value) throws IOException {
622        if (value == null) {
623            write(NULL_OBJECT);
624            return;
625        }
626        write(value.length);
627        for (int x = 0; x < value.length; x++)
628            write(value[x]);
629    }
630
631    protected void write(boolean[][] value) throws IOException {
632        if (value == null) {
633            write(NULL_OBJECT);
634            return;
635        }
636        write(value.length);
637        for (int x = 0; x < value.length; x++)
638            write(value[x]);
639    }
640
641    // String
642
643    protected void write(String value) throws IOException {
644        if (value == null) {
645            write(NULL_OBJECT);
646            return;
647        }
648        // write our output as UTF-8. Java misspells UTF-8 as UTF8 for official use in java.lang
649        byte[] bytes = value.getBytes("UTF8");
650        write(bytes.length);
651        baos.write(bytes);
652    }
653
654    protected void write(String[] value) throws IOException {
655        if (value == null) {
656            write(NULL_OBJECT);
657            return;
658        }
659        write(value.length);
660        for (int x = 0; x < value.length; x++)
661            write(value[x]);
662    }
663
664    protected void write(String[][] value) throws IOException {
665        if (value == null) {
666            write(NULL_OBJECT);
667            return;
668        }
669        write(value.length);
670        for (int x = 0; x < value.length; x++)
671            write(value[x]);
672    }
673
674    // BitSet
675
676    protected void write(BitSet value) throws IOException {
677        if (value == null) {
678            write(NULL_OBJECT);
679            return;
680        }
681        write(value.size());
682        // TODO: MAKE THIS SMALLER
683        for (int x = 0, max = value.size(); x < max; x++)
684            write(value.get(x));
685    }
686
687    // DEFLATOR for int and long
688
689    protected static byte[] deflate(byte[] bytes) {
690        int size = bytes.length;
691        if (size == 4) {
692            int possibleMagic = ByteUtils.convertIntFromBytes(bytes);
693            if (possibleMagic == NULL_OBJECT)
694                return NULL_BYTES;
695            else if (possibleMagic == DEFAULT_OBJECT)
696                return DEFAULT_BYTES;
697        }
698        for (int x = 0; x < bytes.length; x++) {
699            if (bytes[x] != 0)
700                break;
701            size--;
702        }
703        if (size == 0)
704            return new byte[1];
705
706        byte[] rVal = new byte[1 + size];
707        rVal[0] = (byte) size;
708        for (int x = 1; x < rVal.length; x++)
709            rVal[x] = bytes[bytes.length - size - 1 + x];
710
711        return rVal;
712    }
713
714    // BinarySavable
715
716    protected void write(Savable object) throws IOException {
717        if (object == null) {
718            write(NULL_OBJECT);
719            return;
720        }
721        int id = exporter.processBinarySavable(object);
722        write(id);
723    }
724
725    // BinarySavable array
726
727    protected void write(Savable[] objects) throws IOException {
728        if (objects == null) {
729            write(NULL_OBJECT);
730            return;
731        }
732        write(objects.length);
733        for (int x = 0; x < objects.length; x++) {
734            write(objects[x]);
735        }
736    }
737
738    protected void write(Savable[][] objects) throws IOException {
739        if (objects == null) {
740            write(NULL_OBJECT);
741            return;
742        }
743        write(objects.length);
744        for (int x = 0; x < objects.length; x++) {
745            write(objects[x]);
746        }
747    }
748
749    // ArrayList<BinarySavable>
750
751    protected void writeSavableArrayList(ArrayList array) throws IOException {
752        if (array == null) {
753            write(NULL_OBJECT);
754            return;
755        }
756        write(array.size());
757        for (Object bs : array) {
758            write((Savable) bs);
759        }
760    }
761
762    protected void writeSavableArrayListArray(ArrayList[] array)
763            throws IOException {
764        if (array == null) {
765            write(NULL_OBJECT);
766            return;
767        }
768        write(array.length);
769        for (ArrayList bs : array) {
770            writeSavableArrayList(bs);
771        }
772    }
773
774    protected void writeSavableArrayListArray2D(ArrayList[][] array)
775            throws IOException {
776        if (array == null) {
777            write(NULL_OBJECT);
778            return;
779        }
780        write(array.length);
781        for (ArrayList[] bs : array) {
782            writeSavableArrayListArray(bs);
783        }
784    }
785
786    // Map<BinarySavable, BinarySavable>
787
788    protected void writeSavableMap(
789            Map<? extends Savable, ? extends Savable> array) throws IOException {
790        if (array == null) {
791            write(NULL_OBJECT);
792            return;
793        }
794        write(array.size());
795        for (Savable key : array.keySet()) {
796            write(new Savable[] { key, array.get(key) });
797        }
798    }
799
800    protected void writeStringSavableMap(Map<String, ? extends Savable> array)
801            throws IOException {
802        if (array == null) {
803            write(NULL_OBJECT);
804            return;
805        }
806        write(array.size());
807
808        // write String array for keys
809        String[] keys = array.keySet().toArray(new String[] {});
810        write(keys);
811
812        // write Savable array for values
813        Savable[] values = array.values().toArray(new Savable[] {});
814        write(values);
815    }
816
817    protected void writeIntSavableMap(IntMap<? extends Savable> array)
818            throws IOException {
819        if (array == null) {
820            write(NULL_OBJECT);
821            return;
822        }
823        write(array.size());
824
825        int[] keys = new int[array.size()];
826        Savable[] values = new Savable[keys.length];
827        int i = 0;
828        for (Entry<? extends Savable> entry : array){
829            keys[i] = entry.getKey();
830            values[i] = entry.getValue();
831            i++;
832        }
833
834        // write String array for keys
835        write(keys);
836
837        // write Savable array for values
838        write(values);
839    }
840
841    // ArrayList<FloatBuffer>
842
843    protected void writeFloatBufferArrayList(ArrayList<FloatBuffer> array)
844            throws IOException {
845        if (array == null) {
846            write(NULL_OBJECT);
847            return;
848        }
849        write(array.size());
850        for (FloatBuffer buf : array) {
851            write(buf);
852        }
853    }
854
855    // ArrayList<FloatBuffer>
856
857    protected void writeByteBufferArrayList(ArrayList<ByteBuffer> array)
858            throws IOException {
859        if (array == null) {
860            write(NULL_OBJECT);
861            return;
862        }
863        write(array.size());
864        for (ByteBuffer buf : array) {
865            write(buf);
866        }
867    }
868
869    // NIO BUFFERS
870    // float buffer
871
872    protected void write(FloatBuffer value) throws IOException {
873        if (value == null) {
874            write(NULL_OBJECT);
875            return;
876        }
877        value.rewind();
878        int length = value.limit();
879        write(length);
880        for (int x = 0; x < length; x++) {
881            writeForBuffer(value.get());
882        }
883        value.rewind();
884    }
885
886    // int buffer
887
888    protected void write(IntBuffer value) throws IOException {
889        if (value == null) {
890            write(NULL_OBJECT);
891            return;
892        }
893        value.rewind();
894        int length = value.limit();
895        write(length);
896
897        for (int x = 0; x < length; x++) {
898            writeForBuffer(value.get());
899        }
900        value.rewind();
901    }
902
903    // byte buffer
904
905    protected void write(ByteBuffer value) throws IOException {
906        if (value == null) {
907            write(NULL_OBJECT);
908            return;
909        }
910        value.rewind();
911        int length = value.limit();
912        write(length);
913        for (int x = 0; x < length; x++) {
914            writeForBuffer(value.get());
915        }
916        value.rewind();
917    }
918
919    // short buffer
920
921    protected void write(ShortBuffer value) throws IOException {
922        if (value == null) {
923            write(NULL_OBJECT);
924            return;
925        }
926        value.rewind();
927        int length = value.limit();
928        write(length);
929        for (int x = 0; x < length; x++) {
930            writeForBuffer(value.get());
931        }
932        value.rewind();
933    }
934
935    public void write(Enum value, String name, Enum defVal) throws IOException {
936        if (value == defVal)
937            return;
938        if (value == null) {
939            return;
940        } else {
941            write(value.name(), name, null);
942        }
943    }
944}