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.InputCapsule; 36 import com.jme3.export.Savable; 37 import com.jme3.export.SavableClassUtil; 38 import com.jme3.util.BufferUtils; 39 import com.jme3.util.IntMap; 40 import java.io.IOException; 41 import java.io.UnsupportedEncodingException; 42 import java.nio.ByteBuffer; 43 import java.nio.FloatBuffer; 44 import java.nio.IntBuffer; 45 import java.nio.ShortBuffer; 46 import java.util.ArrayList; 47 import java.util.BitSet; 48 import java.util.HashMap; 49 import java.util.Map; 50 import java.util.logging.Level; 51 import java.util.logging.Logger; 52 53 /** 54 * @author Joshua Slack 55 */ 56 final class BinaryInputCapsule implements InputCapsule { 57 58 private static final Logger logger = Logger 59 .getLogger(BinaryInputCapsule.class.getName()); 60 61 protected BinaryImporter importer; 62 protected BinaryClassObject cObj; 63 protected Savable savable; 64 protected HashMap<Byte, Object> fieldData; 65 66 protected int index = 0; 67 BinaryInputCapsule(BinaryImporter importer, Savable savable, BinaryClassObject bco)68 public BinaryInputCapsule(BinaryImporter importer, Savable savable, BinaryClassObject bco) { 69 this.importer = importer; 70 this.cObj = bco; 71 this.savable = savable; 72 } 73 setContent(byte[] content, int start, int limit)74 public void setContent(byte[] content, int start, int limit) { 75 fieldData = new HashMap<Byte, Object>(); 76 for (index = start; index < limit;) { 77 byte alias = content[index]; 78 79 index++; 80 81 try { 82 byte type = cObj.aliasFields.get(alias).type; 83 Object value = null; 84 85 switch (type) { 86 case BinaryClassField.BITSET: { 87 value = readBitSet(content); 88 break; 89 } 90 case BinaryClassField.BOOLEAN: { 91 value = readBoolean(content); 92 break; 93 } 94 case BinaryClassField.BOOLEAN_1D: { 95 value = readBooleanArray(content); 96 break; 97 } 98 case BinaryClassField.BOOLEAN_2D: { 99 value = readBooleanArray2D(content); 100 break; 101 } 102 case BinaryClassField.BYTE: { 103 value = readByte(content); 104 break; 105 } 106 case BinaryClassField.BYTE_1D: { 107 value = readByteArray(content); 108 break; 109 } 110 case BinaryClassField.BYTE_2D: { 111 value = readByteArray2D(content); 112 break; 113 } 114 case BinaryClassField.BYTEBUFFER: { 115 value = readByteBuffer(content); 116 break; 117 } 118 case BinaryClassField.DOUBLE: { 119 value = readDouble(content); 120 break; 121 } 122 case BinaryClassField.DOUBLE_1D: { 123 value = readDoubleArray(content); 124 break; 125 } 126 case BinaryClassField.DOUBLE_2D: { 127 value = readDoubleArray2D(content); 128 break; 129 } 130 case BinaryClassField.FLOAT: { 131 value = readFloat(content); 132 break; 133 } 134 case BinaryClassField.FLOAT_1D: { 135 value = readFloatArray(content); 136 break; 137 } 138 case BinaryClassField.FLOAT_2D: { 139 value = readFloatArray2D(content); 140 break; 141 } 142 case BinaryClassField.FLOATBUFFER: { 143 value = readFloatBuffer(content); 144 break; 145 } 146 case BinaryClassField.FLOATBUFFER_ARRAYLIST: { 147 value = readFloatBufferArrayList(content); 148 break; 149 } 150 case BinaryClassField.BYTEBUFFER_ARRAYLIST: { 151 value = readByteBufferArrayList(content); 152 break; 153 } 154 case BinaryClassField.INT: { 155 value = readInt(content); 156 break; 157 } 158 case BinaryClassField.INT_1D: { 159 value = readIntArray(content); 160 break; 161 } 162 case BinaryClassField.INT_2D: { 163 value = readIntArray2D(content); 164 break; 165 } 166 case BinaryClassField.INTBUFFER: { 167 value = readIntBuffer(content); 168 break; 169 } 170 case BinaryClassField.LONG: { 171 value = readLong(content); 172 break; 173 } 174 case BinaryClassField.LONG_1D: { 175 value = readLongArray(content); 176 break; 177 } 178 case BinaryClassField.LONG_2D: { 179 value = readLongArray2D(content); 180 break; 181 } 182 case BinaryClassField.SAVABLE: { 183 value = readSavable(content); 184 break; 185 } 186 case BinaryClassField.SAVABLE_1D: { 187 value = readSavableArray(content); 188 break; 189 } 190 case BinaryClassField.SAVABLE_2D: { 191 value = readSavableArray2D(content); 192 break; 193 } 194 case BinaryClassField.SAVABLE_ARRAYLIST: { 195 value = readSavableArray(content); 196 break; 197 } 198 case BinaryClassField.SAVABLE_ARRAYLIST_1D: { 199 value = readSavableArray2D(content); 200 break; 201 } 202 case BinaryClassField.SAVABLE_ARRAYLIST_2D: { 203 value = readSavableArray3D(content); 204 break; 205 } 206 case BinaryClassField.SAVABLE_MAP: { 207 value = readSavableMap(content); 208 break; 209 } 210 case BinaryClassField.STRING_SAVABLE_MAP: { 211 value = readStringSavableMap(content); 212 break; 213 } 214 case BinaryClassField.INT_SAVABLE_MAP: { 215 value = readIntSavableMap(content); 216 break; 217 } 218 case BinaryClassField.SHORT: { 219 value = readShort(content); 220 break; 221 } 222 case BinaryClassField.SHORT_1D: { 223 value = readShortArray(content); 224 break; 225 } 226 case BinaryClassField.SHORT_2D: { 227 value = readShortArray2D(content); 228 break; 229 } 230 case BinaryClassField.SHORTBUFFER: { 231 value = readShortBuffer(content); 232 break; 233 } 234 case BinaryClassField.STRING: { 235 value = readString(content); 236 break; 237 } 238 case BinaryClassField.STRING_1D: { 239 value = readStringArray(content); 240 break; 241 } 242 case BinaryClassField.STRING_2D: { 243 value = readStringArray2D(content); 244 break; 245 } 246 247 default: 248 // skip put statement 249 continue; 250 } 251 252 fieldData.put(alias, value); 253 254 } catch (IOException e) { 255 logger.logp(Level.SEVERE, this.getClass().toString(), 256 "setContent(byte[] content)", "Exception", e); 257 } 258 } 259 } 260 getSavableVersion(Class<? extends Savable> desiredClass)261 public int getSavableVersion(Class<? extends Savable> desiredClass){ 262 return SavableClassUtil.getSavedSavableVersion(savable, desiredClass, 263 cObj.classHierarchyVersions, importer.getFormatVersion()); 264 } 265 readBitSet(String name, BitSet defVal)266 public BitSet readBitSet(String name, BitSet defVal) throws IOException { 267 BinaryClassField field = cObj.nameFields.get(name); 268 if (field == null || !fieldData.containsKey(field.alias)) 269 return defVal; 270 return (BitSet) fieldData.get(field.alias); 271 } 272 readBoolean(String name, boolean defVal)273 public boolean readBoolean(String name, boolean defVal) throws IOException { 274 BinaryClassField field = cObj.nameFields.get(name); 275 if (field == null || !fieldData.containsKey(field.alias)) 276 return defVal; 277 return ((Boolean) fieldData.get(field.alias)).booleanValue(); 278 } 279 readBooleanArray(String name, boolean[] defVal)280 public boolean[] readBooleanArray(String name, boolean[] defVal) 281 throws IOException { 282 BinaryClassField field = cObj.nameFields.get(name); 283 if (field == null || !fieldData.containsKey(field.alias)) 284 return defVal; 285 return (boolean[]) fieldData.get(field.alias); 286 } 287 readBooleanArray2D(String name, boolean[][] defVal)288 public boolean[][] readBooleanArray2D(String name, boolean[][] defVal) 289 throws IOException { 290 BinaryClassField field = cObj.nameFields.get(name); 291 if (field == null || !fieldData.containsKey(field.alias)) 292 return defVal; 293 return (boolean[][]) fieldData.get(field.alias); 294 } 295 readByte(String name, byte defVal)296 public byte readByte(String name, byte defVal) throws IOException { 297 BinaryClassField field = cObj.nameFields.get(name); 298 if (field == null || !fieldData.containsKey(field.alias)) 299 return defVal; 300 return ((Byte) fieldData.get(field.alias)).byteValue(); 301 } 302 readByteArray(String name, byte[] defVal)303 public byte[] readByteArray(String name, byte[] defVal) throws IOException { 304 BinaryClassField field = cObj.nameFields.get(name); 305 if (field == null || !fieldData.containsKey(field.alias)) 306 return defVal; 307 return (byte[]) fieldData.get(field.alias); 308 } 309 readByteArray2D(String name, byte[][] defVal)310 public byte[][] readByteArray2D(String name, byte[][] defVal) 311 throws IOException { 312 BinaryClassField field = cObj.nameFields.get(name); 313 if (field == null || !fieldData.containsKey(field.alias)) 314 return defVal; 315 return (byte[][]) fieldData.get(field.alias); 316 } 317 readByteBuffer(String name, ByteBuffer defVal)318 public ByteBuffer readByteBuffer(String name, ByteBuffer defVal) 319 throws IOException { 320 BinaryClassField field = cObj.nameFields.get(name); 321 if (field == null || !fieldData.containsKey(field.alias)) 322 return defVal; 323 return (ByteBuffer) fieldData.get(field.alias); 324 } 325 326 @SuppressWarnings("unchecked") readByteBufferArrayList(String name, ArrayList<ByteBuffer> defVal)327 public ArrayList<ByteBuffer> readByteBufferArrayList(String name, 328 ArrayList<ByteBuffer> defVal) throws IOException { 329 BinaryClassField field = cObj.nameFields.get(name); 330 if (field == null || !fieldData.containsKey(field.alias)) 331 return defVal; 332 return (ArrayList<ByteBuffer>) fieldData.get(field.alias); 333 } 334 readDouble(String name, double defVal)335 public double readDouble(String name, double defVal) throws IOException { 336 BinaryClassField field = cObj.nameFields.get(name); 337 if (field == null || !fieldData.containsKey(field.alias)) 338 return defVal; 339 return ((Double) fieldData.get(field.alias)).doubleValue(); 340 } 341 readDoubleArray(String name, double[] defVal)342 public double[] readDoubleArray(String name, double[] defVal) 343 throws IOException { 344 BinaryClassField field = cObj.nameFields.get(name); 345 if (field == null || !fieldData.containsKey(field.alias)) 346 return defVal; 347 return (double[]) fieldData.get(field.alias); 348 } 349 readDoubleArray2D(String name, double[][] defVal)350 public double[][] readDoubleArray2D(String name, double[][] defVal) 351 throws IOException { 352 BinaryClassField field = cObj.nameFields.get(name); 353 if (field == null || !fieldData.containsKey(field.alias)) 354 return defVal; 355 return (double[][]) fieldData.get(field.alias); 356 } 357 readFloat(String name, float defVal)358 public float readFloat(String name, float defVal) throws IOException { 359 BinaryClassField field = cObj.nameFields.get(name); 360 if (field == null || !fieldData.containsKey(field.alias)) 361 return defVal; 362 return ((Float) fieldData.get(field.alias)).floatValue(); 363 } 364 readFloatArray(String name, float[] defVal)365 public float[] readFloatArray(String name, float[] defVal) 366 throws IOException { 367 BinaryClassField field = cObj.nameFields.get(name); 368 if (field == null || !fieldData.containsKey(field.alias)) 369 return defVal; 370 return (float[]) fieldData.get(field.alias); 371 } 372 readFloatArray2D(String name, float[][] defVal)373 public float[][] readFloatArray2D(String name, float[][] defVal) 374 throws IOException { 375 BinaryClassField field = cObj.nameFields.get(name); 376 if (field == null || !fieldData.containsKey(field.alias)) 377 return defVal; 378 return (float[][]) fieldData.get(field.alias); 379 } 380 readFloatBuffer(String name, FloatBuffer defVal)381 public FloatBuffer readFloatBuffer(String name, FloatBuffer defVal) 382 throws IOException { 383 BinaryClassField field = cObj.nameFields.get(name); 384 if (field == null || !fieldData.containsKey(field.alias)) 385 return defVal; 386 return (FloatBuffer) fieldData.get(field.alias); 387 } 388 389 @SuppressWarnings("unchecked") readFloatBufferArrayList(String name, ArrayList<FloatBuffer> defVal)390 public ArrayList<FloatBuffer> readFloatBufferArrayList(String name, 391 ArrayList<FloatBuffer> defVal) throws IOException { 392 BinaryClassField field = cObj.nameFields.get(name); 393 if (field == null || !fieldData.containsKey(field.alias)) 394 return defVal; 395 return (ArrayList<FloatBuffer>) fieldData.get(field.alias); 396 } 397 readInt(String name, int defVal)398 public int readInt(String name, int defVal) throws IOException { 399 BinaryClassField field = cObj.nameFields.get(name); 400 if (field == null || !fieldData.containsKey(field.alias)) 401 return defVal; 402 return ((Integer) fieldData.get(field.alias)).intValue(); 403 } 404 readIntArray(String name, int[] defVal)405 public int[] readIntArray(String name, int[] defVal) throws IOException { 406 BinaryClassField field = cObj.nameFields.get(name); 407 if (field == null || !fieldData.containsKey(field.alias)) 408 return defVal; 409 return (int[]) fieldData.get(field.alias); 410 } 411 readIntArray2D(String name, int[][] defVal)412 public int[][] readIntArray2D(String name, int[][] defVal) 413 throws IOException { 414 BinaryClassField field = cObj.nameFields.get(name); 415 if (field == null || !fieldData.containsKey(field.alias)) 416 return defVal; 417 return (int[][]) fieldData.get(field.alias); 418 } 419 readIntBuffer(String name, IntBuffer defVal)420 public IntBuffer readIntBuffer(String name, IntBuffer defVal) 421 throws IOException { 422 BinaryClassField field = cObj.nameFields.get(name); 423 if (field == null || !fieldData.containsKey(field.alias)) 424 return defVal; 425 return (IntBuffer) fieldData.get(field.alias); 426 } 427 readLong(String name, long defVal)428 public long readLong(String name, long defVal) throws IOException { 429 BinaryClassField field = cObj.nameFields.get(name); 430 if (field == null || !fieldData.containsKey(field.alias)) 431 return defVal; 432 return ((Long) fieldData.get(field.alias)).longValue(); 433 } 434 readLongArray(String name, long[] defVal)435 public long[] readLongArray(String name, long[] defVal) throws IOException { 436 BinaryClassField field = cObj.nameFields.get(name); 437 if (field == null || !fieldData.containsKey(field.alias)) 438 return defVal; 439 return (long[]) fieldData.get(field.alias); 440 } 441 readLongArray2D(String name, long[][] defVal)442 public long[][] readLongArray2D(String name, long[][] defVal) 443 throws IOException { 444 BinaryClassField field = cObj.nameFields.get(name); 445 if (field == null || !fieldData.containsKey(field.alias)) 446 return defVal; 447 return (long[][]) fieldData.get(field.alias); 448 } 449 readSavable(String name, Savable defVal)450 public Savable readSavable(String name, Savable defVal) throws IOException { 451 BinaryClassField field = cObj.nameFields.get(name); 452 if (field == null || !fieldData.containsKey(field.alias)) 453 return defVal; 454 Object value = fieldData.get(field.alias); 455 if (value == null) 456 return null; 457 else if (value instanceof ID) { 458 value = importer.readObject(((ID) value).id); 459 fieldData.put(field.alias, value); 460 return (Savable) value; 461 } else 462 return defVal; 463 } 464 readSavableArray(String name, Savable[] defVal)465 public Savable[] readSavableArray(String name, Savable[] defVal) 466 throws IOException { 467 BinaryClassField field = cObj.nameFields.get(name); 468 if (field == null || !fieldData.containsKey(field.alias)) 469 return defVal; 470 Object[] values = (Object[]) fieldData.get(field.alias); 471 if (values instanceof ID[]) { 472 values = resolveIDs(values); 473 fieldData.put(field.alias, values); 474 return (Savable[]) values; 475 } else 476 return defVal; 477 } 478 resolveIDs(Object[] values)479 private Savable[] resolveIDs(Object[] values) { 480 if (values != null) { 481 Savable[] savables = new Savable[values.length]; 482 for (int i = 0; i < values.length; i++) { 483 final ID id = (ID) values[i]; 484 savables[i] = id != null ? importer.readObject(id.id) : null; 485 } 486 return savables; 487 } else { 488 return null; 489 } 490 } 491 readSavableArray2D(String name, Savable[][] defVal)492 public Savable[][] readSavableArray2D(String name, Savable[][] defVal) 493 throws IOException { 494 BinaryClassField field = cObj.nameFields.get(name); 495 if (field == null ||!fieldData.containsKey(field.alias)) 496 return defVal; 497 Object[][] values = (Object[][]) fieldData.get(field.alias); 498 if (values instanceof ID[][]) { 499 Savable[][] savables = new Savable[values.length][]; 500 for (int i = 0; i < values.length; i++) { 501 if (values[i] != null) { 502 savables[i] = resolveIDs(values[i]); 503 } else savables[i] = null; 504 } 505 values = savables; 506 fieldData.put(field.alias, values); 507 } 508 return (Savable[][]) values; 509 } 510 readSavableArray3D(String name, Savable[][][] defVal)511 public Savable[][][] readSavableArray3D(String name, Savable[][][] defVal) 512 throws IOException { 513 BinaryClassField field = cObj.nameFields.get(name); 514 if (field == null || !fieldData.containsKey(field.alias)) 515 return defVal; 516 Object[][][] values = (Object[][][]) fieldData.get(field.alias); 517 if (values instanceof ID[][][]) { 518 Savable[][][] savables = new Savable[values.length][][]; 519 for (int i = 0; i < values.length; i++) { 520 if (values[i] != null) { 521 savables[i] = new Savable[values[i].length][]; 522 for (int j = 0; j < values[i].length; j++) { 523 savables[i][j] = resolveIDs(values[i][j]); 524 } 525 } else savables[i] = null; 526 } 527 fieldData.put(field.alias, savables); 528 return savables; 529 } else 530 return defVal; 531 } 532 savableArrayListFromArray(Savable[] savables)533 private ArrayList<Savable> savableArrayListFromArray(Savable[] savables) { 534 if(savables == null) { 535 return null; 536 } 537 ArrayList<Savable> arrayList = new ArrayList<Savable>(savables.length); 538 for (int x = 0; x < savables.length; x++) { 539 arrayList.add(savables[x]); 540 } 541 return arrayList; 542 } 543 544 // Assumes array of size 2 arrays where pos 0 is key and pos 1 is value. savableMapFrom2DArray(Savable[][] savables)545 private Map<Savable, Savable> savableMapFrom2DArray(Savable[][] savables) { 546 if(savables == null) { 547 return null; 548 } 549 Map<Savable, Savable> map = new HashMap<Savable, Savable>(savables.length); 550 for (int x = 0; x < savables.length; x++) { 551 map.put(savables[x][0], savables[x][1]); 552 } 553 return map; 554 } 555 stringSavableMapFromKV(String[] keys, Savable[] values)556 private Map<String, Savable> stringSavableMapFromKV(String[] keys, Savable[] values) { 557 if(keys == null || values == null) { 558 return null; 559 } 560 561 Map<String, Savable> map = new HashMap<String, Savable>(keys.length); 562 for (int x = 0; x < keys.length; x++) 563 map.put(keys[x], values[x]); 564 565 return map; 566 } 567 intSavableMapFromKV(int[] keys, Savable[] values)568 private IntMap<Savable> intSavableMapFromKV(int[] keys, Savable[] values) { 569 if(keys == null || values == null) { 570 return null; 571 } 572 573 IntMap<Savable> map = new IntMap<Savable>(keys.length); 574 for (int x = 0; x < keys.length; x++) 575 map.put(keys[x], values[x]); 576 577 return map; 578 } 579 readSavableArrayList(String name, ArrayList defVal)580 public ArrayList readSavableArrayList(String name, ArrayList defVal) 581 throws IOException { 582 BinaryClassField field = cObj.nameFields.get(name); 583 if (field == null || !fieldData.containsKey(field.alias)) 584 return defVal; 585 Object value = fieldData.get(field.alias); 586 if (value instanceof ID[]) { 587 // read Savable array and convert to ArrayList 588 Savable[] savables = readSavableArray(name, null); 589 value = savableArrayListFromArray(savables); 590 fieldData.put(field.alias, value); 591 } 592 return (ArrayList) value; 593 } 594 readSavableArrayListArray(String name, ArrayList[] defVal)595 public ArrayList[] readSavableArrayListArray(String name, ArrayList[] defVal) 596 throws IOException { 597 BinaryClassField field = cObj.nameFields.get(name); 598 if (field == null || !fieldData.containsKey(field.alias)) 599 return defVal; 600 Object value = fieldData.get(field.alias); 601 if (value instanceof ID[][]) { 602 // read 2D Savable array and convert to ArrayList array 603 Savable[][] savables = readSavableArray2D(name, null); 604 if (savables != null) { 605 ArrayList[] arrayLists = new ArrayList[savables.length]; 606 for (int i = 0; i < savables.length; i++) { 607 arrayLists[i] = savableArrayListFromArray(savables[i]); 608 } 609 value = arrayLists; 610 } else 611 value = defVal; 612 fieldData.put(field.alias, value); 613 } 614 return (ArrayList[]) value; 615 } 616 readSavableArrayListArray2D(String name, ArrayList[][] defVal)617 public ArrayList[][] readSavableArrayListArray2D(String name, 618 ArrayList[][] defVal) throws IOException { 619 BinaryClassField field = cObj.nameFields.get(name); 620 if (field == null || !fieldData.containsKey(field.alias)) 621 return defVal; 622 Object value = fieldData.get(field.alias); 623 if (value instanceof ID[][][]) { 624 // read 3D Savable array and convert to 2D ArrayList array 625 Savable[][][] savables = readSavableArray3D(name, null); 626 if (savables != null && savables.length > 0) { 627 ArrayList[][] arrayLists = new ArrayList[savables.length][]; 628 for (int i = 0; i < savables.length; i++) { 629 arrayLists[i] = new ArrayList[savables[i].length]; 630 for (int j = 0; j < savables[i].length; j++) { 631 arrayLists[i][j] = savableArrayListFromArray(savables[i][j]); 632 } 633 } 634 value = arrayLists; 635 } else 636 value = defVal; 637 fieldData.put(field.alias, value); 638 } 639 return (ArrayList[][]) value; 640 } 641 642 @SuppressWarnings("unchecked") readSavableMap(String name, Map<? extends Savable, ? extends Savable> defVal)643 public Map<? extends Savable, ? extends Savable> readSavableMap(String name, Map<? extends Savable, ? extends Savable> defVal) 644 throws IOException { 645 BinaryClassField field = cObj.nameFields.get(name); 646 if (field == null || !fieldData.containsKey(field.alias)) 647 return defVal; 648 Object value = fieldData.get(field.alias); 649 if (value instanceof ID[][]) { 650 // read Savable array and convert to Map 651 Savable[][] savables = readSavableArray2D(name, null); 652 value = savableMapFrom2DArray(savables); 653 fieldData.put(field.alias, value); 654 } 655 return (Map<? extends Savable, ? extends Savable>) value; 656 } 657 658 @SuppressWarnings("unchecked") readStringSavableMap(String name, Map<String, ? extends Savable> defVal)659 public Map<String, ? extends Savable> readStringSavableMap(String name, Map<String, ? extends Savable> defVal) 660 throws IOException { 661 BinaryClassField field = cObj.nameFields.get(name); 662 if (field == null || !fieldData.containsKey(field.alias)) 663 return defVal; 664 Object value = fieldData.get(field.alias); 665 if (value instanceof StringIDMap) { 666 // read Savable array and convert to Map values 667 StringIDMap in = (StringIDMap) value; 668 Savable[] values = resolveIDs(in.values); 669 value = stringSavableMapFromKV(in.keys, values); 670 fieldData.put(field.alias, value); 671 } 672 return (Map<String, Savable>) value; 673 } 674 675 @SuppressWarnings("unchecked") readIntSavableMap(String name, IntMap<? extends Savable> defVal)676 public IntMap<? extends Savable> readIntSavableMap(String name, IntMap<? extends Savable> defVal) 677 throws IOException { 678 BinaryClassField field = cObj.nameFields.get(name); 679 if (field == null || !fieldData.containsKey(field.alias)) 680 return defVal; 681 Object value = fieldData.get(field.alias); 682 if (value instanceof IntIDMap) { 683 // read Savable array and convert to Map values 684 IntIDMap in = (IntIDMap) value; 685 Savable[] values = resolveIDs(in.values); 686 value = intSavableMapFromKV(in.keys, values); 687 fieldData.put(field.alias, value); 688 } 689 return (IntMap<Savable>) value; 690 } 691 readShort(String name, short defVal)692 public short readShort(String name, short defVal) throws IOException { 693 BinaryClassField field = cObj.nameFields.get(name); 694 if (field == null || !fieldData.containsKey(field.alias)) 695 return defVal; 696 return ((Short) fieldData.get(field.alias)).shortValue(); 697 } 698 readShortArray(String name, short[] defVal)699 public short[] readShortArray(String name, short[] defVal) 700 throws IOException { 701 BinaryClassField field = cObj.nameFields.get(name); 702 if (field == null || !fieldData.containsKey(field.alias)) 703 return defVal; 704 return (short[]) fieldData.get(field.alias); 705 } 706 readShortArray2D(String name, short[][] defVal)707 public short[][] readShortArray2D(String name, short[][] defVal) 708 throws IOException { 709 BinaryClassField field = cObj.nameFields.get(name); 710 if (field == null || !fieldData.containsKey(field.alias)) 711 return defVal; 712 return (short[][]) fieldData.get(field.alias); 713 } 714 readShortBuffer(String name, ShortBuffer defVal)715 public ShortBuffer readShortBuffer(String name, ShortBuffer defVal) 716 throws IOException { 717 BinaryClassField field = cObj.nameFields.get(name); 718 if (field == null || !fieldData.containsKey(field.alias)) 719 return defVal; 720 return (ShortBuffer) fieldData.get(field.alias); 721 } 722 readString(String name, String defVal)723 public String readString(String name, String defVal) throws IOException { 724 BinaryClassField field = cObj.nameFields.get(name); 725 if (field == null || !fieldData.containsKey(field.alias)) 726 return defVal; 727 return (String) fieldData.get(field.alias); 728 } 729 readStringArray(String name, String[] defVal)730 public String[] readStringArray(String name, String[] defVal) 731 throws IOException { 732 BinaryClassField field = cObj.nameFields.get(name); 733 if (field == null || !fieldData.containsKey(field.alias)) 734 return defVal; 735 return (String[]) fieldData.get(field.alias); 736 } 737 readStringArray2D(String name, String[][] defVal)738 public String[][] readStringArray2D(String name, String[][] defVal) 739 throws IOException { 740 BinaryClassField field = cObj.nameFields.get(name); 741 if (field == null || !fieldData.containsKey(field.alias)) 742 return defVal; 743 return (String[][]) fieldData.get(field.alias); 744 } 745 746 // byte primitive 747 readByte(byte[] content)748 protected byte readByte(byte[] content) throws IOException { 749 byte value = content[index]; 750 index++; 751 return value; 752 } 753 readByteForBuffer(byte[] content)754 protected byte readByteForBuffer(byte[] content) throws IOException { 755 byte value = content[index]; 756 index++; 757 return value; 758 } 759 readByteArray(byte[] content)760 protected byte[] readByteArray(byte[] content) throws IOException { 761 int length = readInt(content); 762 if (length == BinaryOutputCapsule.NULL_OBJECT) 763 return null; 764 byte[] value = new byte[length]; 765 for (int x = 0; x < length; x++) 766 value[x] = readByte(content); 767 return value; 768 } 769 readByteArray2D(byte[] content)770 protected byte[][] readByteArray2D(byte[] content) throws IOException { 771 int length = readInt(content); 772 if (length == BinaryOutputCapsule.NULL_OBJECT) 773 return null; 774 byte[][] value = new byte[length][]; 775 for (int x = 0; x < length; x++) 776 value[x] = readByteArray(content); 777 return value; 778 } 779 780 // int primitive 781 readIntForBuffer(byte[] content)782 protected int readIntForBuffer(byte[] content){ 783 int number = ((content[index+3] & 0xFF) << 24) 784 + ((content[index+2] & 0xFF) << 16) 785 + ((content[index+1] & 0xFF) << 8) 786 + (content[index] & 0xFF); 787 index += 4; 788 return number; 789 } 790 readInt(byte[] content)791 protected int readInt(byte[] content) throws IOException { 792 byte[] bytes = inflateFrom(content, index); 793 index += 1 + bytes.length; 794 bytes = ByteUtils.rightAlignBytes(bytes, 4); 795 int value = ByteUtils.convertIntFromBytes(bytes); 796 if (value == BinaryOutputCapsule.NULL_OBJECT 797 || value == BinaryOutputCapsule.DEFAULT_OBJECT) 798 index -= 4; 799 return value; 800 } 801 readIntArray(byte[] content)802 protected int[] readIntArray(byte[] content) throws IOException { 803 int length = readInt(content); 804 if (length == BinaryOutputCapsule.NULL_OBJECT) 805 return null; 806 int[] value = new int[length]; 807 for (int x = 0; x < length; x++) 808 value[x] = readInt(content); 809 return value; 810 } 811 readIntArray2D(byte[] content)812 protected int[][] readIntArray2D(byte[] content) throws IOException { 813 int length = readInt(content); 814 if (length == BinaryOutputCapsule.NULL_OBJECT) 815 return null; 816 int[][] value = new int[length][]; 817 for (int x = 0; x < length; x++) 818 value[x] = readIntArray(content); 819 return value; 820 } 821 822 // float primitive 823 readFloat(byte[] content)824 protected float readFloat(byte[] content) throws IOException { 825 float value = ByteUtils.convertFloatFromBytes(content, index); 826 index += 4; 827 return value; 828 } 829 readFloatForBuffer(byte[] content)830 protected float readFloatForBuffer(byte[] content) throws IOException { 831 int number = readIntForBuffer(content); 832 return Float.intBitsToFloat(number); 833 } 834 readFloatArray(byte[] content)835 protected float[] readFloatArray(byte[] content) throws IOException { 836 int length = readInt(content); 837 if (length == BinaryOutputCapsule.NULL_OBJECT) 838 return null; 839 float[] value = new float[length]; 840 for (int x = 0; x < length; x++) 841 value[x] = readFloat(content); 842 return value; 843 } 844 readFloatArray2D(byte[] content)845 protected float[][] readFloatArray2D(byte[] content) throws IOException { 846 int length = readInt(content); 847 if (length == BinaryOutputCapsule.NULL_OBJECT) 848 return null; 849 float[][] value = new float[length][]; 850 for (int x = 0; x < length; x++) 851 value[x] = readFloatArray(content); 852 return value; 853 } 854 855 // double primitive 856 readDouble(byte[] content)857 protected double readDouble(byte[] content) throws IOException { 858 double value = ByteUtils.convertDoubleFromBytes(content, index); 859 index += 8; 860 return value; 861 } 862 readDoubleArray(byte[] content)863 protected double[] readDoubleArray(byte[] content) throws IOException { 864 int length = readInt(content); 865 if (length == BinaryOutputCapsule.NULL_OBJECT) 866 return null; 867 double[] value = new double[length]; 868 for (int x = 0; x < length; x++) 869 value[x] = readDouble(content); 870 return value; 871 } 872 readDoubleArray2D(byte[] content)873 protected double[][] readDoubleArray2D(byte[] content) throws IOException { 874 int length = readInt(content); 875 if (length == BinaryOutputCapsule.NULL_OBJECT) 876 return null; 877 double[][] value = new double[length][]; 878 for (int x = 0; x < length; x++) 879 value[x] = readDoubleArray(content); 880 return value; 881 } 882 883 // long primitive 884 readLong(byte[] content)885 protected long readLong(byte[] content) throws IOException { 886 byte[] bytes = inflateFrom(content, index); 887 index += 1 + bytes.length; 888 bytes = ByteUtils.rightAlignBytes(bytes, 8); 889 long value = ByteUtils.convertLongFromBytes(bytes); 890 return value; 891 } 892 readLongArray(byte[] content)893 protected long[] readLongArray(byte[] content) throws IOException { 894 int length = readInt(content); 895 if (length == BinaryOutputCapsule.NULL_OBJECT) 896 return null; 897 long[] value = new long[length]; 898 for (int x = 0; x < length; x++) 899 value[x] = readLong(content); 900 return value; 901 } 902 readLongArray2D(byte[] content)903 protected long[][] readLongArray2D(byte[] content) throws IOException { 904 int length = readInt(content); 905 if (length == BinaryOutputCapsule.NULL_OBJECT) 906 return null; 907 long[][] value = new long[length][]; 908 for (int x = 0; x < length; x++) 909 value[x] = readLongArray(content); 910 return value; 911 } 912 913 // short primitive 914 readShort(byte[] content)915 protected short readShort(byte[] content) throws IOException { 916 short value = ByteUtils.convertShortFromBytes(content, index); 917 index += 2; 918 return value; 919 } 920 readShortForBuffer(byte[] content)921 protected short readShortForBuffer(byte[] content) throws IOException { 922 short number = (short) ((content[index+0] & 0xFF) 923 + ((content[index+1] & 0xFF) << 8)); 924 index += 2; 925 return number; 926 } 927 readShortArray(byte[] content)928 protected short[] readShortArray(byte[] content) throws IOException { 929 int length = readInt(content); 930 if (length == BinaryOutputCapsule.NULL_OBJECT) 931 return null; 932 short[] value = new short[length]; 933 for (int x = 0; x < length; x++) 934 value[x] = readShort(content); 935 return value; 936 } 937 readShortArray2D(byte[] content)938 protected short[][] readShortArray2D(byte[] content) throws IOException { 939 int length = readInt(content); 940 if (length == BinaryOutputCapsule.NULL_OBJECT) 941 return null; 942 short[][] value = new short[length][]; 943 for (int x = 0; x < length; x++) 944 value[x] = readShortArray(content); 945 return value; 946 } 947 948 // boolean primitive 949 readBoolean(byte[] content)950 protected boolean readBoolean(byte[] content) throws IOException { 951 boolean value = ByteUtils.convertBooleanFromBytes(content, index); 952 index += 1; 953 return value; 954 } 955 readBooleanArray(byte[] content)956 protected boolean[] readBooleanArray(byte[] content) throws IOException { 957 int length = readInt(content); 958 if (length == BinaryOutputCapsule.NULL_OBJECT) 959 return null; 960 boolean[] value = new boolean[length]; 961 for (int x = 0; x < length; x++) 962 value[x] = readBoolean(content); 963 return value; 964 } 965 readBooleanArray2D(byte[] content)966 protected boolean[][] readBooleanArray2D(byte[] content) throws IOException { 967 int length = readInt(content); 968 if (length == BinaryOutputCapsule.NULL_OBJECT) 969 return null; 970 boolean[][] value = new boolean[length][]; 971 for (int x = 0; x < length; x++) 972 value[x] = readBooleanArray(content); 973 return value; 974 } 975 976 /* 977 * UTF-8 crash course: 978 * 979 * UTF-8 codepoints map to UTF-16 codepoints and vv, which is what Java uses for it's Strings. 980 * (so a UTF-8 codepoint can contain all possible values for a Java char) 981 * 982 * A UTF-8 codepoint can be 1, 2 or 3 bytes long. How long a codepint is can be told by reading the first byte: 983 * b < 0x80, 1 byte 984 * (b & 0xC0) == 0xC0, 2 bytes 985 * (b & 0xE0) == 0xE0, 3 bytes 986 * 987 * However there is an additional restriction to UTF-8, to enable you to find the start of a UTF-8 codepoint, 988 * if you start reading at a random point in a UTF-8 byte stream. That's why UTF-8 requires for the second and third byte of 989 * a multibyte codepoint: 990 * (b & 0x80) == 0x80 (in other words, first bit must be 1) 991 */ 992 private final static int UTF8_START = 0; // next byte should be the start of a new 993 private final static int UTF8_2BYTE = 2; // next byte should be the second byte of a 2 byte codepoint 994 private final static int UTF8_3BYTE_1 = 3; // next byte should be the second byte of a 3 byte codepoint 995 private final static int UTF8_3BYTE_2 = 4; // next byte should be the third byte of a 3 byte codepoint 996 private final static int UTF8_ILLEGAL = 10; // not an UTF8 string 997 998 // String readString(byte[] content)999 protected String readString(byte[] content) throws IOException { 1000 int length = readInt(content); 1001 if (length == BinaryOutputCapsule.NULL_OBJECT) 1002 return null; 1003 1004 /* 1005 * @see ISSUE 276 1006 * 1007 * We'll transfer the bytes into a seperate byte array. 1008 * While we do that we'll take the opportunity to check if the byte data is valid UTF-8. 1009 * 1010 * If it is not UTF-8 it is most likely saved with the BinaryOutputCapsule bug, that saves Strings using their native 1011 * encoding. Unfortunatly there is no way to know what encoding was used, so we'll parse using the most common one in 1012 * that case; latin-1 aka ISO8859_1 1013 * 1014 * Encoding of "low" ASCII codepoint (in plain speak: when no special characters are used) will usually look the same 1015 * for UTF-8 and the other 1 byte codepoint encodings (espc true for numbers and regular letters of the alphabet). So these 1016 * are valid UTF-8 and will give the same result (at most a few charakters will appear different, such as the euro sign). 1017 * 1018 * However, when "high" codepoints are used (any codepoint that over 0x7F, in other words where the first bit is a 1) it's 1019 * a different matter and UTF-8 and the 1 byte encoding greatly will differ, as well as most 1 byte encodings relative to each 1020 * other. 1021 * 1022 * It is impossible to detect which one-byte encoding is used. Since UTF8 and practically all 1-byte encodings share the most 1023 * used characters (the "none-high" ones) parsing them will give the same result. However, not all byte sequences are legal in 1024 * UTF-8 (see explantion above). If not UTF-8 encoded content is detected we therefor fallback on latin1. We also log a warning. 1025 * 1026 * By this method we detect all use of 1 byte encoding if they: 1027 * - use a "high" codepoint after a "low" codepoint or a sequence of codepoints that is valid as UTF-8 bytes, that starts with 1000 1028 * - use a "low" codepoint after a "high" codepoint 1029 * - use a "low" codepoint after "high" codepoint, after a "high" codepoint that starts with 1110 1030 * 1031 * In practise this means that unless 2 or 3 "high" codepoints are used after each other in proper order, we'll detect the string 1032 * was not originally UTF-8 encoded. 1033 * 1034 */ 1035 byte[] bytes = new byte[length]; 1036 int utf8State = UTF8_START; 1037 int b; 1038 for (int x = 0; x < length; x++) { 1039 bytes[x] = content[index++]; 1040 b = (int) bytes[x] & 0xFF; // unsign our byte 1041 1042 switch (utf8State) { 1043 case UTF8_START: 1044 if (b < 0x80) { 1045 // good 1046 } 1047 else if ((b & 0xC0) == 0xC0) { 1048 utf8State = UTF8_2BYTE; 1049 } 1050 else if ((b & 0xE0) == 0xE0) { 1051 utf8State = UTF8_3BYTE_1; 1052 } 1053 else { 1054 utf8State = UTF8_ILLEGAL; 1055 } 1056 break; 1057 case UTF8_3BYTE_1: 1058 case UTF8_3BYTE_2: 1059 case UTF8_2BYTE: 1060 if ((b & 0x80) == 0x80) 1061 utf8State = utf8State == UTF8_3BYTE_1 ? UTF8_3BYTE_2 : UTF8_START; 1062 else 1063 utf8State = UTF8_ILLEGAL; 1064 break; 1065 } 1066 } 1067 1068 try { 1069 // even though so far the parsing might have been a legal UTF-8 sequence, only if a codepoint is fully given is it correct UTF-8 1070 if (utf8State == UTF8_START) { 1071 // Java misspells UTF-8 as UTF8 for official use in java.lang 1072 return new String(bytes, "UTF8"); 1073 } 1074 else { 1075 logger.log( 1076 Level.WARNING, 1077 "Your export has been saved with an incorrect encoding for it's String fields which means it might not load correctly " + 1078 "due to encoding issues. You should probably re-export your work. See ISSUE 276 in the jME issue tracker." 1079 ); 1080 // We use ISO8859_1 to be consistent across platforms. We could default to native encoding, but this would lead to inconsistent 1081 // behaviour across platforms! 1082 // Developers that have previously saved their exports using the old exporter (wich uses native encoding), can temporarly 1083 // remove the ""ISO8859_1" parameter, and change the above if statement to "if (false)". 1084 // They should then import and re-export their models using the same enviroment they were orginally created in. 1085 return new String(bytes, "ISO8859_1"); 1086 } 1087 } catch (UnsupportedEncodingException uee) { 1088 // as a last resort fall back to platform native. 1089 // JavaDoc is vague about what happens when a decoding a String that contains un undecodable sequence 1090 // it also doesn't specify which encodings have to be supported (though UTF-8 and ISO8859 have been in the SUN JRE since at least 1.1) 1091 logger.log( 1092 Level.SEVERE, 1093 "Your export has been saved with an incorrect encoding or your version of Java is unable to decode the stored string. " + 1094 "While your export may load correctly by falling back, using it on different platforms or java versions might lead to "+ 1095 "very strange inconsitenties. You should probably re-export your work. See ISSUE 276 in the jME issue tracker." 1096 ); 1097 return new String(bytes); 1098 } 1099 } 1100 readStringArray(byte[] content)1101 protected String[] readStringArray(byte[] content) throws IOException { 1102 int length = readInt(content); 1103 if (length == BinaryOutputCapsule.NULL_OBJECT) 1104 return null; 1105 String[] value = new String[length]; 1106 for (int x = 0; x < length; x++) 1107 value[x] = readString(content); 1108 return value; 1109 } 1110 readStringArray2D(byte[] content)1111 protected String[][] readStringArray2D(byte[] content) throws IOException { 1112 int length = readInt(content); 1113 if (length == BinaryOutputCapsule.NULL_OBJECT) 1114 return null; 1115 String[][] value = new String[length][]; 1116 for (int x = 0; x < length; x++) 1117 value[x] = readStringArray(content); 1118 return value; 1119 } 1120 1121 // BitSet 1122 readBitSet(byte[] content)1123 protected BitSet readBitSet(byte[] content) throws IOException { 1124 int length = readInt(content); 1125 if (length == BinaryOutputCapsule.NULL_OBJECT) 1126 return null; 1127 BitSet value = new BitSet(length); 1128 for (int x = 0; x < length; x++) 1129 value.set(x, readBoolean(content)); 1130 return value; 1131 } 1132 1133 // INFLATOR for int and long 1134 inflateFrom(byte[] contents, int index)1135 protected static byte[] inflateFrom(byte[] contents, int index) { 1136 byte firstByte = contents[index]; 1137 if (firstByte == BinaryOutputCapsule.NULL_OBJECT) 1138 return ByteUtils.convertToBytes(BinaryOutputCapsule.NULL_OBJECT); 1139 else if (firstByte == BinaryOutputCapsule.DEFAULT_OBJECT) 1140 return ByteUtils.convertToBytes(BinaryOutputCapsule.DEFAULT_OBJECT); 1141 else if (firstByte == 0) 1142 return new byte[0]; 1143 else { 1144 byte[] rVal = new byte[firstByte]; 1145 for (int x = 0; x < rVal.length; x++) 1146 rVal[x] = contents[x + 1 + index]; 1147 return rVal; 1148 } 1149 } 1150 1151 // BinarySavable 1152 readSavable(byte[] content)1153 protected ID readSavable(byte[] content) throws IOException { 1154 int id = readInt(content); 1155 if (id == BinaryOutputCapsule.NULL_OBJECT) { 1156 return null; 1157 } 1158 1159 return new ID(id); 1160 } 1161 1162 // BinarySavable array 1163 readSavableArray(byte[] content)1164 protected ID[] readSavableArray(byte[] content) throws IOException { 1165 int elements = readInt(content); 1166 if (elements == BinaryOutputCapsule.NULL_OBJECT) 1167 return null; 1168 ID[] rVal = new ID[elements]; 1169 for (int x = 0; x < elements; x++) { 1170 rVal[x] = readSavable(content); 1171 } 1172 return rVal; 1173 } 1174 readSavableArray2D(byte[] content)1175 protected ID[][] readSavableArray2D(byte[] content) throws IOException { 1176 int elements = readInt(content); 1177 if (elements == BinaryOutputCapsule.NULL_OBJECT) 1178 return null; 1179 ID[][] rVal = new ID[elements][]; 1180 for (int x = 0; x < elements; x++) { 1181 rVal[x] = readSavableArray(content); 1182 } 1183 return rVal; 1184 } 1185 readSavableArray3D(byte[] content)1186 protected ID[][][] readSavableArray3D(byte[] content) throws IOException { 1187 int elements = readInt(content); 1188 if (elements == BinaryOutputCapsule.NULL_OBJECT) 1189 return null; 1190 ID[][][] rVal = new ID[elements][][]; 1191 for (int x = 0; x < elements; x++) { 1192 rVal[x] = readSavableArray2D(content); 1193 } 1194 return rVal; 1195 } 1196 1197 // BinarySavable map 1198 readSavableMap(byte[] content)1199 protected ID[][] readSavableMap(byte[] content) throws IOException { 1200 int elements = readInt(content); 1201 if (elements == BinaryOutputCapsule.NULL_OBJECT) 1202 return null; 1203 ID[][] rVal = new ID[elements][]; 1204 for (int x = 0; x < elements; x++) { 1205 rVal[x] = readSavableArray(content); 1206 } 1207 return rVal; 1208 } 1209 readStringSavableMap(byte[] content)1210 protected StringIDMap readStringSavableMap(byte[] content) throws IOException { 1211 int elements = readInt(content); 1212 if (elements == BinaryOutputCapsule.NULL_OBJECT) 1213 return null; 1214 String[] keys = readStringArray(content); 1215 ID[] values = readSavableArray(content); 1216 StringIDMap rVal = new StringIDMap(); 1217 rVal.keys = keys; 1218 rVal.values = values; 1219 return rVal; 1220 } 1221 readIntSavableMap(byte[] content)1222 protected IntIDMap readIntSavableMap(byte[] content) throws IOException { 1223 int elements = readInt(content); 1224 if (elements == BinaryOutputCapsule.NULL_OBJECT) 1225 return null; 1226 int[] keys = readIntArray(content); 1227 ID[] values = readSavableArray(content); 1228 IntIDMap rVal = new IntIDMap(); 1229 rVal.keys = keys; 1230 rVal.values = values; 1231 return rVal; 1232 } 1233 1234 1235 // ArrayList<FloatBuffer> 1236 readFloatBufferArrayList(byte[] content)1237 protected ArrayList<FloatBuffer> readFloatBufferArrayList(byte[] content) 1238 throws IOException { 1239 int length = readInt(content); 1240 if (length == BinaryOutputCapsule.NULL_OBJECT) { 1241 return null; 1242 } 1243 ArrayList<FloatBuffer> rVal = new ArrayList<FloatBuffer>(length); 1244 for (int x = 0; x < length; x++) { 1245 rVal.add(readFloatBuffer(content)); 1246 } 1247 return rVal; 1248 } 1249 1250 // ArrayList<ByteBuffer> 1251 readByteBufferArrayList(byte[] content)1252 protected ArrayList<ByteBuffer> readByteBufferArrayList(byte[] content) 1253 throws IOException { 1254 int length = readInt(content); 1255 if (length == BinaryOutputCapsule.NULL_OBJECT) { 1256 return null; 1257 } 1258 ArrayList<ByteBuffer> rVal = new ArrayList<ByteBuffer>(length); 1259 for (int x = 0; x < length; x++) { 1260 rVal.add(readByteBuffer(content)); 1261 } 1262 return rVal; 1263 } 1264 1265 // NIO BUFFERS 1266 // float buffer 1267 readFloatBuffer(byte[] content)1268 protected FloatBuffer readFloatBuffer(byte[] content) throws IOException { 1269 int length = readInt(content); 1270 if (length == BinaryOutputCapsule.NULL_OBJECT) 1271 return null; 1272 1273 if (BinaryImporter.canUseFastBuffers()){ 1274 ByteBuffer value = BufferUtils.createByteBuffer(length * 4); 1275 value.put(content, index, length * 4).rewind(); 1276 index += length * 4; 1277 return value.asFloatBuffer(); 1278 }else{ 1279 FloatBuffer value = BufferUtils.createFloatBuffer(length); 1280 for (int x = 0; x < length; x++) { 1281 value.put(readFloatForBuffer(content)); 1282 } 1283 value.rewind(); 1284 return value; 1285 } 1286 } 1287 1288 // int buffer 1289 readIntBuffer(byte[] content)1290 protected IntBuffer readIntBuffer(byte[] content) throws IOException { 1291 int length = readInt(content); 1292 if (length == BinaryOutputCapsule.NULL_OBJECT) 1293 return null; 1294 1295 if (BinaryImporter.canUseFastBuffers()){ 1296 ByteBuffer value = BufferUtils.createByteBuffer(length * 4); 1297 value.put(content, index, length * 4).rewind(); 1298 index += length * 4; 1299 return value.asIntBuffer(); 1300 }else{ 1301 IntBuffer value = BufferUtils.createIntBuffer(length); 1302 for (int x = 0; x < length; x++) { 1303 value.put(readIntForBuffer(content)); 1304 } 1305 value.rewind(); 1306 return value; 1307 } 1308 } 1309 1310 // byte buffer 1311 readByteBuffer(byte[] content)1312 protected ByteBuffer readByteBuffer(byte[] content) throws IOException { 1313 int length = readInt(content); 1314 if (length == BinaryOutputCapsule.NULL_OBJECT) 1315 return null; 1316 1317 if (BinaryImporter.canUseFastBuffers()){ 1318 ByteBuffer value = BufferUtils.createByteBuffer(length); 1319 value.put(content, index, length).rewind(); 1320 index += length; 1321 return value; 1322 }else{ 1323 ByteBuffer value = BufferUtils.createByteBuffer(length); 1324 for (int x = 0; x < length; x++) { 1325 value.put(readByteForBuffer(content)); 1326 } 1327 value.rewind(); 1328 return value; 1329 } 1330 } 1331 1332 // short buffer 1333 readShortBuffer(byte[] content)1334 protected ShortBuffer readShortBuffer(byte[] content) throws IOException { 1335 int length = readInt(content); 1336 if (length == BinaryOutputCapsule.NULL_OBJECT) 1337 return null; 1338 1339 if (BinaryImporter.canUseFastBuffers()){ 1340 ByteBuffer value = BufferUtils.createByteBuffer(length * 2); 1341 value.put(content, index, length * 2).rewind(); 1342 index += length * 2; 1343 return value.asShortBuffer(); 1344 }else{ 1345 ShortBuffer value = BufferUtils.createShortBuffer(length); 1346 for (int x = 0; x < length; x++) { 1347 value.put(readShortForBuffer(content)); 1348 } 1349 value.rewind(); 1350 return value; 1351 } 1352 } 1353 1354 static private class ID { 1355 public int id; 1356 ID(int id)1357 public ID(int id) { 1358 this.id = id; 1359 } 1360 } 1361 1362 static private class StringIDMap { 1363 public String[] keys; 1364 public ID[] values; 1365 } 1366 1367 static private class IntIDMap { 1368 public int[] keys; 1369 public ID[] values; 1370 } 1371 readEnum(String name, Class<T> enumType, T defVal)1372 public <T extends Enum<T>> T readEnum(String name, Class<T> enumType, T defVal) throws IOException { 1373 String eVal = readString(name, defVal != null ? defVal.name() : null); 1374 if (eVal != null) { 1375 return Enum.valueOf(enumType, eVal); 1376 } else { 1377 return null; 1378 } 1379 } 1380 }