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 */
32package com.jme3.scene.plugins.blender.file;
33
34import com.jme3.scene.plugins.blender.BlenderContext;
35import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
36
37/**
38 * A class that holds the header data of a file block. The file block itself is not implemented. This class holds its
39 * start position in the stream and using this the structure can fill itself with the proper data.
40 * @author Marcin Roguski
41 */
42public class FileBlockHeader {
43
44    public static final int BLOCK_TE00 = 'T' << 24 | 'E' << 16;					//TE00
45    public static final int BLOCK_ME00 = 'M' << 24 | 'E' << 16;					//ME00
46    public static final int BLOCK_SR00 = 'S' << 24 | 'R' << 16;					//SR00
47    public static final int BLOCK_CA00 = 'C' << 24 | 'A' << 16;					//CA00
48    public static final int BLOCK_LA00 = 'L' << 24 | 'A' << 16;					//LA00
49    public static final int BLOCK_OB00 = 'O' << 24 | 'B' << 16;					//OB00
50    public static final int BLOCK_MA00 = 'M' << 24 | 'A' << 16;					//MA00
51    public static final int BLOCK_SC00 = 'S' << 24 | 'C' << 16;					//SC00
52    public static final int BLOCK_WO00 = 'W' << 24 | 'O' << 16;					//WO00
53    public static final int BLOCK_TX00 = 'T' << 24 | 'X' << 16;					//TX00
54    public static final int BLOCK_IP00 = 'I' << 24 | 'P' << 16;					//IP00
55    public static final int BLOCK_AC00 = 'A' << 24 | 'C' << 16;					//AC00
56    public static final int BLOCK_GLOB = 'G' << 24 | 'L' << 16 | 'O' << 8 | 'B';	//GLOB
57    public static final int BLOCK_REND = 'R' << 24 | 'E' << 16 | 'N' << 8 | 'D';	//REND
58    public static final int BLOCK_DATA = 'D' << 24 | 'A' << 16 | 'T' << 8 | 'A';	//DATA
59    public static final int BLOCK_DNA1 = 'D' << 24 | 'N' << 16 | 'A' << 8 | '1';	//DNA1
60    public static final int BLOCK_ENDB = 'E' << 24 | 'N' << 16 | 'D' << 8 | 'B';	//ENDB
61    /** Identifier of the file-block [4 bytes]. */
62    private int code;
63    /** Total length of the data after the file-block-header [4 bytes]. */
64    private int size;
65    /**
66     * Memory address the structure was located when written to disk [4 or 8 bytes (defined in file header as a pointer
67     * size)].
68     */
69    private long oldMemoryAddress;
70    /** Index of the SDNA structure [4 bytes]. */
71    private int sdnaIndex;
72    /** Number of structure located in this file-block [4 bytes]. */
73    private int count;
74    /** Start position of the block's data in the stream. */
75    private int blockPosition;
76
77    /**
78     * Constructor. Loads the block header from the given stream during instance creation.
79     * @param inputStream
80     *        the stream we read the block header from
81     * @param blenderContext
82     *        the blender context
83     * @throws BlenderFileException
84     *         this exception is thrown when the pointer size is neither 4 nor 8
85     */
86    public FileBlockHeader(BlenderInputStream inputStream, BlenderContext blenderContext) throws BlenderFileException {
87        inputStream.alignPosition(4);
88        code = inputStream.readByte() << 24 | inputStream.readByte() << 16
89                | inputStream.readByte() << 8 | inputStream.readByte();
90        size = inputStream.readInt();
91        oldMemoryAddress = inputStream.readPointer();
92        sdnaIndex = inputStream.readInt();
93        count = inputStream.readInt();
94        blockPosition = inputStream.getPosition();
95        if (FileBlockHeader.BLOCK_DNA1 == code) {
96            blenderContext.setBlockData(new DnaBlockData(inputStream, blenderContext));
97        } else {
98            inputStream.setPosition(blockPosition + size);
99            blenderContext.addFileBlockHeader(Long.valueOf(oldMemoryAddress), this);
100        }
101    }
102
103    /**
104     * This method returns the structure described by the header filled with appropriate data.
105     * @param blenderContext
106     *        the blender context
107     * @return structure filled with data
108     * @throws BlenderFileException
109     */
110    public Structure getStructure(BlenderContext blenderContext) throws BlenderFileException {
111        blenderContext.getInputStream().setPosition(blockPosition);
112        Structure structure = blenderContext.getDnaBlockData().getStructure(sdnaIndex);
113        structure.fill(blenderContext.getInputStream());
114        return structure;
115    }
116
117    /**
118     * This method returns the code of this data block.
119     * @return the code of this data block
120     */
121    public int getCode() {
122        return code;
123    }
124
125    /**
126     * This method returns the size of the data stored in this block.
127     * @return the size of the data stored in this block
128     */
129    public int getSize() {
130        return size;
131    }
132
133    /**
134     * This method returns the memory address.
135     * @return the memory address
136     */
137    public long getOldMemoryAddress() {
138        return oldMemoryAddress;
139    }
140
141    /**
142     * This method returns the sdna index.
143     * @return the sdna index
144     */
145    public int getSdnaIndex() {
146        return sdnaIndex;
147    }
148
149    /**
150     * This data returns the number of structure stored in the data block after this header.
151     * @return the number of structure stored in the data block after this header
152     */
153    public int getCount() {
154        return count;
155    }
156
157    /**
158     * This method returns the start position of the data block in the blend file stream.
159     * @return the start position of the data block
160     */
161    public int getBlockPosition() {
162        return blockPosition;
163    }
164
165    /**
166     * This method indicates if the block is the last block in the file.
167     * @return true if this block is the last one in the file nad false otherwise
168     */
169    public boolean isLastBlock() {
170        return FileBlockHeader.BLOCK_ENDB == code;
171    }
172
173    /**
174     * This method indicates if the block is the SDNA block.
175     * @return true if this block is the SDNA block and false otherwise
176     */
177    public boolean isDnaBlock() {
178        return FileBlockHeader.BLOCK_DNA1 == code;
179    }
180
181    @Override
182    public String toString() {
183        return "FILE BLOCK HEADER [" + this.codeToString(code) + " : " + size + " : " + oldMemoryAddress + " : " + sdnaIndex + " : " + count + "]";
184    }
185
186    /**
187     * This method transforms the coded bloch id into a string value.
188     * @param code
189     *        the id of the block
190     * @return the string value of the block id
191     */
192    protected String codeToString(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