Home | History | Annotate | Download | only in file
      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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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
    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