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 package com.jme3.scene.plugins.blender.file; 33 34 import com.jme3.scene.plugins.blender.BlenderContext; 35 import com.jme3.scene.plugins.blender.exceptions.BlenderFileException; 36 import java.util.HashMap; 37 import java.util.Map; 38 39 /** 40 * The data block containing the description of the file. 41 * @author Marcin Roguski 42 */ 43 public class DnaBlockData { 44 45 private static final int SDNA_ID = 'S' << 24 | 'D' << 16 | 'N' << 8 | 'A'; //SDNA 46 private static final int NAME_ID = 'N' << 24 | 'A' << 16 | 'M' << 8 | 'E'; //NAME 47 private static final int TYPE_ID = 'T' << 24 | 'Y' << 16 | 'P' << 8 | 'E'; //TYPE 48 private static final int TLEN_ID = 'T' << 24 | 'L' << 16 | 'E' << 8 | 'N'; //TLEN 49 private static final int STRC_ID = 'S' << 24 | 'T' << 16 | 'R' << 8 | 'C'; //STRC 50 /** Structures available inside the file. */ 51 private final Structure[] structures; 52 /** A map that helps finding a structure by type. */ 53 private final Map<String, Structure> structuresMap; 54 55 /** 56 * Constructor. Loads the block from the given stream during instance creation. 57 * @param inputStream 58 * the stream we read the block from 59 * @param blenderContext 60 * the blender context 61 * @throws BlenderFileException 62 * this exception is throw if the blend file is invalid or somehow corrupted 63 */ DnaBlockData(BlenderInputStream inputStream, BlenderContext blenderContext)64 public DnaBlockData(BlenderInputStream inputStream, BlenderContext blenderContext) throws BlenderFileException { 65 int identifier; 66 67 //reading 'SDNA' identifier 68 identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 69 | inputStream.readByte() << 8 | inputStream.readByte(); 70 71 if (identifier != SDNA_ID) { 72 throw new BlenderFileException("Invalid identifier! '" + this.toString(SDNA_ID) + "' expected and found: " + this.toString(identifier)); 73 } 74 75 //reading names 76 identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 77 | inputStream.readByte() << 8 | inputStream.readByte(); 78 if (identifier != NAME_ID) { 79 throw new BlenderFileException("Invalid identifier! '" + this.toString(NAME_ID) + "' expected and found: " + this.toString(identifier)); 80 } 81 int amount = inputStream.readInt(); 82 if (amount <= 0) { 83 throw new BlenderFileException("The names amount number should be positive!"); 84 } 85 String[] names = new String[amount]; 86 for (int i = 0; i < amount; ++i) { 87 names[i] = inputStream.readString(); 88 } 89 90 //reding types 91 inputStream.alignPosition(4); 92 identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 93 | inputStream.readByte() << 8 | inputStream.readByte(); 94 if (identifier != TYPE_ID) { 95 throw new BlenderFileException("Invalid identifier! '" + this.toString(TYPE_ID) + "' expected and found: " + this.toString(identifier)); 96 } 97 amount = inputStream.readInt(); 98 if (amount <= 0) { 99 throw new BlenderFileException("The types amount number should be positive!"); 100 } 101 String[] types = new String[amount]; 102 for (int i = 0; i < amount; ++i) { 103 types[i] = inputStream.readString(); 104 } 105 106 //reading lengths 107 inputStream.alignPosition(4); 108 identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 109 | inputStream.readByte() << 8 | inputStream.readByte(); 110 if (identifier != TLEN_ID) { 111 throw new BlenderFileException("Invalid identifier! '" + this.toString(TLEN_ID) + "' expected and found: " + this.toString(identifier)); 112 } 113 int[] lengths = new int[amount];//theamount is the same as int types 114 for (int i = 0; i < amount; ++i) { 115 lengths[i] = inputStream.readShort(); 116 } 117 118 //reading structures 119 inputStream.alignPosition(4); 120 identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 121 | inputStream.readByte() << 8 | inputStream.readByte(); 122 if (identifier != STRC_ID) { 123 throw new BlenderFileException("Invalid identifier! '" + this.toString(STRC_ID) + "' expected and found: " + this.toString(identifier)); 124 } 125 amount = inputStream.readInt(); 126 if (amount <= 0) { 127 throw new BlenderFileException("The structures amount number should be positive!"); 128 } 129 structures = new Structure[amount]; 130 structuresMap = new HashMap<String, Structure>(amount); 131 for (int i = 0; i < amount; ++i) { 132 structures[i] = new Structure(inputStream, names, types, blenderContext); 133 if (structuresMap.containsKey(structures[i].getType())) { 134 throw new BlenderFileException("Blend file seems to be corrupted! The type " + structures[i].getType() + " is defined twice!"); 135 } 136 structuresMap.put(structures[i].getType(), structures[i]); 137 } 138 } 139 140 /** 141 * This method returns the amount of the structures. 142 * @return the amount of the structures 143 */ getStructuresCount()144 public int getStructuresCount() { 145 return structures.length; 146 } 147 148 /** 149 * This method returns the structure of the given index. 150 * @param index 151 * the index of the structure 152 * @return the structure of the given index 153 */ getStructure(int index)154 public Structure getStructure(int index) { 155 try { 156 return (Structure) structures[index].clone(); 157 } catch (CloneNotSupportedException e) { 158 throw new IllegalStateException("Structure should be clonable!!!", e); 159 } 160 } 161 162 /** 163 * This method returns a structure of the given name. If the name does not exists then null is returned. 164 * @param name 165 * the name of the structure 166 * @return the required structure or null if the given name is inapropriate 167 */ getStructure(String name)168 public Structure getStructure(String name) { 169 try { 170 return (Structure) structuresMap.get(name).clone(); 171 } catch (CloneNotSupportedException e) { 172 throw new IllegalStateException(e.getMessage(), e); 173 } 174 } 175 176 /** 177 * This method indicates if the structure of the given name exists. 178 * @param name 179 * the name of the structure 180 * @return true if the structure exists and false otherwise 181 */ hasStructure(String name)182 public boolean hasStructure(String name) { 183 return structuresMap.containsKey(name); 184 } 185 186 /** 187 * This method converts the given identifier code to string. 188 * @param code 189 * the code taht is to be converted 190 * @return the string value of the identifier 191 */ toString(int code)192 private String toString(int code) { 193 char c1 = (char) ((code & 0xFF000000) >> 24); 194 char c2 = (char) ((code & 0xFF0000) >> 16); 195 char c3 = (char) ((code & 0xFF00) >> 8); 196 char c4 = (char) (code & 0xFF); 197 return String.valueOf(c1) + c2 + c3 + c4; 198 } 199 200 @Override toString()201 public String toString() { 202 StringBuilder stringBuilder = new StringBuilder("=============== ").append(SDNA_ID).append('\n'); 203 for (Structure structure : structures) { 204 stringBuilder.append(structure.toString()).append('\n'); 205 } 206 return stringBuilder.append("===============").toString(); 207 } 208 } 209