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 }