Package com.ardor3d.util.export.binary

Source Code of com.ardor3d.util.export.binary.BinaryImporter

/**
* 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.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;

import com.ardor3d.annotation.SavableFactory;
import com.ardor3d.math.MathUtils;
import com.ardor3d.util.Ardor3dException;
import com.ardor3d.util.export.Ardor3dImporter;
import com.ardor3d.util.export.ByteUtils;
import com.ardor3d.util.export.ReadListener;
import com.ardor3d.util.export.Savable;
import com.google.common.collect.Maps;

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

    // Key - alias, object - bco
    protected final Map<String, BinaryClassObject> _classes = Maps.newHashMap();
    // Key - id, object - the savable
    protected final Map<Integer, Savable> _contentTable = Maps.newHashMap();
    // Key - savable, object - capsule
    protected final Map<Savable, BinaryInputCapsule> _capsuleTable = Maps.newIdentityHashMap();
    // Key - id, opject - location in the file
    protected final Map<Integer, Integer> _locationTable = Maps.newHashMap();

    protected byte[] _dataArray = null;
    protected int _aliasWidth = 0;

    public BinaryImporter() {}

    public Savable load(final InputStream is) throws IOException {
        return load(is, null, null);
    }

    public Savable load(final InputStream is, final ReadListener listener) throws IOException {
        return load(is, listener, null);
    }

    public Savable load(final InputStream is, final ReadListener listener, final ByteArrayOutputStream reuseableStream)
            throws IOException {
        try {
            final GZIPInputStream zis = new GZIPInputStream(is);
            BufferedInputStream bis = new BufferedInputStream(zis);
            final int numClasses = ByteUtils.readInt(bis);
            int bytes = 4;
            _aliasWidth = ((int) MathUtils.log(numClasses, 256) + 1);
            for (int i = 0; i < numClasses; i++) {
                final String alias = readString(bis, _aliasWidth);

                final int classLength = ByteUtils.readInt(bis);
                final String className = readString(bis, classLength);
                final BinaryClassObject bco = new BinaryClassObject();
                bco._alias = alias.getBytes();
                bco._className = className;

                final int fields = ByteUtils.readInt(bis);
                bytes += (8 + _aliasWidth + classLength);

                bco._nameFields = new HashMap<String, BinaryClassField>(fields);
                bco._aliasFields = new HashMap<Byte, BinaryClassField>(fields);
                for (int x = 0; x < fields; x++) {
                    final byte fieldAlias = (byte) bis.read();
                    final byte fieldType = (byte) bis.read();

                    final int fieldNameLength = ByteUtils.readInt(bis);
                    final String fieldName = readString(bis, fieldNameLength);
                    final BinaryClassField bcf = new BinaryClassField(fieldName, fieldAlias, fieldType);
                    bco._nameFields.put(fieldName, bcf);
                    bco._aliasFields.put(fieldAlias, bcf);
                    bytes += (6 + fieldNameLength);
                }
                _classes.put(alias, bco);
            }
            if (listener != null) {
                listener.readBytes(bytes);
            }

            final int numLocs = ByteUtils.readInt(bis);
            bytes = 4;

            for (int i = 0; i < numLocs; i++) {
                final int id = ByteUtils.readInt(bis);
                final int loc = ByteUtils.readInt(bis);
                _locationTable.put(id, loc);
                bytes += 8;
            }

            @SuppressWarnings("unused")
            final int numbIDs = ByteUtils.readInt(bis); // XXX: NOT CURRENTLY USED
            final int id = ByteUtils.readInt(bis);
            bytes += 8;
            if (listener != null) {
                listener.readBytes(bytes);
            }

            ByteArrayOutputStream baos = reuseableStream;
            if (baos == null) {
                baos = new ByteArrayOutputStream(bytes);
            } else {
                baos.reset();
            }
            int size = -1;
            final byte[] cache = new byte[4096];
            while ((size = bis.read(cache)) != -1) {
                baos.write(cache, 0, size);
                if (listener != null) {
                    listener.readBytes(size);
                }
            }
            bis = null;

            _dataArray = baos.toByteArray();
            baos = null;

            final Savable rVal = readObject(id);

            if (logger.isLoggable(Level.FINE)) {
                logger.fine("Importer Stats: ");
                logger.fine("Tags: " + numClasses);
                logger.fine("Objects: " + numLocs);
                logger.fine("Data Size: " + _dataArray.length);
            }
            return rVal;

        } finally {
            // Let go of / reset contents.
            _aliasWidth = 0;
            _contentTable.clear();
            _classes.clear();
            _capsuleTable.clear();
            _locationTable.clear();
            _dataArray = null;
        }
    }

    public Savable load(final URL url) throws IOException {
        return load(url, null);
    }

    public Savable load(final URL url, final ReadListener listener) throws IOException {
        final InputStream is = url.openStream();
        final Savable rVal = load(is, listener);
        is.close();
        return rVal;
    }

    public Savable load(final File file) throws IOException {
        return load(file, null);
    }

    public Savable load(final File file, final ReadListener listener) throws IOException {
        final FileInputStream fis = new FileInputStream(file);
        final Savable rVal = load(fis, listener);
        fis.close();
        return rVal;
    }

    public Savable load(final byte[] data) throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(data);
        final Savable rVal = load(bais);
        bais.close();
        return rVal;
    }

    protected String readString(final InputStream is, final int length) throws IOException {
        final byte[] data = new byte[length];
        is.read(data, 0, length);
        return new String(data);
    }

    protected String readString(final int length, final int offset) throws IOException {
        final byte[] data = new byte[length];
        for (int j = 0; j < length; j++) {
            data[j] = _dataArray[j + offset];
        }

        return new String(data);
    }

    public Savable readObject(final int id) {

        if (_contentTable.get(id) != null) {
            return _contentTable.get(id);
        }

        try {
            int loc = _locationTable.get(id);

            final String alias = readString(_aliasWidth, loc);
            loc += _aliasWidth;

            final BinaryClassObject bco = _classes.get(alias);

            if (bco == null) {
                logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int id)", "NULL class object: "
                        + alias);
                return null;
            }

            final int dataLength = ByteUtils.convertIntFromBytes(_dataArray, loc);
            loc += 4;

            final BinaryInputCapsule cap = new BinaryInputCapsule(this, bco);
            cap.setContent(_dataArray, loc, loc + dataLength);

            final Savable out;

            try {
                @SuppressWarnings("unchecked")
                final Class<? extends Savable> clazz = (Class<? extends Savable>) Class.forName(bco._className);
                final SavableFactory ann = clazz.getAnnotation(SavableFactory.class);
                if (ann == null) {
                    out = clazz.newInstance();
                } else {
                    out = (Savable) clazz.getMethod(ann.factoryMethod(), (Class<?>[]) null).invoke(null,
                            (Object[]) null);
                }
            } catch (final InstantiationException e) {
                logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int)",
                        "Could not access constructor of class '" + bco._className + "'! \n"
                                + "Some types may require the annotation SavableFactory.  Please double check.", e);
                throw new Ardor3dException(e);
            } catch (final NoSuchMethodException e) {
                logger
                        .logp(
                                Level.SEVERE,
                                this.getClass().toString(),
                                "readObject(int)",
                                e.getMessage()
                                        + " \n"
                                        + "Method specified in annotation does not appear to exist or has an invalid method signature.",
                                e);
                throw new Ardor3dException(e);
            }

            _capsuleTable.put(out, cap);
            _contentTable.put(id, out);

            out.read(_capsuleTable.get(out));

            _capsuleTable.remove(out);

            return out;

        } catch (final Ardor3dException e) {
            // rethrow our own exceptions
            throw e;
        } catch (final Exception e) {
            logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int)", "Exception", e);
            throw new Ardor3dException(e);
        }
    }
}
TOP

Related Classes of com.ardor3d.util.export.binary.BinaryImporter

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.