/* * Copyright (c) 2009-2012 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'jMonkeyEngine' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jme3.scene.plugins.blender.file; import com.jme3.scene.plugins.blender.BlenderContext; import java.util.HashMap; import java.util.Map; /** * The data block containing the description of the file. * @author Marcin Roguski (Kaelthas) */ public class DnaBlockData { private static final int SDNA_ID = 'S' << 24 | 'D' << 16 | 'N' << 8 | 'A'; // SDNA private static final int NAME_ID = 'N' << 24 | 'A' << 16 | 'M' << 8 | 'E'; // NAME private static final int TYPE_ID = 'T' << 24 | 'Y' << 16 | 'P' << 8 | 'E'; // TYPE private static final int TLEN_ID = 'T' << 24 | 'L' << 16 | 'E' << 8 | 'N'; // TLEN private static final int STRC_ID = 'S' << 24 | 'T' << 16 | 'R' << 8 | 'C'; // STRC /** Structures available inside the file. */ private final Structure[] structures; /** A map that helps finding a structure by type. */ private final Map<String, Structure> structuresMap; /** * Constructor. Loads the block from the given stream during instance creation. * @param inputStream * the stream we read the block from * @param blenderContext * the blender context * @throws BlenderFileException * this exception is throw if the blend file is invalid or somehow corrupted */ public DnaBlockData(BlenderInputStream inputStream, BlenderContext blenderContext) throws BlenderFileException { int identifier; // reading 'SDNA' identifier identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte(); if (identifier != SDNA_ID) { throw new BlenderFileException("Invalid identifier! '" + this.toString(SDNA_ID) + "' expected and found: " + this.toString(identifier)); } // reading names identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte(); if (identifier != NAME_ID) { throw new BlenderFileException("Invalid identifier! '" + this.toString(NAME_ID) + "' expected and found: " + this.toString(identifier)); } int amount = inputStream.readInt(); if (amount <= 0) { throw new BlenderFileException("The names amount number should be positive!"); } String[] names = new String[amount]; for (int i = 0; i < amount; ++i) { names[i] = inputStream.readString(); } // reding types inputStream.alignPosition(4); identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte(); if (identifier != TYPE_ID) { throw new BlenderFileException("Invalid identifier! '" + this.toString(TYPE_ID) + "' expected and found: " + this.toString(identifier)); } amount = inputStream.readInt(); if (amount <= 0) { throw new BlenderFileException("The types amount number should be positive!"); } String[] types = new String[amount]; for (int i = 0; i < amount; ++i) { types[i] = inputStream.readString(); } // reading lengths inputStream.alignPosition(4); identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte(); if (identifier != TLEN_ID) { throw new BlenderFileException("Invalid identifier! '" + this.toString(TLEN_ID) + "' expected and found: " + this.toString(identifier)); } int[] lengths = new int[amount];// theamount is the same as int types for (int i = 0; i < amount; ++i) { lengths[i] = inputStream.readShort(); } // reading structures inputStream.alignPosition(4); identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte(); if (identifier != STRC_ID) { throw new BlenderFileException("Invalid identifier! '" + this.toString(STRC_ID) + "' expected and found: " + this.toString(identifier)); } amount = inputStream.readInt(); if (amount <= 0) { throw new BlenderFileException("The structures amount number should be positive!"); } structures = new Structure[amount]; structuresMap = new HashMap<String, Structure>(amount); for (int i = 0; i < amount; ++i) { structures[i] = new Structure(inputStream, names, types, blenderContext); if (structuresMap.containsKey(structures[i].getType())) { throw new BlenderFileException("Blend file seems to be corrupted! The type " + structures[i].getType() + " is defined twice!"); } structuresMap.put(structures[i].getType(), structures[i]); } } /** * This method returns the amount of the structures. * @return the amount of the structures */ public int getStructuresCount() { return structures.length; } /** * This method returns the structure of the given index. * @param index * the index of the structure * @return the structure of the given index */ public Structure getStructure(int index) { try { return (Structure) structures[index].clone(); } catch (CloneNotSupportedException e) { throw new IllegalStateException("Structure should be clonable!!!", e); } } /** * This method returns a structure of the given name. If the name does not exists then null is returned. * @param name * the name of the structure * @return the required structure or null if the given name is inapropriate */ public Structure getStructure(String name) { try { return (Structure) structuresMap.get(name).clone(); } catch (CloneNotSupportedException e) { throw new IllegalStateException(e.getMessage(), e); } } /** * This method indicates if the structure of the given name exists. * @param name * the name of the structure * @return true if the structure exists and false otherwise */ public boolean hasStructure(String name) { return structuresMap.containsKey(name); } /** * This method converts the given identifier code to string. * @param code * the code taht is to be converted * @return the string value of the identifier */ private String toString(int code) { char c1 = (char) ((code & 0xFF000000) >> 24); char c2 = (char) ((code & 0xFF0000) >> 16); char c3 = (char) ((code & 0xFF00) >> 8); char c4 = (char) (code & 0xFF); return String.valueOf(c1) + c2 + c3 + c4; } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder("=============== ").append(SDNA_ID).append('\n'); for (Structure structure : structures) { stringBuilder.append(structure.toString()).append('\n'); } return stringBuilder.append("===============").toString(); } }