Package com.ardor3d.util.export.binary

Source Code of com.ardor3d.util.export.binary.BinaryInputCapsule$ID

/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.util.export.binary;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.ardor3d.util.export.ByteUtils;
import com.ardor3d.util.export.InputCapsule;
import com.ardor3d.util.export.Savable;
import com.ardor3d.util.geom.BufferUtils;

public class BinaryInputCapsule implements InputCapsule {
    private static final Logger logger = Logger.getLogger(BinaryInputCapsule.class.getName());

    protected BinaryImporter _importer;
    protected BinaryClassObject _cObj;
    protected HashMap<Byte, Object> _fieldData;

    protected int _index = 0;

    public BinaryInputCapsule(final BinaryImporter importer, final BinaryClassObject bco) {
        _importer = importer;
        _cObj = bco;
    }

    public void setContent(final byte[] content, final int start, final int limit) {
        _fieldData = new HashMap<Byte, Object>();
        for (_index = start; _index < limit;) {
            final byte alias = content[_index];

            _index++;

            try {
                final byte type = _cObj._aliasFields.get(alias)._type;
                Object value = null;

                switch (type) {
                    case BinaryClassField.BITSET: {
                        value = readBitSet(content);
                        break;
                    }
                    case BinaryClassField.BOOLEAN: {
                        value = readBoolean(content);
                        break;
                    }
                    case BinaryClassField.BOOLEAN_1D: {
                        value = readBooleanArray(content);
                        break;
                    }
                    case BinaryClassField.BOOLEAN_2D: {
                        value = readBooleanArray2D(content);
                        break;
                    }
                    case BinaryClassField.BYTE: {
                        value = readByte(content);
                        break;
                    }
                    case BinaryClassField.BYTE_1D: {
                        value = readByteArray(content);
                        break;
                    }
                    case BinaryClassField.BYTE_2D: {
                        value = readByteArray2D(content);
                        break;
                    }
                    case BinaryClassField.BYTEBUFFER: {
                        value = readByteBuffer(content);
                        break;
                    }
                    case BinaryClassField.DOUBLE: {
                        value = readDouble(content);
                        break;
                    }
                    case BinaryClassField.DOUBLE_1D: {
                        value = readDoubleArray(content);
                        break;
                    }
                    case BinaryClassField.DOUBLE_2D: {
                        value = readDoubleArray2D(content);
                        break;
                    }
                    case BinaryClassField.FLOAT: {
                        value = readFloat(content);
                        break;
                    }
                    case BinaryClassField.FLOAT_1D: {
                        value = readFloatArray(content);
                        break;
                    }
                    case BinaryClassField.FLOAT_2D: {
                        value = readFloatArray2D(content);
                        break;
                    }
                    case BinaryClassField.FLOATBUFFER: {
                        value = readFloatBuffer(content);
                        break;
                    }
                    case BinaryClassField.FLOATBUFFER_ARRAYLIST: {
                        value = readFloatBufferArrayList(content);
                        break;
                    }
                    case BinaryClassField.BYTEBUFFER_ARRAYLIST: {
                        value = readByteBufferArrayList(content);
                        break;
                    }
                    case BinaryClassField.INT: {
                        value = readInt(content);
                        break;
                    }
                    case BinaryClassField.INT_1D: {
                        value = readIntArray(content);
                        break;
                    }
                    case BinaryClassField.INT_2D: {
                        value = readIntArray2D(content);
                        break;
                    }
                    case BinaryClassField.INTBUFFER: {
                        value = readIntBuffer(content);
                        break;
                    }
                    case BinaryClassField.LONG: {
                        value = readLong(content);
                        break;
                    }
                    case BinaryClassField.LONG_1D: {
                        value = readLongArray(content);
                        break;
                    }
                    case BinaryClassField.LONG_2D: {
                        value = readLongArray2D(content);
                        break;
                    }
                    case BinaryClassField.SAVABLE: {
                        value = readSavable(content);
                        break;
                    }
                    case BinaryClassField.SAVABLE_1D: {
                        value = readSavableArray(content);
                        break;
                    }
                    case BinaryClassField.SAVABLE_2D: {
                        value = readSavableArray2D(content);
                        break;
                    }
                    case BinaryClassField.SAVABLE_ARRAYLIST: {
                        value = readSavableArray(content);
                        break;
                    }
                    case BinaryClassField.SAVABLE_ARRAYLIST_1D: {
                        value = readSavableArray2D(content);
                        break;
                    }
                    case BinaryClassField.SAVABLE_ARRAYLIST_2D: {
                        value = readSavableArray3D(content);
                        break;
                    }
                    case BinaryClassField.SAVABLE_MAP: {
                        value = readSavableMap(content);
                        break;
                    }
                    case BinaryClassField.STRING_SAVABLE_MAP: {
                        value = readStringSavableMap(content);
                        break;
                    }
                    case BinaryClassField.SHORT: {
                        value = readShort(content);
                        break;
                    }
                    case BinaryClassField.SHORT_1D: {
                        value = readShortArray(content);
                        break;
                    }
                    case BinaryClassField.SHORT_2D: {
                        value = readShortArray2D(content);
                        break;
                    }
                    case BinaryClassField.SHORTBUFFER: {
                        value = readShortBuffer(content);
                        break;
                    }
                    case BinaryClassField.STRING: {
                        value = readString(content);
                        break;
                    }
                    case BinaryClassField.STRING_1D: {
                        value = readStringArray(content);
                        break;
                    }
                    case BinaryClassField.STRING_2D: {
                        value = readStringArray2D(content);
                        break;
                    }

                    default:
                        // skip put statement
                        continue;
                }

                _fieldData.put(alias, value);

            } catch (final IOException e) {
                logger.logp(Level.SEVERE, this.getClass().toString(), "setContent(byte[] content)", "Exception", e);
            }
        }
    }

    public BitSet readBitSet(final String name, final BitSet defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (BitSet) _fieldData.get(field._alias);
    }

    public boolean readBoolean(final String name, final boolean defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return ((Boolean) _fieldData.get(field._alias)).booleanValue();
    }

    public boolean[] readBooleanArray(final String name, final boolean[] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (boolean[]) _fieldData.get(field._alias);
    }

    public boolean[][] readBooleanArray2D(final String name, final boolean[][] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (boolean[][]) _fieldData.get(field._alias);
    }

    public byte readByte(final String name, final byte defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return ((Byte) _fieldData.get(field._alias)).byteValue();
    }

    public byte[] readByteArray(final String name, final byte[] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (byte[]) _fieldData.get(field._alias);
    }

    public byte[][] readByteArray2D(final String name, final byte[][] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (byte[][]) _fieldData.get(field._alias);
    }

    public ByteBuffer readByteBuffer(final String name, final ByteBuffer defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (ByteBuffer) _fieldData.get(field._alias);
    }

    @SuppressWarnings("unchecked")
    public List<ByteBuffer> readByteBufferList(final String name, final List<ByteBuffer> defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (List<ByteBuffer>) _fieldData.get(field._alias);
    }

    public double readDouble(final String name, final double defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return ((Double) _fieldData.get(field._alias)).doubleValue();
    }

    public double[] readDoubleArray(final String name, final double[] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (double[]) _fieldData.get(field._alias);
    }

    public double[][] readDoubleArray2D(final String name, final double[][] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (double[][]) _fieldData.get(field._alias);
    }

    public float readFloat(final String name, final float defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return ((Float) _fieldData.get(field._alias)).floatValue();
    }

    public float[] readFloatArray(final String name, final float[] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (float[]) _fieldData.get(field._alias);
    }

    public float[][] readFloatArray2D(final String name, final float[][] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (float[][]) _fieldData.get(field._alias);
    }

    public FloatBuffer readFloatBuffer(final String name, final FloatBuffer defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (FloatBuffer) _fieldData.get(field._alias);
    }

    @SuppressWarnings("unchecked")
    public List<FloatBuffer> readFloatBufferList(final String name, final List<FloatBuffer> defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (List<FloatBuffer>) _fieldData.get(field._alias);
    }

    public int readInt(final String name, final int defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return ((Integer) _fieldData.get(field._alias)).intValue();
    }

    public int[] readIntArray(final String name, final int[] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (int[]) _fieldData.get(field._alias);
    }

    public int[][] readIntArray2D(final String name, final int[][] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (int[][]) _fieldData.get(field._alias);
    }

    public IntBuffer readIntBuffer(final String name, final IntBuffer defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (IntBuffer) _fieldData.get(field._alias);
    }

    public long readLong(final String name, final long defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return ((Long) _fieldData.get(field._alias)).longValue();
    }

    public long[] readLongArray(final String name, final long[] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (long[]) _fieldData.get(field._alias);
    }

    public long[][] readLongArray2D(final String name, final long[][] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (long[][]) _fieldData.get(field._alias);
    }

    public Savable readSavable(final String name, final Savable defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        Object value = _fieldData.get(field._alias);
        if (value == null) {
            return null;
        } else if (value instanceof ID) {
            value = _importer.readObject(((ID) value).id);
            _fieldData.put(field._alias, value);
            return (Savable) value;
        } else {
            return defVal;
        }
    }

    public Savable[] readSavableArray(final String name, final Savable[] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        Object[] values = (Object[]) _fieldData.get(field._alias);
        if (values instanceof ID[]) {
            values = resolveIDs(values);
            _fieldData.put(field._alias, values);
            return (Savable[]) values;
        } else {
            return defVal;
        }
    }

    private Savable[] resolveIDs(final Object[] values) {
        if (values != null) {
            final Savable[] savables = new Savable[values.length];
            for (int i = 0; i < values.length; i++) {
                final ID id = (ID) values[i];
                savables[i] = id != null ? _importer.readObject(id.id) : null;
            }
            return savables;
        } else {
            return null;
        }
    }

    public Savable[][] readSavableArray2D(final String name, final Savable[][] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        Object[][] values = (Object[][]) _fieldData.get(field._alias);
        if (values instanceof ID[][]) {
            final Savable[][] savables = new Savable[values.length][];
            for (int i = 0; i < values.length; i++) {
                if (values[i] != null) {
                    savables[i] = resolveIDs(values[i]);
                } else {
                    savables[i] = null;
                }
            }
            values = savables;
            _fieldData.put(field._alias, values);
        }
        return (Savable[][]) values;
    }

    public Savable[][][] readSavableArray3D(final String name, final Savable[][][] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        final Object[][][] values = (Object[][][]) _fieldData.get(field._alias);
        if (values instanceof ID[][][]) {
            final Savable[][][] savables = new Savable[values.length][][];
            for (int i = 0; i < values.length; i++) {
                if (values[i] != null) {
                    savables[i] = new Savable[values[i].length][];
                    for (int j = 0; j < values[i].length; j++) {
                        savables[i][j] = resolveIDs(values[i][j]);
                    }
                } else {
                    savables[i] = null;
                }
            }
            _fieldData.put(field._alias, savables);
            return savables;
        } else {
            return defVal;
        }
    }

    private List<Savable> savableArrayListFromArray(final Savable[] savables) {
        if (savables == null) {
            return null;
        }
        final List<Savable> list = new ArrayList<Savable>(savables.length);
        for (int x = 0; x < savables.length; x++) {
            list.add(savables[x]);
        }
        return list;
    }

    // Assumes array of size 2 arrays where pos 0 is key and pos 1 is value.
    private Map<Savable, Savable> savableMapFrom2DArray(final Savable[][] savables) {
        if (savables == null) {
            return null;
        }
        final Map<Savable, Savable> map = new HashMap<Savable, Savable>(savables.length);
        for (int x = 0; x < savables.length; x++) {
            map.put(savables[x][0], savables[x][1]);
        }
        return map;
    }

    private Map<String, Savable> stringSavableMapFromKV(final String[] keys, final Savable[] values) {
        if (keys == null || values == null) {
            return null;
        }

        final Map<String, Savable> map = new HashMap<String, Savable>(keys.length);
        for (int x = 0; x < keys.length; x++) {
            map.put(keys[x], values[x]);
        }

        return map;
    }

    @SuppressWarnings("unchecked")
    public <E extends Savable> List<E> readSavableList(final String name, final List<E> defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        Object value = _fieldData.get(field._alias);
        if (value instanceof ID[]) {
            // read Savable array and convert to ArrayList
            final Savable[] savables = readSavableArray(name, null);
            value = savableArrayListFromArray(savables);
            _fieldData.put(field._alias, value);
        }
        return (List<E>) value;
    }

    @SuppressWarnings("unchecked")
    public <E extends Savable> List<E>[] readSavableListArray(final String name, final List<E>[] defVal)
            throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        Object value = _fieldData.get(field._alias);
        if (value instanceof ID[][]) {
            // read 2D Savable array and convert to ArrayList array
            final Savable[][] savables = readSavableArray2D(name, null);
            if (savables != null) {
                final List<Savable>[] arrayLists = new ArrayList[savables.length];
                for (int i = 0; i < savables.length; i++) {
                    arrayLists[i] = savableArrayListFromArray(savables[i]);
                }
                value = arrayLists;
            } else {
                value = defVal;
            }
            _fieldData.put(field._alias, value);
        }
        return (List<E>[]) value;
    }

    @SuppressWarnings("unchecked")
    public <E extends Savable> List<E>[][] readSavableListArray2D(final String name, final List<E>[][] defVal)
            throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        Object value = _fieldData.get(field._alias);
        if (value instanceof ID[][][]) {
            // read 3D Savable array and convert to 2D ArrayList array
            final Savable[][][] savables = readSavableArray3D(name, null);
            if (savables != null && savables.length > 0) {
                final List<Savable>[][] arrayLists = new ArrayList[savables.length][];
                for (int i = 0; i < savables.length; i++) {
                    arrayLists[i] = new ArrayList[savables[i].length];
                    for (int j = 0; j < savables[i].length; j++) {
                        arrayLists[i][j] = savableArrayListFromArray(savables[i][j]);
                    }
                }
                value = arrayLists;
            } else {
                value = defVal;
            }
            _fieldData.put(field._alias, value);
        }
        return (List<E>[][]) value;
    }

    @SuppressWarnings("unchecked")
    public <K extends Savable, V extends Savable> Map<K, V> readSavableMap(final String name, final Map<K, V> defVal)
            throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        Object value = _fieldData.get(field._alias);
        if (value instanceof ID[][]) {
            // read Savable array and convert to Map
            final Savable[][] savables = readSavableArray2D(name, null);
            value = savableMapFrom2DArray(savables);
            _fieldData.put(field._alias, value);
        }
        return (Map<K, V>) value;
    }

    @SuppressWarnings("unchecked")
    public <V extends Savable> Map<String, V> readStringSavableMap(final String name, final Map<String, V> defVal)
            throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        Object value = _fieldData.get(field._alias);
        if (value instanceof StringIDMap) {
            // read Savable array and convert to Map values
            final StringIDMap in = (StringIDMap) value;
            final Savable[] values = resolveIDs(in.values);
            value = stringSavableMapFromKV(in.keys, values);
            _fieldData.put(field._alias, value);
        }
        return (Map<String, V>) value;
    }

    public short readShort(final String name, final short defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return ((Short) _fieldData.get(field._alias)).shortValue();
    }

    public short[] readShortArray(final String name, final short[] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (short[]) _fieldData.get(field._alias);
    }

    public short[][] readShortArray2D(final String name, final short[][] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (short[][]) _fieldData.get(field._alias);
    }

    public ShortBuffer readShortBuffer(final String name, final ShortBuffer defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (ShortBuffer) _fieldData.get(field._alias);
    }

    public String readString(final String name, final String defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (String) _fieldData.get(field._alias);
    }

    public String[] readStringArray(final String name, final String[] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (String[]) _fieldData.get(field._alias);
    }

    public String[][] readStringArray2D(final String name, final String[][] defVal) throws IOException {
        final BinaryClassField field = _cObj._nameFields.get(name);
        if (field == null || !_fieldData.containsKey(field._alias)) {
            return defVal;
        }
        return (String[][]) _fieldData.get(field._alias);
    }

    // byte primitive

    protected byte readByte(final byte[] content) throws IOException {
        final byte value = content[_index];
        _index++;
        return value;
    }

    protected byte[] readByteArray(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final byte[] value = new byte[length];
        for (int x = 0; x < length; x++) {
            value[x] = readByte(content);
        }
        return value;
    }

    protected byte[][] readByteArray2D(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final byte[][] value = new byte[length][];
        for (int x = 0; x < length; x++) {
            value[x] = readByteArray(content);
        }
        return value;
    }

    // int primitive

    protected int readInt(final byte[] content) throws IOException {
        byte[] bytes = inflateFrom(content, _index);
        _index += 1 + bytes.length;
        bytes = ByteUtils.rightAlignBytes(bytes, 4);
        final int value = ByteUtils.convertIntFromBytes(bytes);
        if (value == BinaryOutputCapsule.NULL_OBJECT || value == BinaryOutputCapsule.DEFAULT_OBJECT) {
            _index -= 4;
        }
        return value;
    }

    protected int[] readIntArray(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final int[] value = new int[length];
        for (int x = 0; x < length; x++) {
            value[x] = readInt(content);
        }
        return value;
    }

    protected int[][] readIntArray2D(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final int[][] value = new int[length][];
        for (int x = 0; x < length; x++) {
            value[x] = readIntArray(content);
        }
        return value;
    }

    // float primitive

    protected float readFloat(final byte[] content) throws IOException {
        final float value = ByteUtils.convertFloatFromBytes(content, _index);
        _index += 4;
        return value;
    }

    protected float[] readFloatArray(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final float[] value = new float[length];
        for (int x = 0; x < length; x++) {
            value[x] = readFloat(content);
        }
        return value;
    }

    protected float[][] readFloatArray2D(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final float[][] value = new float[length][];
        for (int x = 0; x < length; x++) {
            value[x] = readFloatArray(content);
        }
        return value;
    }

    // double primitive

    protected double readDouble(final byte[] content) throws IOException {
        final double value = ByteUtils.convertDoubleFromBytes(content, _index);
        _index += 8;
        return value;
    }

    protected double[] readDoubleArray(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final double[] value = new double[length];
        for (int x = 0; x < length; x++) {
            value[x] = readDouble(content);
        }
        return value;
    }

    protected double[][] readDoubleArray2D(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final double[][] value = new double[length][];
        for (int x = 0; x < length; x++) {
            value[x] = readDoubleArray(content);
        }
        return value;
    }

    // long primitive

    protected long readLong(final byte[] content) throws IOException {
        byte[] bytes = inflateFrom(content, _index);
        _index += 1 + bytes.length;
        bytes = ByteUtils.rightAlignBytes(bytes, 8);
        final long value = ByteUtils.convertLongFromBytes(bytes);
        return value;
    }

    protected long[] readLongArray(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final long[] value = new long[length];
        for (int x = 0; x < length; x++) {
            value[x] = readLong(content);
        }
        return value;
    }

    protected long[][] readLongArray2D(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final long[][] value = new long[length][];
        for (int x = 0; x < length; x++) {
            value[x] = readLongArray(content);
        }
        return value;
    }

    // short primitive

    protected short readShort(final byte[] content) throws IOException {
        final short value = ByteUtils.convertShortFromBytes(content, _index);
        _index += 2;
        return value;
    }

    protected short[] readShortArray(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final short[] value = new short[length];
        for (int x = 0; x < length; x++) {
            value[x] = readShort(content);
        }
        return value;
    }

    protected short[][] readShortArray2D(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final short[][] value = new short[length][];
        for (int x = 0; x < length; x++) {
            value[x] = readShortArray(content);
        }
        return value;
    }

    // boolean primitive

    protected boolean readBoolean(final byte[] content) throws IOException {
        final boolean value = ByteUtils.convertBooleanFromBytes(content, _index);
        _index += 1;
        return value;
    }

    protected boolean[] readBooleanArray(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final boolean[] value = new boolean[length];
        for (int x = 0; x < length; x++) {
            value[x] = readBoolean(content);
        }
        return value;
    }

    protected boolean[][] readBooleanArray2D(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final boolean[][] value = new boolean[length][];
        for (int x = 0; x < length; x++) {
            value[x] = readBooleanArray(content);
        }
        return value;
    }

    /*
     * UTF-8 crash course:
     *
     * UTF-8 codepoints map to UTF-16 codepoints and vv, which is what Java uses for it's Strings. (so a UTF-8 codepoint
     * can contain all possible values for a Java char)
     *
     * A UTF-8 codepoint can be 1, 2 or 3 bytes long. How long a codepoint is can be told by reading the first byte: b <
     * 0x80, 1 byte (b & 0xC0) == 0xC0, 2 bytes (b & 0xE0) == 0xE0, 3 bytes
     *
     * However there is an additional restriction to UTF-8, to enable you to find the start of a UTF-8 codepoint, 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 a multibyte codepoint: (b & 0x80) == 0x80 (in other words, first bit must be 1)
     */
    private final static int UTF8_START = 0; // next byte should be the start of a new
    private final static int UTF8_2BYTE = 2; // next byte should be the second byte of a 2 byte codepoint
    private final static int UTF8_3BYTE_1 = 3; // next byte should be the second byte of a 3 byte codepoint
    private final static int UTF8_3BYTE_2 = 4; // next byte should be the third byte of a 3 byte codepoint
    private final static int UTF8_ILLEGAL = 10; // not an UTF8 string

    // String
    protected String readString(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }

        /*
         * We'll transfer the bytes into a separate byte array. While we do that we'll take the opportunity to check if
         * the byte data is valid UTF-8.
         *
         * If it is not UTF-8 it is most likely saved with the BinaryOutputCapsule bug, that saves Strings using their
         * native encoding. Unfortunatly there is no way to know what encoding was used, so we'll parse using the most
         * common one in that case; latin-1 aka ISO8859_1
         *
         * Encoding of "low" ASCII codepoint (in plain speak: when no special characters are used) will usually look the
         * same for UTF-8 and the other 1 byte codepoint encodings (espc true for numbers and regular letters of the
         * alphabet). So these are valid UTF-8 and will give the same result (at most a few charakters will appear
         * different, such as the euro sign).
         *
         * However, when "high" codepoints are used (any codepoint that over 0x7F, in other words where the first bit is
         * a 1) it's a different matter and UTF-8 and the 1 byte encoding greatly will differ, as well as most 1 byte
         * encodings relative to each other.
         *
         * It is impossible to detect which one-byte encoding is used. Since UTF8 and practically all 1-byte encodings
         * share the most used characters (the "none-high" ones) parsing them will give the same result. However, not
         * all byte sequences are legal in UTF-8 (see explantion above). If not UTF-8 encoded content is detected we
         * therefor fallback on latin1. We also log a warning.
         *
         * By this method we detect all use of 1 byte encoding if they: - use a "high" codepoint after a "low" codepoint
         * or a sequence of codepoints that is valid as UTF-8 bytes, that starts with 1000 - use a "low" codepoint after
         * a "high" codepoint - use a "low" codepoint after "high" codepoint, after a "high" codepoint that starts with
         * 1110
         *
         * In practice this means that unless 2 or 3 "high" codepoints are used after each other in proper order, we'll
         * detect the string was not originally UTF-8 encoded.
         */
        final byte[] bytes = new byte[length];
        int utf8State = UTF8_START;
        int b;
        for (int x = 0; x < length; x++) {
            bytes[x] = content[_index++];
            b = bytes[x] & 0xFF; // unsign our byte

            switch (utf8State) {
                case UTF8_START:
                    if (b < 0x80) {
                        // good
                    } else if ((b & 0xC0) == 0xC0) {
                        utf8State = UTF8_2BYTE;
                    } else if ((b & 0xE0) == 0xE0) {
                        utf8State = UTF8_3BYTE_1;
                    } else {
                        utf8State = UTF8_ILLEGAL;
                    }
                    break;
                case UTF8_3BYTE_1:
                case UTF8_3BYTE_2:
                case UTF8_2BYTE:
                    if ((b & 0x80) == 0x80) {
                        utf8State = utf8State == UTF8_3BYTE_1 ? UTF8_3BYTE_2 : UTF8_START;
                    } else {
                        utf8State = UTF8_ILLEGAL;
                    }
                    break;
            }
        }

        try {
            // 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
            if (utf8State == UTF8_START) {
                // Java misspells UTF-8 as UTF8 for official use in java.lang
                return new String(bytes, "UTF8");
            } else {
                logger.log(Level.WARNING,
                        "Your export has been saved with an incorrect encoding for it's String fields which means it might not load correctly "
                                + "due to encoding issues.");
                // We use ISO8859_1 to be consistent across platforms. We could default to native encoding, but this
                // would lead to inconsistent
                // behaviour across platforms!
                // Developers that have previously saved their exports using the old exporter (wich uses native
                // encoding), can temporarly
                // remove the ""ISO8859_1" parameter, and change the above if statement to "if (false)".
                // They should then import and re-export their models using the same enviroment they were orginally
                // created in.
                return new String(bytes, "ISO8859_1");
            }
        } catch (final UnsupportedEncodingException uee) {
            // as a last resort fall back to platform native.
            // JavaDoc is vague about what happens when a decoding a String that contains un undecodable sequence
            // 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)
            logger.log(
                    Level.SEVERE,
                    "Your export has been saved with an incorrect encoding or your version of Java is unable to decode the stored string. "
                            + "While your export may load correctly by falling back, using it on different platforms or java versions might lead to "
                            + "very strange inconsitenties. You should probably re-export your work.");
            return new String(bytes);
        }
    }

    protected String[] readStringArray(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final String[] value = new String[length];
        for (int x = 0; x < length; x++) {
            value[x] = readString(content);
        }
        return value;
    }

    protected String[][] readStringArray2D(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final String[][] value = new String[length][];
        for (int x = 0; x < length; x++) {
            value[x] = readStringArray(content);
        }
        return value;
    }

    // BitSet

    protected BitSet readBitSet(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final BitSet value = new BitSet(length);
        for (int x = 0; x < length; x++) {
            value.set(x, readBoolean(content));
        }
        return value;
    }

    // INFLATOR for int and long

    protected static byte[] inflateFrom(final byte[] contents, final int index) {
        final byte firstByte = contents[index];
        if (firstByte == BinaryOutputCapsule.NULL_OBJECT) {
            return ByteUtils.convertToBytes(BinaryOutputCapsule.NULL_OBJECT);
        } else if (firstByte == BinaryOutputCapsule.DEFAULT_OBJECT) {
            return ByteUtils.convertToBytes(BinaryOutputCapsule.DEFAULT_OBJECT);
        } else if (firstByte == 0) {
            return new byte[0];
        } else {
            final byte[] rVal = new byte[firstByte];
            for (int x = 0; x < rVal.length; x++) {
                rVal[x] = contents[x + 1 + index];
            }
            return rVal;
        }
    }

    // BinarySavable

    protected ID readSavable(final byte[] content) throws IOException {
        final int id = readInt(content);
        if (id == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }

        return new ID(id);
    }

    // BinarySavable array

    protected ID[] readSavableArray(final byte[] content) throws IOException {
        final int elements = readInt(content);
        if (elements == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final ID[] rVal = new ID[elements];
        for (int x = 0; x < elements; x++) {
            rVal[x] = readSavable(content);
        }
        return rVal;
    }

    protected ID[][] readSavableArray2D(final byte[] content) throws IOException {
        final int elements = readInt(content);
        if (elements == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final ID[][] rVal = new ID[elements][];
        for (int x = 0; x < elements; x++) {
            rVal[x] = readSavableArray(content);
        }
        return rVal;
    }

    protected ID[][][] readSavableArray3D(final byte[] content) throws IOException {
        final int elements = readInt(content);
        if (elements == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final ID[][][] rVal = new ID[elements][][];
        for (int x = 0; x < elements; x++) {
            rVal[x] = readSavableArray2D(content);
        }
        return rVal;
    }

    // BinarySavable map

    protected ID[][] readSavableMap(final byte[] content) throws IOException {
        final int elements = readInt(content);
        if (elements == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final ID[][] rVal = new ID[elements][];
        for (int x = 0; x < elements; x++) {
            rVal[x] = readSavableArray(content);
        }
        return rVal;
    }

    protected StringIDMap readStringSavableMap(final byte[] content) throws IOException {
        final int elements = readInt(content);
        if (elements == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final String[] keys = readStringArray(content);
        final ID[] values = readSavableArray(content);
        final StringIDMap rVal = new StringIDMap();
        rVal.keys = keys;
        rVal.values = values;
        return rVal;
    }

    // ArrayList<FloatBuffer>

    protected List<FloatBuffer> readFloatBufferArrayList(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final List<FloatBuffer> rVal = new ArrayList<FloatBuffer>(length);
        for (int x = 0; x < length; x++) {
            rVal.add(readFloatBuffer(content));
        }
        return rVal;
    }

    // ArrayList<ByteBuffer>

    protected List<ByteBuffer> readByteBufferArrayList(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }
        final List<ByteBuffer> rVal = new ArrayList<ByteBuffer>(length);
        for (int x = 0; x < length; x++) {
            rVal.add(readByteBuffer(content));
        }
        return rVal;
    }

    // NIO BUFFERS

    // float buffer
    protected FloatBuffer readFloatBuffer(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }

        final boolean direct = readBoolean(content);

        // Pull data in as a little endian byte buffer.
        final ByteBuffer buf = ByteBuffer.allocateDirect(length * 4).order(ByteOrder.LITTLE_ENDIAN);
        buf.put(content, _index, length * 4).rewind();

        // increment index
        _index += length * 4;

        // Convert to float buffer.
        final FloatBuffer value;
        final boolean contentCopyRequired;
        if (direct) {
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                value = buf.asFloatBuffer();
                contentCopyRequired = false;
            } else {
                value = BufferUtils.createFloatBuffer(length);
                contentCopyRequired = true;
            }
        } else {
            value = BufferUtils.createFloatBufferOnHeap(length);
            contentCopyRequired = true;
        }
        if (contentCopyRequired) {
            value.put(buf.asFloatBuffer());
            value.rewind();
        }

        return value;
    }

    // int buffer
    protected IntBuffer readIntBuffer(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }

        final boolean direct = readBoolean(content);

        // Pull data in as a little endian byte buffer.
        final ByteBuffer buf = ByteBuffer.allocateDirect(length * 4).order(ByteOrder.LITTLE_ENDIAN);
        buf.put(content, _index, length * 4).rewind();

        // increment index
        _index += length * 4;

        // Convert to int buffer.
        final IntBuffer value;
        final boolean contentCopyRequired;
        if (direct) {
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                value = buf.asIntBuffer();
                contentCopyRequired = false;
            } else {
                value = BufferUtils.createIntBuffer(length);
                contentCopyRequired = true;
            }
        } else {
            value = BufferUtils.createIntBufferOnHeap(length);
            contentCopyRequired = true;
        }
        if (contentCopyRequired) {
            value.put(buf.asIntBuffer());
            value.rewind();
        }
        return value;
    }

    // short buffer
    protected ShortBuffer readShortBuffer(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }

        final boolean direct = readBoolean(content);

        // Pull data in as a little endian byte buffer.
        final ByteBuffer buf = ByteBuffer.allocateDirect(length * 2).order(ByteOrder.LITTLE_ENDIAN);
        buf.put(content, _index, length * 2).rewind();

        // increment index
        _index += length * 2;

        // Convert to short buffer.
        final ShortBuffer value;
        final boolean contentCopyRequired;
        if (direct) {
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                value = buf.asShortBuffer();
                contentCopyRequired = false;
            } else {
                value = BufferUtils.createShortBuffer(length);
                contentCopyRequired = true;
            }
        } else {
            value = BufferUtils.createShortBufferOnHeap(length);
            contentCopyRequired = true;
        }
        if (contentCopyRequired) {
            value.put(buf.asShortBuffer());
            value.rewind();
        }
        return value;
    }

    // byte buffer
    protected ByteBuffer readByteBuffer(final byte[] content) throws IOException {
        final int length = readInt(content);
        if (length == BinaryOutputCapsule.NULL_OBJECT) {
            return null;
        }

        final boolean direct = readBoolean(content);

        // Pull data in as a little endian byte buffer.
        final ByteBuffer buf = ByteBuffer.allocateDirect(length).order(ByteOrder.LITTLE_ENDIAN);
        buf.put(content, _index, length).rewind();

        // increment index
        _index += length;

        // Convert to platform endian buffer.
        final ByteBuffer value;
        final boolean contentCopyRequired;
        if (direct) {
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                value = buf;
                contentCopyRequired = false;
            } else {
                value = BufferUtils.createByteBuffer(length);
                contentCopyRequired = true;
            }
        } else {
            value = BufferUtils.createByteBufferOnHeap(length);
            contentCopyRequired = true;
        }
        if (contentCopyRequired) {
            value.put(buf);
            value.rewind();
        }
        return value;
    }

    static private class ID {
        public int id;

        public ID(final int id) {
            this.id = id;
        }
    }

    static private class StringIDMap {
        public String[] keys;
        public ID[] values;
    }

    public <T extends Enum<T>> T readEnum(final String name, final Class<T> enumType, final T defVal)
            throws IOException {
        final String eVal = readString(name, defVal != null ? defVal.name() : null);
        if (eVal != null) {
            return Enum.valueOf(enumType, eVal);
        } else {
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    public <T extends Enum<T>> T[] readEnumArray(final String name, final Class<T> enumType, final T[] defVal)
            throws IOException {
        final String[] eVals = readStringArray(name, null);
        if (eVals != null) {
            final T[] rVal = (T[]) Array.newInstance(enumType, eVals.length);
            int i = 0;
            for (final String eVal : eVals) {
                rVal[i++] = Enum.valueOf(enumType, eVal);
            }
            return rVal;
        } else {
            return defVal;
        }
    }
}
TOP

Related Classes of com.ardor3d.util.export.binary.BinaryInputCapsule$ID

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.