diff --git a/code/ASELoader.cpp b/code/ASELoader.cpp index f36e2cd84..b085ecdb3 100644 --- a/code/ASELoader.cpp +++ b/code/ASELoader.cpp @@ -93,8 +93,8 @@ bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler) const if (extension[2] != 's' && extension[2] != 'S')return false; // NOTE: Sometimes the extension .ASK is also used - // however, often it only contains static animation skeletons - // without real animations. + // however, it often contains static animation skeletons + // only (without real animations). if (extension[3] != 'e' && extension[3] != 'E' && extension[3] != 'k' && extension[3] != 'K')return false; @@ -112,77 +112,70 @@ void ASEImporter::InternReadFile( throw new ImportErrorException( "Failed to open ASE file " + pFile + "."); size_t fileSize = file->FileSize(); + std::string::size_type pos = pFile.find_last_of('.'); std::string extension = pFile.substr( pos); // allocate storage and copy the contents of the file to a memory buffer // (terminate it with zero) - this->mBuffer = new unsigned char[fileSize+1]; + std::vector mBuffer2(fileSize+1); + file->Read( &mBuffer2[0], 1, fileSize); + mBuffer2[fileSize] = '\0'; + + this->mBuffer = &mBuffer2[0]; this->pcScene = pScene; - file->Read( (void*)mBuffer, 1, fileSize); - this->mBuffer[fileSize] = '\0'; // construct an ASE parser and parse the file - this->mParser = new ASE::Parser((const char*)this->mBuffer); - try + // TODO: clean this up, mParser should be a reference, not a pointer ... + ASE::Parser parser(this->mBuffer); + this->mParser = &parser; + this->mParser->Parse(); + + // if absolutely no material has been loaded from the file + // we need to generate a default material + this->GenerateDefaultMaterial(); + + // process all meshes + std::vector avOutMeshes; + avOutMeshes.reserve(this->mParser->m_vMeshes.size()*2); + for (std::vector::iterator + i = this->mParser->m_vMeshes.begin(); + i != this->mParser->m_vMeshes.end();++i) { - this->mParser->Parse(); + if ((*i).bSkip)continue; - // if absolutely no material has been loaded from the file - // we need to generate a default material - this->GenerateDefaultMaterial(); + this->TransformVertices(*i); + // now we need to create proper meshes from the import we need to + // split them by materials, build valid vertex/face lists ... + this->BuildUniqueRepresentation(*i); - // process all meshes - std::vector avOutMeshes; - avOutMeshes.reserve(this->mParser->m_vMeshes.size()*2); - for (std::vector::iterator - i = this->mParser->m_vMeshes.begin(); - i != this->mParser->m_vMeshes.end();++i) - { - if ((*i).bSkip)continue; - - this->TransformVertices(*i); - // now we need to create proper meshes from the import we need to - // split them by materials, build valid vertex/face lists ... - this->BuildUniqueRepresentation(*i); - - // need to generate proper vertex normals if necessary - this->GenerateNormals(*i); - - // convert all meshes to aiMesh objects - this->ConvertMeshes(*i,avOutMeshes); - } - - // now build the output mesh list. remove dummies - pScene->mNumMeshes = (unsigned int)avOutMeshes.size(); - aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - for (std::vector::const_iterator - i = avOutMeshes.begin(); - i != avOutMeshes.end();++i) - { - if (!(*i)->mNumFaces)continue; - *pp++ = *i; - } - pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes); - - // buil final material indices (remove submaterials and make the final list) - this->BuildMaterialIndices(); - - // build the final node graph - this->BuildNodes(); - - // build output animations - this->BuildAnimations(); + // need to generate proper vertex normals if necessary + this->GenerateNormals(*i); + // convert all meshes to aiMesh objects + this->ConvertMeshes(*i,avOutMeshes); } - catch (ImportErrorException* ex) + + // now build the output mesh list. remove dummies + pScene->mNumMeshes = (unsigned int)avOutMeshes.size(); + aiMesh** pp = pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + for (std::vector::const_iterator + i = avOutMeshes.begin(); + i != avOutMeshes.end();++i) { - delete this->mParser; AI_DEBUG_INVALIDATE_PTR( this->mParser ); - delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR( this->mBuffer ); - throw ex; + if (!(*i)->mNumFaces)continue; + *pp++ = *i; } - delete this->mParser; AI_DEBUG_INVALIDATE_PTR( this->mParser ); - delete[] this->mBuffer; AI_DEBUG_INVALIDATE_PTR( this->mBuffer ); + pScene->mNumMeshes = (unsigned int)(pp - pScene->mMeshes); + + // buil final material indices (remove submaterials and make the final list) + this->BuildMaterialIndices(); + + // build the final node graph + this->BuildNodes(); + + // build output animations + this->BuildAnimations(); return; } // ------------------------------------------------------------------------------------------------ diff --git a/code/ASELoader.h b/code/ASELoader.h index 86f4e2edc..e85642fa8 100644 --- a/code/ASELoader.h +++ b/code/ASELoader.h @@ -164,7 +164,7 @@ protected: ASE::Parser* mParser; /** Buffer to hold the loaded file */ - unsigned char* mBuffer; + char* mBuffer; /** Scene to be filled */ aiScene* pcScene; diff --git a/code/LWOLoader.cpp b/code/LWOLoader.cpp index a9f56bb69..c368e441d 100644 --- a/code/LWOLoader.cpp +++ b/code/LWOLoader.cpp @@ -70,9 +70,6 @@ LWOImporter::LWOImporter() // Destructor, private as well LWOImporter::~LWOImporter() { - mFaces.clear(); - mTempPoints.clear(); - mSurfaces.clear(); } // ------------------------------------------------------------------------------------------------ @@ -122,112 +119,122 @@ void LWOImporter::InternReadFile( const std::string& pFile, mFileBuffer = &mBuffer[0] + 12; fileSize -= 12; - try + // create temporary storage on the stack but store points to + // it in the class instance. Therefoe everything will be destructed + // properly if an exception is thrown. + PointList _mTempPoints; + mTempPoints = &_mTempPoints; + FaceList _mFaces; + mFaces = &_mFaces; + TagList _mTags; + mTags = &_mTags; + TagMappingTable _mMapping; + mMapping = &_mMapping; + SurfaceList _mSurfaces; + mSurfaces = &_mSurfaces; + + // old lightwave file format (prior to v6) + if (AI_LWO_FOURCC_LWOB == fileType)this->LoadLWOBFile(); + + // new lightwave format + else if (AI_LWO_FOURCC_LWO2 == fileType)this->LoadLWO2File(); + + // we don't know this format + else { - // old lightwave file format (prior to v6) - if (AI_LWO_FOURCC_LWOB == fileType) - this->LoadLWOBFile(); - // new lightwave format - else if (AI_LWO_FOURCC_LWO2 == fileType) - this->LoadLWO2File(); - // we don't know this format - else - { - char szBuff[5]; - szBuff[0] = (char)(fileType >> 24u); - szBuff[1] = (char)(fileType >> 16u); - szBuff[2] = (char)(fileType >> 8u); - szBuff[3] = (char)(fileType); - throw new ImportErrorException(std::string("Unknown LWO sub format: ") + szBuff); - } - - // generate a default surface if necessary - if (mSurfaces.empty()) - mSurfaces.push_back(LWO::Surface()); - - // now sort all faces by the surfaces assigned to them - typedef std::vector SortedRep; - std::vector pSorted(mSurfaces.size()); - - unsigned int i = 0; - for (FaceList::iterator it = mFaces.begin(), end = mFaces.end(); - it != end;++it,++i) - { - if ((*it).surfaceIndex >= mSurfaces.size()) - { - DefaultLogger::get()->warn("LWO: Invalid face surface index"); - (*it).surfaceIndex = mSurfaces.size()-1; - } - pSorted[(*it).surfaceIndex].push_back(i); - } - - // now generate output meshes - for (unsigned int p = 0; p < mSurfaces.size();++p) - if (!pSorted[p].empty())pScene->mNumMeshes++; - - if (!(pScene->mNumMaterials = pScene->mNumMeshes)) - throw new ImportErrorException("LWO: There are no meshes"); - - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; - for (unsigned int p = 0,i = 0;i < mSurfaces.size();++i) - { - SortedRep& sorted = pSorted[i]; - if (sorted.empty())continue; - - // generate the mesh - aiMesh* mesh = pScene->mMeshes[p] = new aiMesh(); - mesh->mNumFaces = sorted.size(); - - for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end(); - it != end;++it) - { - mesh->mNumVertices += mFaces[*it].mNumIndices; - } - - mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - mesh->mFaces = new aiFace[mesh->mNumFaces]; - mesh->mMaterialIndex = p; - - // now convert all faces - unsigned int vert = 0; - for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end(); - it != end;++it) - { - LWO::Face& face = mFaces[*it]; - - // copy all vertices - for (unsigned int q = 0; q < face.mNumIndices;++q) - { - *mesh->mVertices++ = mTempPoints[face.mIndices[q]]; - face.mIndices[q] = vert++; - } - - mesh->mFaces->mIndices = face.mIndices; - mesh->mFaces->mNumIndices = face.mNumIndices; - face.mIndices = NULL; // make sure it won't be deleted - - mesh->mFaces++; - } - mesh->mFaces -= mesh->mNumFaces; - mesh->mVertices -= mesh->mNumVertices; - - // generate the corresponding material - MaterialHelper* pcMat = new MaterialHelper(); - pScene->mMaterials[p] = pcMat; - - // todo - - ++p; - } + char szBuff[5]; + szBuff[0] = (char)(fileType >> 24u); + szBuff[1] = (char)(fileType >> 16u); + szBuff[2] = (char)(fileType >> 8u); + szBuff[3] = (char)(fileType); + throw new ImportErrorException(std::string("Unknown LWO sub format: ") + szBuff); } - // make sure the arrays are cleaned up ... - catch (ImportErrorException* ex) + ResolveTags(); + + // now sort all faces by the surfaces assigned to them + typedef std::vector SortedRep; + std::vector pSorted(mSurfaces->size()+1); + + unsigned int i = 0; + unsigned int iDefaultSurface = 0xffffffff; + for (FaceList::iterator it = mFaces->begin(), end = mFaces->end(); + it != end;++it,++i) { - this->~LWOImporter(); - throw ex; + unsigned int idx = (*it).surfaceIndex; + if (idx >= mTags->size()) + { + DefaultLogger::get()->warn("LWO: Invalid face surface index"); + idx = mTags->size()-1; + } + if(0xffffffff == (idx = _mMapping[idx])) + { + if (0xffffffff == iDefaultSurface) + { + iDefaultSurface = mSurfaces->size(); + mSurfaces->push_back(LWO::Surface()); + LWO::Surface& surf = mSurfaces->back(); + surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f; + } + idx = iDefaultSurface; + } + pSorted[idx].push_back(i); + } + if (0xffffffff == iDefaultSurface)pSorted.erase(pSorted.end()-1); + + // now generate output meshes + for (unsigned int p = 0; p < mSurfaces->size();++p) + if (!pSorted[p].empty())pScene->mNumMeshes++; + + if (!(pScene->mNumMaterials = pScene->mNumMeshes)) + throw new ImportErrorException("LWO: There are no meshes"); + + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; + for (unsigned int p = 0,i = 0;i < mSurfaces->size();++i) + { + SortedRep& sorted = pSorted[i]; + if (sorted.empty())continue; + + // generate the mesh + aiMesh* mesh = pScene->mMeshes[p] = new aiMesh(); + mesh->mNumFaces = sorted.size(); + + for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end(); + it != end;++it) + { + mesh->mNumVertices += _mFaces[*it].mNumIndices; + } + + aiVector3D* pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + aiFace* pf = mesh->mFaces = new aiFace[mesh->mNumFaces]; + mesh->mMaterialIndex = p; + + // now convert all faces + unsigned int vert = 0; + for (SortedRep::const_iterator it = sorted.begin(), end = sorted.end(); + it != end;++it) + { + LWO::Face& face = _mFaces[*it]; + + // copy all vertices + for (unsigned int q = 0; q < face.mNumIndices;++q) + { + *pv++ = _mTempPoints[face.mIndices[q]]; + face.mIndices[q] = vert++; + } + + pf->mIndices = face.mIndices; + pf->mNumIndices = face.mNumIndices; + face.mIndices = NULL; // make sure it won't be deleted + pf++; + } + + // generate the corresponding material + MaterialHelper* pcMat = new MaterialHelper(); + pScene->mMaterials[p] = pcMat; + //ConvertMaterial(mSurfaces[i],pcMat); + ++p; } - this->~LWOImporter(); } // ------------------------------------------------------------------------------------------------ void LWOImporter::CountVertsAndFaces(unsigned int& verts, unsigned int& faces, @@ -248,29 +255,34 @@ void LWOImporter::CountVertsAndFaces(unsigned int& verts, unsigned int& faces, } } // ------------------------------------------------------------------------------------------------ -void LWOImporter::CopyFaceIndices(LWOImporter::FaceList::iterator& it,LE_NCONST uint8_t*& cursor, - const uint8_t* const end, unsigned int max) +void LWOImporter::CopyFaceIndices(LWOImporter::FaceList::iterator& it, + LE_NCONST uint8_t*& cursor, + const uint8_t* const end, + unsigned int max) { while (cursor < end && max--) { LWO::Face& face = *it;++it; - face.mNumIndices = *((uint16_t*)cursor); - if (cursor + face.mNumIndices*2 + 4 >= end)break; - face.mIndices = new unsigned int[face.mNumIndices]; - for (unsigned int i = 0; i < face.mNumIndices;++i) + if(face.mNumIndices = *((uint16_t*)cursor)) { - face.mIndices[i] = *((uint16_t*)(cursor+=2)); - if (face.mIndices[i] >= mTempPoints.size()) + if (cursor + face.mNumIndices*2 + 4 >= end)break; + face.mIndices = new unsigned int[face.mNumIndices]; + for (unsigned int i = 0; i < face.mNumIndices;++i) { - face.mIndices[i] = mTempPoints.size()-1; - DefaultLogger::get()->warn("LWO: Face index is out of range"); + face.mIndices[i] = *((uint16_t*)(cursor+=2)); + if (face.mIndices[i] >= mTempPoints->size()) + { + face.mIndices[i] = mTempPoints->size()-1; + DefaultLogger::get()->warn("LWO: Face index is out of range"); + } } } + else DefaultLogger::get()->warn("LWO: Face has 0 indices"); cursor+=2; int16_t surface = *((uint16_t*)cursor);cursor+=2; if (surface < 0) { - surface *= -1; + surface = -surface; // there are detail polygons uint16_t numPolygons = *((uint16_t*)cursor);cursor+=2; @@ -279,12 +291,81 @@ void LWOImporter::CopyFaceIndices(LWOImporter::FaceList::iterator& it,LE_NCONST face.surfaceIndex = surface-1; } } +// ------------------------------------------------------------------------------------------------ +void LWOImporter::ResolveTags() +{ + mMapping->resize(mTags->size(),0xffffffff); + for (unsigned int a = 0; a < mTags->size();++a) + { + for (unsigned int i = 0; i < mSurfaces->size();++i) + { + if ((*mTags)[a] == (*mSurfaces)[i].mName) + { + (*mMapping)[a] = i; + break; + } + } + } +} +// ------------------------------------------------------------------------------------------------ +void LWOImporter::ParseString(std::string& out,unsigned int max) +{ + unsigned int iCursor = 0; + const char* in = (const char*)mFileBuffer,*sz = in; + while (*in) + { + if (++iCursor > max) + { + DefaultLogger::get()->warn("LWOB: Invalid file, texture name (TIMG) is too long"); + break; + } + ++in; + } + unsigned int len = unsigned int (in-sz); + out = std::string(sz,len); +} +// ------------------------------------------------------------------------------------------------ +void LWOImporter::AdjustTexturePath(std::string& out) +{ + if (::strstr(out.c_str(), "(sequence)")) + { + // remove the (sequence) and append 000 + DefaultLogger::get()->info("LWO: Sequence of animated texture found. It will be ignored"); + out = out.substr(0,out.length()-10) + "000"; + } +} + +// ------------------------------------------------------------------------------------------------ +#define AI_LWO_VALIDATE_CHUNK_LENGTH(name,size) \ + if (head->length < size) \ + { \ + DefaultLogger::get()->warn("LWO: "#name" chunk is too small"); \ + break; \ + } \ + +// ------------------------------------------------------------------------------------------------ +void LWOImporter::LoadLWOTags(unsigned int size) +{ + const char* szCur = (const char*)mFileBuffer, *szLast = szCur; + const char* const szEnd = szLast+size; + while (szCur < szEnd) + { + if (!(*szCur++)) + { + const unsigned int len = unsigned int(szCur-szLast); + mTags->push_back(std::string(szLast,len)); + szCur += len & 1; + szLast = szCur; + } + } +} + // ------------------------------------------------------------------------------------------------ void LWOImporter::LoadLWOBSurface(unsigned int size) { uint32_t iCursor = 0; - mSurfaces.push_back( LWO::Surface () ); - LWO::Surface& surf = mSurfaces.back(); + mSurfaces->push_back( LWO::Surface () ); + LWO::Surface& surf = mSurfaces->back(); LWO::Texture* pTex = NULL; // at first we'll need to read the name of the surface @@ -309,16 +390,13 @@ void LWOImporter::LoadLWOBSurface(unsigned int size) "a surface sub chunk points behind the end of the file"); } mFileBuffer += sizeof(IFF::ChunkHeader); + LE_NCONST uint8_t* next = mFileBuffer+head->length; switch (head->type) { // diffuse color case AI_LWO_COLR: { - if (head->length < 3) - { - DefaultLogger::get()->warn("LWO: COLR chunk is expected to be at least 3 bytes in size"); - break; - } + AI_LWO_VALIDATE_CHUNK_LENGTH(COLR,3); surf.mColor.r = *mFileBuffer++ / 255.0f; surf.mColor.g = *mFileBuffer++ / 255.0f; surf.mColor.b = *mFileBuffer / 255.0f; @@ -327,6 +405,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size) // diffuse strength ... hopefully case AI_LWO_DIFF: { + AI_LWO_VALIDATE_CHUNK_LENGTH(DIFF,2); AI_LSWAP2(mFileBuffer); surf.mDiffuseValue = *((int16_t*)mFileBuffer) / 255.0f; break; @@ -334,6 +413,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size) // specular strength ... hopefully case AI_LWO_SPEC: { + AI_LWO_VALIDATE_CHUNK_LENGTH(SPEC,2); AI_LSWAP2(mFileBuffer); surf.mSpecularValue = *((int16_t*)mFileBuffer) / 255.0f; break; @@ -341,6 +421,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size) // transparency case AI_LWO_TRAN: { + AI_LWO_VALIDATE_CHUNK_LENGTH(TRAN,2); AI_LSWAP2(mFileBuffer); surf.mTransparency = *((int16_t*)mFileBuffer) / 255.0f; break; @@ -348,6 +429,7 @@ void LWOImporter::LoadLWOBSurface(unsigned int size) // glossiness case AI_LWO_GLOS: { + AI_LWO_VALIDATE_CHUNK_LENGTH(GLOS,2); AI_LSWAP2(mFileBuffer); surf.mGlossiness = float(*((int16_t*)mFileBuffer)); break; @@ -387,18 +469,9 @@ void LWOImporter::LoadLWOBSurface(unsigned int size) { if (pTex) { - unsigned int iCursor = 0; - while (*mFileBuffer) - { - if (++iCursor > head->length) - { - DefaultLogger::get()->warn("LWOB: Invalid file, texture name (TIMG) is too long"); - break; - } - ++mFileBuffer; - } - unsigned int len = unsigned int (mFileBuffer-sz); - pTex->mFileName = std::string((const char*)sz,len); + ParseString(pTex->mFileName,head->length); + AdjustTexturePath(pTex->mFileName); + mFileBuffer += pTex->mFileName.length(); } else DefaultLogger::get()->warn("LWOB: TIMG tag was encuntered although " "there was no xTEX tag before"); @@ -407,13 +480,14 @@ void LWOImporter::LoadLWOBSurface(unsigned int size) // texture strength case AI_LWO_TVAL: { + AI_LWO_VALIDATE_CHUNK_LENGTH(TVAL,1); if (pTex)pTex->mStrength = *mFileBuffer / 255.0f; else DefaultLogger::get()->warn("LWOB: TVAL tag was encuntered " "although there was no xTEX tag before"); break; } } - mFileBuffer += head->length; + mFileBuffer = next; } } // ------------------------------------------------------------------------------------------------ @@ -433,17 +507,18 @@ void LWOImporter::LoadLWOBFile() break; } mFileBuffer += sizeof(IFF::ChunkHeader); + LE_NCONST uint8_t* next = mFileBuffer+head->length; switch (head->type) { // vertex list case AI_LWO_PNTS: { - mTempPoints.resize( head->length / 12 ); + mTempPoints->resize( head->length / 12 ); #ifndef AI_BUILD_BIG_ENDIAN for (unsigned int i = 0; i < head->length>>2;++i) ByteSwap::Swap4( mFileBuffer + (i << 2)); #endif - ::memcpy(&mTempPoints[0],mFileBuffer,head->length); + ::memcpy(&(*mTempPoints)[0],mFileBuffer,head->length); break; } // face list @@ -464,13 +539,21 @@ void LWOImporter::LoadLWOBFile() // allocate the output array and copy face indices if (iNumFaces) { - this->mTempPoints.resize(iNumVertices); - this->mFaces.resize(iNumFaces); - FaceList::iterator it = this->mFaces.begin(); - CopyFaceIndices(it,mFileBuffer,end); + cursor = mFileBuffer; + this->mTempPoints->resize(iNumVertices); + this->mFaces->resize(iNumFaces); + FaceList::iterator it = this->mFaces->begin(); + CopyFaceIndices(it,cursor,end); } break; } + // list of tags + case AI_LWO_SRFS: + { + LoadLWOTags(head->length); + break; + } + // surface chunk case AI_LWO_SURF: { @@ -478,7 +561,7 @@ void LWOImporter::LoadLWOBFile() break; } } - mFileBuffer += head->length; + mFileBuffer = next; } } // ------------------------------------------------------------------------------------------------ diff --git a/code/LWOLoader.h b/code/LWOLoader.h index c102c199c..6fd662e9e 100644 --- a/code/LWOLoader.h +++ b/code/LWOLoader.h @@ -107,10 +107,23 @@ protected: */ void LoadLWOBSurface(unsigned int size); + // ------------------------------------------------------------------- + /** Loads the LWO tag list from the file + */ + void LoadLWOTags(unsigned int size); - typedef std::vector PointList; - typedef std::vector FaceList; - typedef std::vector SurfaceList; + // ------------------------------------------------------------------- + /** Resolve the tag and surface lists that have been loaded. + * Generates the mMapping table. + */ + void ResolveTags(); + + + typedef std::vector PointList; + typedef std::vector FaceList; + typedef std::vector SurfaceList; + typedef std::vector TagList; + typedef std::vector TagMappingTable; private: @@ -131,16 +144,33 @@ private: const uint8_t* const end, unsigned int max = 0xffffffff); + // ------------------------------------------------------------------- + /** Parse a string from the current file position + */ + void ParseString(std::string& out,unsigned int max); + + // ------------------------------------------------------------------- + /** Adjust a texture path + */ + void AdjustTexturePath(std::string& out); + protected: /** Temporary point list from the file */ - PointList mTempPoints; + PointList* mTempPoints; /** Temporary face list from the file*/ - FaceList mFaces; + FaceList* mFaces; + + /** Temporary tag list from the file */ + TagList* mTags; + + /** Mapping table to convert from tag to surface indices. + 0xffffffff indicates that a no corresponding surface is available */ + TagMappingTable* mMapping; /** Temporary surface list from the file */ - SurfaceList mSurfaces; + SurfaceList* mSurfaces; /** file buffer */ LE_NCONST uint8_t* mFileBuffer;