• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 package com.jme3.export.binary;
34 
35 import com.jme3.export.OutputCapsule;
36 import com.jme3.export.Savable;
37 import com.jme3.util.IntMap;
38 import com.jme3.util.IntMap.Entry;
39 import java.io.ByteArrayOutputStream;
40 import java.io.IOException;
41 import java.nio.ByteBuffer;
42 import java.nio.FloatBuffer;
43 import java.nio.IntBuffer;
44 import java.nio.ShortBuffer;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.BitSet;
48 import java.util.Map;
49 
50 /**
51  * @author Joshua Slack
52  */
53 final 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 
BinaryOutputCapsule(BinaryExporter exporter, BinaryClassObject bco)66     public BinaryOutputCapsule(BinaryExporter exporter, BinaryClassObject bco) {
67         this.baos = new ByteArrayOutputStream();
68         this.exporter = exporter;
69         this.cObj = bco;
70     }
71 
write(byte value, String name, byte defVal)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 
write(byte[] value, String name, byte[] defVal)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 
write(byte[][] value, String name, byte[][] defVal)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 
write(int value, String name, int defVal)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 
write(int[] value, String name, int[] defVal)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 
write(int[][] value, String name, int[][] defVal)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 
write(float value, String name, float defVal)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 
write(float[] value, String name, float[] defVal)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 
write(float[][] value, String name, float[][] defVal)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 
write(double value, String name, double defVal)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 
write(double[] value, String name, double[] defVal)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 
write(double[][] value, String name, double[][] defVal)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 
write(long value, String name, long defVal)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 
write(long[] value, String name, long[] defVal)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 
write(long[][] value, String name, long[][] defVal)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 
write(short value, String name, short defVal)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 
write(short[] value, String name, short[] defVal)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 
write(short[][] value, String name, short[][] defVal)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 
write(boolean value, String name, boolean defVal)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 
write(boolean[] value, String name, boolean[] defVal)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 
write(boolean[][] value, String name, boolean[][] defVal)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 
write(String value, String name, String defVal)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 
write(String[] value, String name, String[] defVal)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 
write(String[][] value, String name, String[][] defVal)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 
write(BitSet value, String name, BitSet defVal)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 
write(Savable object, String name, Savable defVal)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 
write(Savable[] objects, String name, Savable[] defVal)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 
write(Savable[][] objects, String name, Savable[][] defVal)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 
write(FloatBuffer value, String name, FloatBuffer defVal)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 
write(IntBuffer value, String name, IntBuffer defVal)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 
write(ByteBuffer value, String name, ByteBuffer defVal)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 
write(ShortBuffer value, String name, ShortBuffer defVal)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 
writeFloatBufferArrayList(ArrayList<FloatBuffer> array, String name, ArrayList<FloatBuffer> defVal)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 
writeByteBufferArrayList(ArrayList<ByteBuffer> array, String name, ArrayList<ByteBuffer> defVal)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 
writeSavableArrayList(ArrayList array, String name, ArrayList defVal)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 
writeSavableArrayListArray(ArrayList[] array, String name, ArrayList[] defVal)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 
writeSavableArrayListArray2D(ArrayList[][] array, String name, ArrayList[][] defVal)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 
writeSavableMap(Map<? extends Savable, ? extends Savable> map, String name, Map<? extends Savable, ? extends Savable> defVal)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 
writeStringSavableMap(Map<String, ? extends Savable> map, String name, Map<String, ? extends Savable> defVal)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 
writeIntSavableMap(IntMap<? extends Savable> map, String name, IntMap<? extends Savable> defVal)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 
writeAlias(String name, byte fieldType)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...
generateAlias(String name, byte type)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
equals(Object arg0)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
hashCode()420     public int hashCode() {
421         int hash = 7;
422         hash = 23 * hash + Arrays.hashCode(this.bytes);
423         return hash;
424     }
425 
finish()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 
write(byte value)437     protected void write(byte value) throws IOException {
438         baos.write(value);
439     }
440 
writeForBuffer(byte value)441     protected void writeForBuffer(byte value) throws IOException {
442         baos.write(value);
443     }
444 
write(byte[] value)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 
write(byte[][] value)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 
write(int value)466     protected void write(int value) throws IOException {
467         baos.write(deflate(ByteUtils.convertToBytes(value)));
468     }
469 
writeForBuffer(int value)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 
write(int[] value)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 
write(int[][] value)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 
write(float value)501     protected void write(float value) throws IOException {
502         baos.write(ByteUtils.convertToBytes(value));
503     }
504 
writeForBuffer(float value)505     protected void writeForBuffer(float value) throws IOException {
506         int integer = Float.floatToIntBits(value);
507         writeForBuffer(integer);
508     }
509 
write(float[] value)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 
write(float[][] value)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 
write(double value)532     protected void write(double value) throws IOException {
533         baos.write(ByteUtils.convertToBytes(value));
534     }
535 
write(double[] value)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 
write(double[][] value)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 
write(long value)558     protected void write(long value) throws IOException {
559         baos.write(deflate(ByteUtils.convertToBytes(value)));
560     }
561 
write(long[] value)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 
write(long[][] value)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 
write(short value)584     protected void write(short value) throws IOException {
585         baos.write(ByteUtils.convertToBytes(value));
586     }
587 
writeForBuffer(short value)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 
write(short[] value)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 
write(short[][] value)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 
write(boolean value)617     protected void write(boolean value) throws IOException {
618         baos.write(ByteUtils.convertToBytes(value));
619     }
620 
write(boolean[] value)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 
write(boolean[][] value)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 
write(String value)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 
write(String[] value)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 
write(String[][] value)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 
write(BitSet value)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 
deflate(byte[] bytes)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 
write(Savable object)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 
write(Savable[] objects)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 
write(Savable[][] objects)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 
writeSavableArrayList(ArrayList array)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 
writeSavableArrayListArray(ArrayList[] array)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 
writeSavableArrayListArray2D(ArrayList[][] array)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 
writeSavableMap( Map<? extends Savable, ? extends Savable> array)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 
writeStringSavableMap(Map<String, ? extends Savable> array)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 
writeIntSavableMap(IntMap<? extends Savable> array)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 
writeFloatBufferArrayList(ArrayList<FloatBuffer> array)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 
writeByteBufferArrayList(ArrayList<ByteBuffer> array)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 
write(FloatBuffer value)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 
write(IntBuffer value)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 
write(ByteBuffer value)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 
write(ShortBuffer value)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 
write(Enum value, String name, Enum defVal)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 }