/* * 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 java.util.ArrayList; import java.util.List; import com.jme3.scene.plugins.blender.BlenderContext; /** * A class that represents a pointer of any level that can be stored in the file. * @author Marcin Roguski */ public class Pointer { /** The blender context. */ private BlenderContext blenderContext; /** The level of the pointer. */ private int pointerLevel; /** The address in file it points to. */ private long oldMemoryAddress; /** This variable indicates if the field is a function pointer. */ public boolean function; /** * Constructr. Stores the basic data about the pointer. * @param pointerLevel * the level of the pointer * @param function * this variable indicates if the field is a function pointer * @param blenderContext * the repository f data; used in fetching the value that the pointer points */ public Pointer(int pointerLevel, boolean function, BlenderContext blenderContext) { this.pointerLevel = pointerLevel; this.function = function; this.blenderContext = blenderContext; } /** * This method fills the pointer with its address value (it doesn't get the actual data yet. Use the 'fetch' method * for this. * @param inputStream * the stream we read the pointer value from */ public void fill(BlenderInputStream inputStream) { oldMemoryAddress = inputStream.readPointer(); } /** * This method fetches the data stored under the given address. * @return the data read from the file * @throws BlenderFileException * this exception is thrown when the blend file structure is somehow invalid or corrupted */ public List<Structure> fetchData() throws BlenderFileException { if (oldMemoryAddress == 0) { throw new NullPointerException("The pointer points to nothing!"); } List<Structure> structures = null; FileBlockHeader dataFileBlock = blenderContext.getFileBlock(oldMemoryAddress); if (dataFileBlock == null) { throw new BlenderFileException("No data stored for address: " + oldMemoryAddress + ". Make sure you did not open the newer blender file with older blender version."); } BlenderInputStream inputStream = blenderContext.getInputStream(); if (pointerLevel > 1) { int pointersAmount = dataFileBlock.getSize() / inputStream.getPointerSize() * dataFileBlock.getCount(); for (int i = 0; i < pointersAmount; ++i) { inputStream.setPosition(dataFileBlock.getBlockPosition() + inputStream.getPointerSize() * i); long oldMemoryAddress = inputStream.readPointer(); if (oldMemoryAddress != 0L) { Pointer p = new Pointer(pointerLevel - 1, function, blenderContext); p.oldMemoryAddress = oldMemoryAddress; if (structures == null) { structures = p.fetchData(); } else { structures.addAll(p.fetchData()); } } else { // it is necessary to put null's if the pointer is null, ie. in materials array that is attached to the mesh, the index // of the material is important, that is why we need null's to indicate that some materials' slots are empty if (structures == null) { structures = new ArrayList<Structure>(); } structures.add(null); } } } else { inputStream.setPosition(dataFileBlock.getBlockPosition()); structures = new ArrayList<Structure>(dataFileBlock.getCount()); for (int i = 0; i < dataFileBlock.getCount(); ++i) { Structure structure = blenderContext.getDnaBlockData().getStructure(dataFileBlock.getSdnaIndex()); structure.fill(blenderContext.getInputStream()); structures.add(structure); } return structures; } return structures; } /** * This method indicates if this pointer points to a function. * @return <b>true</b> if this is a function pointer and <b>false</b> otherwise */ public boolean isFunction() { return function; } /** * This method indicates if this is a null-pointer or not. * @return <b>true</b> if the pointer is null and <b>false</b> otherwise */ public boolean isNull() { return oldMemoryAddress == 0; } /** * This method indicates if this is a null-pointer or not. * @return <b>true</b> if the pointer is not null and <b>false</b> otherwise */ public boolean isNotNull() { return oldMemoryAddress != 0; } /** * This method returns the old memory address of the structure pointed by the pointer. * @return the old memory address of the structure pointed by the pointer */ public long getOldMemoryAddress() { return oldMemoryAddress; } @Override public String toString() { return oldMemoryAddress == 0 ? "{$null$}" : "{$" + oldMemoryAddress + "$}"; } @Override public int hashCode() { return 31 + (int) (oldMemoryAddress ^ oldMemoryAddress >>> 32); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } Pointer other = (Pointer) obj; if (oldMemoryAddress != other.oldMemoryAddress) { return false; } return true; } }