diff --git a/code/nel/tools/pipeline/max/storage_chunks.cpp b/code/nel/tools/pipeline/max/storage_chunks.cpp new file mode 100644 index 000000000..5edf1fdaa --- /dev/null +++ b/code/nel/tools/pipeline/max/storage_chunks.cpp @@ -0,0 +1,189 @@ +/** + * \file storage_chunks.cpp + * \brief CStorageChunks + * \date 2012-08-18 09:20GMT + * \author Jan Boon (Kaetemi) + * CStorageChunks + */ + +/* + * Copyright (C) 2012 by authors + * + * This file is part of RYZOM CORE PIPELINE. + * RYZOM CORE PIPELINE is free software: you can redistribute it + * and/or modify it under the terms of the GNU Affero General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * RYZOM CORE PIPELINE is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with RYZOM CORE PIPELINE. If not, see + * . + */ + +#include +#include "storage_chunks.h" + +// STL includes + +// NeL includes +#include + +// Project includes + +// using namespace std; +// using namespace NLMISC; + +// #define NL_DEBUG_STORAGE + +namespace PIPELINE { +namespace MAX { + +CStorageChunks::CStorageChunks(NLMISC::IStream &stream, sint64 size) : m_Stream(stream), m_Is64Bit(false) +{ + if (size >= 2147483647L) + throw NLMISC::EStream("64bit chunks not supported"); + m_Chunks.reserve(64); + m_Chunks.resize(1); + m_Chunks[0].HeaderSize = 0; + m_Chunks[0].OffsetBegin = stream.getPos(); + if (stream.isReading()) + { + m_Chunks[0].Id = 0; + m_Chunks[0].Size = 0x80000000 | (uint32)(size); + } + else + { + m_Chunks[0].Id = 1; + m_Chunks[0].Size = 0; + } +} + +CStorageChunks::~CStorageChunks() +{ +#ifdef NL_DEBUG_STORAGE + if (m_Chunks.size() != 1) + nldebug("Not all chunks were closed"); +#endif +} + +bool CStorageChunks::enterChunk() +{ + if (m_Stream.isReading()) + { + // input logic + if (!isChunkContainer()) + { +#ifdef NL_DEBUG_STORAGE + nldebug("Current chunk is not a container, cannot enter"); +#endif + return false; + } + if (endOfChunk()) + { +#ifdef NL_DEBUG_STORAGE + nldebug("End of chunk, cannot enter"); +#endif + return false; + } + m_Chunks.resize(m_Chunks.size() + 1); + CChunk *chunk = currentChunk(); + chunk->OffsetBegin = m_Stream.getPos(); + m_Stream.serial(chunk->Id); + m_Stream.serial(chunk->Size); + chunk->HeaderSize = 6; + if (chunk->Size == 0) + { + // this is a 64bit chunk + uint64 size64; + m_Stream.serial(size64); + chunk->HeaderSize += 8; + bool iscont = (size64 & 0x8000000000000000) == 0x8000000000000000; + size64 &= 0x7FFFFFFFFFFFFFFF; + if (size64 >= 2147483647L) + throw NLMISC::EStream("64bit chunks not supported"); + // downgrade to 32 bit chunk + chunk->Size = (uint32)size64; + if (iscont) chunk->Size |= 0x80000000; + m_Is64Bit = true; // it's true + } + return true; + } + else + { +#ifdef NL_DEBUG_STORAGE + nldebug("No input, this function cannot output, throw exception"); +#endif + throw NLMISC::EStream(); + } +} + +bool CStorageChunks::enterChunk(uint16 id, bool container) +{ + if (!m_Stream.isReading()) + { + if (m_Is64Bit) + throw NLMISC::EStream("64bit chunks not supported"); + + // enter the new chunk + m_Chunks.resize(m_Chunks.size() + 1); + CChunk *chunk = currentChunk(); + uint32 sizeDummy = 0xFFFFFFFF; + chunk->Id = container ? 1 : 0; + chunk->OffsetBegin = m_Stream.getPos(); // store current pos + + // write header + m_Stream.serial(id); // write the id + m_Stream.serial(sizeDummy); // write 32 bit size placeholder + return true; + } + else // input or exception + { + while (enterChunk()) + { + if (getChunkId() == id) + return true; + leaveChunk(); // skip data + } + return false; + } +} + +sint32 CStorageChunks::leaveChunk() +{ + if (m_Stream.isReading()) + { + // input logic + sint32 skipped = currentChunk()->endOfChunk() - m_Stream.getPos(); + if (skipped) + { + m_Stream.seek(currentChunk()->endOfChunk(), NLMISC::IStream::begin); +#ifdef NL_DEBUG_STORAGE + nldebug("Skipped %i bytes in the current chunk", skipped); +#endif + } + m_Chunks.resize(m_Chunks.size() - 1); + return skipped; + } + else + { + sint32 pos = m_Stream.getPos(); + sint32 sizeWithHeader = pos - currentChunk()->OffsetBegin; + sint32 sizePos = currentChunk()->OffsetBegin + 2; + m_Stream.seek(sizePos, NLMISC::IStream::begin); // hopefully this correctly overwrites!!! + uint32 sizeField = (uint32)sizeWithHeader | (uint32)currentChunk()->Id << 31; // add container flag + m_Stream.serial(sizeField); + m_Stream.seek(pos, NLMISC::IStream::begin); + m_Chunks.resize(m_Chunks.size() - 1); + return sizeWithHeader; + } +} + +} /* namespace MAX */ +} /* namespace PIPELINE */ + +/* end of file */ diff --git a/code/nel/tools/pipeline/max/storage_chunks.h b/code/nel/tools/pipeline/max/storage_chunks.h new file mode 100644 index 000000000..45d72fb87 --- /dev/null +++ b/code/nel/tools/pipeline/max/storage_chunks.h @@ -0,0 +1,107 @@ +/** + * \file storage_chunks.h + * \brief CStorageChunks + * \date 2012-08-18 09:20GMT + * \author Jan Boon (Kaetemi) + * CStorageChunks + */ + +/* + * Copyright (C) 2012 by authors + * + * This file is part of RYZOM CORE PIPELINE. + * RYZOM CORE PIPELINE is free software: you can redistribute it + * and/or modify it under the terms of the GNU Affero General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * RYZOM CORE PIPELINE is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with RYZOM CORE PIPELINE. If not, see + * . + */ + +#ifndef PIPELINE_STORAGE_CHUNKS_H +#define PIPELINE_STORAGE_CHUNKS_H +#include + +// STL includes + +// NeL includes +#include + +// Project includes + +namespace PIPELINE { +namespace MAX { + +/** + * \brief CStorageChunks + * \date 2012-08-18 09:20GMT + * \author Jan Boon (Kaetemi) + * CStorageChunks + */ +class CStorageChunks +{ +private: + struct CChunk + { + // Size of the chunk header, 6 for 32 bit, 14 for 64 bit + uint8 HeaderSize; + // Where the header starts + sint32 OffsetBegin; + + // Identifier + uint16 Id; + // Size including header size + uint32 Size; + + inline sint32 getSizeWithHeader() const { return (sint32)(Size & 0x7FFFFFFF); } + inline sint32 getSize() const { return getSizeWithHeader() - (sint32)HeaderSize; } + inline bool isContainer() const { return (Size & 0x80000000) == 0x80000000; } + inline sint32 endOfChunk() const { return OffsetBegin + getSizeWithHeader(); } + inline sint32 getDataBegin() const { return OffsetBegin + (sint32)HeaderSize; } + }; + +public: + CStorageChunks(NLMISC::IStream &stream, sint64 size = 0); + virtual ~CStorageChunks(); + + // Returns true if there's another chunk, false if no more chunks in this container or if the current chunk is not a container + bool enterChunk(); + // Reads and skips chunks until the one with given id is found, or writes a chunk with this id + bool enterChunk(uint16 id, bool container); + // Returns the number of skipped bytes in read more, returns chunk size including header in write mode + sint32 leaveChunk(); + + inline bool is64Bit() const { return m_Is64Bit; } + inline void set64Bit(bool enabled = true) { m_Is64Bit = enabled; } + + inline uint16 getChunkId() const { return currentChunk()->Id; } + inline sint32 getChunkSize() const { return currentChunk()->getSize(); } + inline bool isChunkContainer() const { return currentChunk()->isContainer(); } + inline bool endOfChunk() const { return /*m_Chunks.size() == 1 ? eof() :*/ m_Stream.getPos() >= currentChunk()->endOfChunk(); } + + inline NLMISC::IStream &stream() { return m_Stream; } + +private: + inline const CChunk *currentChunk() const { return &m_Chunks[m_Chunks.size() - 1]; } + inline CChunk *currentChunk() { return &m_Chunks[m_Chunks.size() - 1]; } + +private: + NLMISC::IStream &m_Stream; + std::vector m_Chunks; + bool m_Is64Bit; + +}; /* class CStorageChunks */ + +} /* namespace MAX */ +} /* namespace PIPELINE */ + +#endif /* #ifndef PIPELINE_STORAGE_CHUNKS_H */ + +/* end of file */ diff --git a/code/nel/tools/pipeline/max/storage_object.cpp b/code/nel/tools/pipeline/max/storage_object.cpp new file mode 100644 index 000000000..2de47052b --- /dev/null +++ b/code/nel/tools/pipeline/max/storage_object.cpp @@ -0,0 +1,236 @@ +/** + * \file storage_object.cpp + * \brief CStorageObject + * \date 2012-08-18 09:02GMT + * \author Jan Boon (Kaetemi) + * CStorageObject + */ + +/* + * Copyright (C) 2012 by authors + * + * This file is part of RYZOM CORE PIPELINE. + * RYZOM CORE PIPELINE is free software: you can redistribute it + * and/or modify it under the terms of the GNU Affero General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * RYZOM CORE PIPELINE is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with RYZOM CORE PIPELINE. If not, see + * . + */ + +#include +#include "storage_object.h" + +// STL includes +#include + +// NeL includes +// #include + +// Project includes +#include "storage_stream.h" +#include "storage_chunks.h" + +// using namespace std; +// using namespace NLMISC; + +#define NL_DEBUG_STORAGE + +namespace PIPELINE { +namespace MAX { + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +std::string IStorageObject::toString() +{ + std::stringstream ss; + toString(ss); + return ss.str(); +} + +void IStorageObject::setSize(sint32 size) +{ + // ignore +} + +bool IStorageObject::getSize(sint32 &size) const +{ + return false; +} + +bool IStorageObject::isContainer() const +{ + return false; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +std::string CStorageContainer::getClassName() // why is this not const in IClassable? +{ + return "StorageContainer"; +} + +void CStorageContainer::serial(NLMISC::IStream &stream) +{ + if (stream.getPos() == 0) + { + CStorageStream *storageStream = dynamic_cast(&stream); + if (storageStream) + { + // implicitly assume the entire stream is the container + CStorageChunks chunks(stream, stream.isReading() ? storageStream->size() : 0); + serial(chunks); + return; + } + } + // wrapping the container inside a stream with necessary size markers + { + const uint32 magic = 0xC0C01473; + stream.serialCheck(magic); + uint version = stream.serialVersion(1); + sint32 sizePos; + bool reading = stream.isReading(); + if (!reading) + sizePos = stream.getPos(); + sint64 size = 0; + stream.serial(size); + CStorageChunks chunks(stream, size); + serial(chunks); + if (!reading) + { + sint32 returnPos = stream.getPos(); + stream.seek(sizePos, NLMISC::IStream::begin); + stream.serial(size); + stream.seek(returnPos, NLMISC::IStream::begin); + } + return; + } +} + +void CStorageContainer::toString(std::ostream &ostream, const std::string &pad) +{ + // note: only use pad when multi-lining + // like Blah: (Something) "SingleValue" + // Blahblah: (Container) { + // Moo: (Foo) "What" } + // only increase pad when multi-lining sub-items + ostream << "(" << getClassName() << ") { "; + std::string padpad = pad + "\t"; + for (TStorageObjectContainer::const_iterator it = Chunks.begin(), end = Chunks.end(); it != end; ++it) + { + std::stringstream ss; + ss << std::hex << std::setfill('0'); + ss << std::setw(4) << it->first; + ostream << "\n" << pad << "0x" << ss.str() << ": "; + it->second->toString(ostream, padpad); + } + ostream << "} "; +} + +bool CStorageContainer::isContainer() const +{ + return true; +} + +void CStorageContainer::serial(CStorageChunks &chunks) +{ + if (chunks.stream().isReading()) + { +#ifdef NL_DEBUG_STORAGE + if (Chunks.size()) + { + nldebug("Storage container not empty, clearing"); + } +#endif + Chunks.clear(); + while (chunks.enterChunk()) + { + uint16 id = chunks.getChunkId(); + IStorageObject *storageObject = createChunkById(id, chunks.isChunkContainer()); + storageObject->setSize(chunks.getChunkSize()); + if (storageObject->isContainer()) static_cast(storageObject)->serial(chunks); + else storageObject->serial(chunks.stream()); + Chunks.push_back(TStorageObjectWithId(id, storageObject)); + if (chunks.leaveChunk()) // bytes were skipped while reading + throw EStorage(); + } + } + else + { + for (TStorageObjectContainer::iterator it = Chunks.begin(), end = Chunks.end(); it != end; ++it) + { + chunks.enterChunk(it->first, it->second->isContainer()); + it->second->serial(chunks.stream()); + chunks.leaveChunk(); + } + } +} + +IStorageObject *CStorageContainer::createChunkById(uint16 id, bool container) +{ + if (container) + { + return new CStorageContainer(); + } + else + { + return new CStorageRaw(); + } +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +std::string CStorageRaw::getClassName() +{ + return "StorageRaw"; +} + +void CStorageRaw::serial(NLMISC::IStream &stream) +{ + stream.serialBuffer(&Value[0], Value.size()); +} + +void CStorageRaw::toString(std::ostream &ostream, const std::string &pad) +{ + // note: only use pad when multi-lining + // like Blah: (Something) "SingleValue" + // Blahblah: (Container) { + // Moo: (Foo) "What" } + // only increase pad when multi-lining sub-items + ostream << "(" << getClassName() << ") { "; + + ostream << "} "; +} + +void CStorageRaw::setSize(sint32 size) +{ + Value.resize(size); +} + +bool CStorageRaw::getSize(sint32 &size) const +{ + size = Value.size(); + return true; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +} /* namespace MAX */ +} /* namespace PIPELINE */ + +/* end of file */ diff --git a/code/nel/tools/pipeline/max/storage_object.h b/code/nel/tools/pipeline/max/storage_object.h new file mode 100644 index 000000000..d6a141964 --- /dev/null +++ b/code/nel/tools/pipeline/max/storage_object.h @@ -0,0 +1,143 @@ +/** + * \file storage_object.h + * \brief CStorageObject + * \date 2012-08-18 09:02GMT + * \author Jan Boon (Kaetemi) + * CStorageObject + */ + +/* + * Copyright (C) 2012 by authors + * + * This file is part of RYZOM CORE PIPELINE. + * RYZOM CORE PIPELINE is free software: you can redistribute it + * and/or modify it under the terms of the GNU Affero General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * RYZOM CORE PIPELINE is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with RYZOM CORE PIPELINE. If not, see + * . + */ + +#ifndef PIPELINE_STORAGE_OBJECT_H +#define PIPELINE_STORAGE_OBJECT_H +#include + +// STL includes +#include + +// NeL includes +#include + +// Project includes + +namespace PIPELINE { +namespace MAX { + class CStorageChunks; + +struct EStorage : public NLMISC::Exception +{ + EStorage() : NLMISC::Exception("PIPELINE::MAX::EStorage") { } + virtual ~EStorage() throw() { } +}; + +// IStorageObject : exposes serial(CStorageStream &stream) and dump(const std::string &pad) +class IStorageObject : public NLMISC::IStreamable +{ +public: + // virtual std::string getClassName() = 0; // inherited from NLMISC::IClassable through NLMISC::IStreamable + // virtual void serial(NLMISC::IStream &stream); // inherited from NLMISC::IStreamable + std::string toString(); + virtual void toString(std::ostream &ostream, const std::string &pad = "") = 0; + +public: // should be protected but that doesn't compile, nice c++! + // Sets size when reading + virtual void setSize(sint32 size); + // Gets the size when writing, return false if unknown + virtual bool getSize(sint32 &size) const; + // Only true when inherting from CStorageContainer + virtual bool isContainer() const; +}; + +// CStorageContainer : serializes a container chunk +class CStorageContainer : public IStorageObject +{ +public: + // public data + typedef std::pair TStorageObjectWithId; + typedef std::vector TStorageObjectContainer; + TStorageObjectContainer Chunks; + + // inherited + virtual std::string getClassName(); + virtual void serial(NLMISC::IStream &stream); // only used to wrap a container inside another stream + virtual void toString(std::ostream &ostream, const std::string &pad = ""); + +public: // should be protected but that doesn't compile, nice c++! + // inherited + virtual bool isContainer() const; + +protected: + // override in subclasses, default to parent if not handled + virtual void serial(CStorageChunks &chunks); + virtual IStorageObject *createChunkById(uint16 id, bool container); +}; + +// CStorageRaw : serializes raw data, use for unknown data +class CStorageRaw : public IStorageObject +{ +public: + // public data + typedef std::vector TType; + TType Value; + + // inherited + virtual std::string getClassName(); + virtual void serial(NLMISC::IStream &stream); + virtual void toString(std::ostream &ostream, const std::string &pad = ""); + +public: // should be protected but that doesn't compile, nice c++! + // Sets size when reading + virtual void setSize(sint32 size); + // Gets the size when writing, return false if unknown + virtual bool getSize(sint32 &size) const; +}; +/* +// CStorageUCString : serializes an ucstring chunk +class CStorageUCString : public ucstring, public IStorageObject +{ +public: + virtual void serial(CStorageStream *stream); + virtual void dump(const std::string &pad); +}; + +// CStorageString : serializes a string chunk +class CStorageString : public std::string, public IStorageObject +{ +public: + virtual void serial(CStorageStream *stream); + virtual void dump(const std::string &pad); +}; + +template +class CStorageValue : public IStorageObject +{ +public: + T Value; + virtual void serial(CStorageStream *stream); + virtual void dump(const std::string &pad); +}; +*/ + +} /* namespace MAX */ +} /* namespace PIPELINE */ + +#endif /* #ifndef PIPELINE_STORAGE_OBJECT_H */ + +/* end of file */ diff --git a/code/nel/tools/pipeline/max/storage_stream.cpp b/code/nel/tools/pipeline/max/storage_stream.cpp index cb6253e18..e0651d826 100644 --- a/code/nel/tools/pipeline/max/storage_stream.cpp +++ b/code/nel/tools/pipeline/max/storage_stream.cpp @@ -39,30 +39,22 @@ // Project includes -using namespace std; +// using namespace std; // using namespace NLMISC; -// #define NL_DEBUG_STORAGE_STREAM +// #define NL_DEBUG_STORAGE namespace PIPELINE { namespace MAX { -CStorageStream::CStorageStream(GsfInput *input) : NLMISC::IStream(true), m_Input(input), m_Output(NULL), m_Is64Bit(false) +CStorageStream::CStorageStream(GsfInput *input) : NLMISC::IStream(true), m_Input(input), m_Output(NULL) { - m_Chunks.reserve(64); - m_Chunks.resize(1); - m_Chunks[0].OffsetBegin = -6; - m_Chunks[0].Id = 0; - m_Chunks[0].Size = 0x80000000; + } -CStorageStream::CStorageStream(GsfOutput *output) : NLMISC::IStream(true), m_Input(NULL), m_Output(output), m_Is64Bit(false) +CStorageStream::CStorageStream(GsfOutput *output) : NLMISC::IStream(false), m_Input(NULL), m_Output(output) { - m_Chunks.reserve(64); - m_Chunks.resize(1); - m_Chunks[0].OffsetBegin = -6; - m_Chunks[0].Id = 1; // in write mode, id flags a container - m_Chunks[0].Size = 0; + } CStorageStream::~CStorageStream() @@ -120,7 +112,7 @@ void CStorageStream::serialBuffer(uint8 *buf, uint len) { if (!len) { -#ifdef NL_DEBUG_STORAGE_STREAM +#ifdef NL_DEBUG_STORAGE nldebug("Serial 0 size buffer"); #endif return; @@ -129,7 +121,7 @@ void CStorageStream::serialBuffer(uint8 *buf, uint len) { if (!gsf_input_read(m_Input, len, buf)) { -#ifdef NL_DEBUG_STORAGE_STREAM +#ifdef NL_DEBUG_STORAGE nldebug("Cannot read from input, throw exception"); #endif throw NLMISC::EStream(); @@ -139,7 +131,7 @@ void CStorageStream::serialBuffer(uint8 *buf, uint len) { if (!gsf_output_write(m_Output, len, buf)) { -#ifdef NL_DEBUG_STORAGE_STREAM +#ifdef NL_DEBUG_STORAGE nldebug("Cannot write to output, throw exception"); #endif throw NLMISC::EStream(); @@ -147,7 +139,7 @@ void CStorageStream::serialBuffer(uint8 *buf, uint len) } else { -#ifdef NL_DEBUG_STORAGE_STREAM +#ifdef NL_DEBUG_STORAGE nldebug("No input or output, should not happen, throw exception"); #endif throw NLMISC::EStream(); @@ -169,132 +161,29 @@ bool CStorageStream::eof() } else { -#ifdef NL_DEBUG_STORAGE_STREAM +#ifdef NL_DEBUG_STORAGE nldebug("No input, this function cannot output, throw exception"); #endif throw NLMISC::EStream(); } } -bool CStorageStream::enterChunk() +sint32 CStorageStream::size() { if (m_Input) { - // input logic - if (!isChunkContainer()) - { -#ifdef NL_DEBUG_STORAGE_STREAM - nldebug("Current chunk is not a container, cannot enter"); -#endif - return false; - } - if (endOfChunk()) - { -#ifdef NL_DEBUG_STORAGE_STREAM - nldebug("End of chunk, cannot enter"); -#endif - return false; - } - m_Chunks.resize(m_Chunks.size() + 1); - CChunk *chunk = currentChunk(); - chunk->OffsetBegin = CStorageStream::getPos(); - serial(chunk->Id); - serial(chunk->Size); - chunk->HeaderSize = 6; - if (chunk->Size == 0) - { - // this is a 64bit chunk - uint64 size64; - serial(size64); - chunk->HeaderSize += 8; - bool iscont = (size64 & 0x8000000000000000) == 0x8000000000000000; - size64 &= 0x7FFFFFFFFFFFFFFF; - if (size64 >= 2147483647L) - throw NLMISC::EStream("64bit chunks not supported"); - // downgrade to 32 bit chunk - chunk->Size = (uint32)size64; - if (iscont) chunk->Size |= 0x80000000; - m_Is64Bit = true; // it's true - } - return true; + gsf_off_t res = gsf_input_size(m_Input); + if (res < 2147483647L) // exception when larger + return (sint32)res; } else { -#ifdef NL_DEBUG_STORAGE_STREAM +#ifdef NL_DEBUG_STORAGE nldebug("No input, this function cannot output, throw exception"); #endif throw NLMISC::EStream(); } -} - -bool CStorageStream::enterChunk(uint16 id) -{ - if (m_Output) - { - if (m_Is64Bit) - throw NLMISC::EStream("64bit chunks not supported"); - - // current chunk is a container - currentChunk()->Id = 1; // in write mode, id flags a container - - // enter the new chunk - m_Chunks.resize(m_Chunks.size() + 1); - CChunk *chunk = currentChunk(); - chunk->Id = 0; // don't know if it's a container - uint32 sizeDummy = 0xFFFFFFFF; - chunk->OffsetBegin = getPos(); // store current pos - - // write header - serial(id); // write the id - serial(sizeDummy); // write 32 bit size placeholder - } - else // input or exception - { - while (enterChunk()) - { - if (getChunkId() == id) - return true; - leaveChunk(); // skip data - } - return false; - } -} - -sint32 CStorageStream::leaveChunk() -{ - if (m_Input) - { - // input logic - sint32 skipped = currentChunk()->endOfChunk() - CStorageStream::getPos(); - if (skipped) - { - CStorageStream::seek(currentChunk()->endOfChunk(), begin); -#ifdef NL_DEBUG_STORAGE_STREAM - nldebug("Skipped %i bytes in the current chunk", skipped); -#endif - } - m_Chunks.resize(m_Chunks.size() - 1); - return skipped; - } - else if (m_Output) - { - sint32 pos = getPos(); - sint32 sizeWithHeader = pos - currentChunk()->OffsetBegin; - sint32 sizePos = currentChunk()->OffsetBegin + 2; - seek(sizePos, begin); // hopefully this correctly overwrites!!! - uint32 sizeField = (uint32)sizeWithHeader | (uint32)currentChunk()->Id << 31; // add container flag - serial(sizeField); - seek(pos, begin); - m_Chunks.resize(m_Chunks.size() - 1); - return sizeWithHeader; - } - else - { -#ifdef NL_DEBUG_STORAGE_STREAM - nldebug("No input or output, should not happen, throw exception"); -#endif - throw NLMISC::EStream(); - } + throw NLMISC::EStream(); } } /* namespace MAX */ diff --git a/code/nel/tools/pipeline/max/storage_stream.h b/code/nel/tools/pipeline/max/storage_stream.h index c1c0e41b0..e50a611d0 100644 --- a/code/nel/tools/pipeline/max/storage_stream.h +++ b/code/nel/tools/pipeline/max/storage_stream.h @@ -52,26 +52,6 @@ namespace MAX { */ class CStorageStream : public NLMISC::IStream { -private: - struct CChunk - { - // Size of the chunk header, 6 for 32 bit, 14 for 64 bit - uint8 HeaderSize; - // Where the header starts - sint32 OffsetBegin; - - // Identifier - uint16 Id; - // Size including header size - uint32 Size; - - inline sint32 getSizeWithHeader() { return (sint32)(Size & 0x7FFFFFFF); } - inline sint32 getSize() { return getSizeWithHeader() - (sint32)HeaderSize; } - inline bool isContainer() { return (Size & 0x80000000) == 0x80000000; } - inline sint32 endOfChunk() { return OffsetBegin + getSizeWithHeader(); } - inline sint32 getDataBegin() { return OffsetBegin + (sint32)HeaderSize; } - }; - public: CStorageStream(GsfInput *input); CStorageStream(GsfOutput *output); @@ -83,31 +63,12 @@ public: virtual void serialBuffer(uint8 *buf, uint len); virtual void serialBit(bool &bit); + sint32 size(); bool eof(); - // Returns true if there's another chunk, false if no more chunks in this container or if the current chunk is not a container - bool enterChunk(); - // Reads and skips chunks until the one with given id is found, or writes a chunk with this id - bool enterChunk(uint16 id); - // Returns the number of skipped bytes in read more, returns chunk size including header in write mode - sint32 leaveChunk(); - - inline bool is64Bit() const { return m_Is64Bit; } - inline void set64Bit(bool enabled = true) { m_Is64Bit = enabled; } - - inline uint16 getChunkId() { return currentChunk()->Id; } - inline sint32 getChunkSize() { return currentChunk()->getSize(); } - inline bool isChunkContainer() { return currentChunk()->isContainer(); } - inline bool endOfChunk() { return m_Chunks.size() == 1 ? eof() : CStorageStream::getPos() >= currentChunk()->endOfChunk(); } - -private: - inline CChunk *currentChunk() { return &m_Chunks[m_Chunks.size() - 1]; } - private: GsfInput *m_Input; GsfOutput *m_Output; - std::vector m_Chunks; - bool m_Is64Bit; /* there exist compressed max files, so maybe we will need this at some point GsfInput * gsf_input_uncompress (GsfInput *src); diff --git a/code/nel/tools/pipeline/max_dump/main.cpp b/code/nel/tools/pipeline/max_dump/main.cpp index 7ffe984dd..e7669306f 100644 --- a/code/nel/tools/pipeline/max_dump/main.cpp +++ b/code/nel/tools/pipeline/max_dump/main.cpp @@ -11,11 +11,13 @@ #include #include #include +#include #include #include #include "../max/storage_stream.h" +#include "../max/storage_object.h" //static const char *filename = "/srv/work/database/interfaces/anims_max/cp_fy_hof_species.max"; static const char *filename = "/home/kaetemi/source/minimax/GE_Acc_MikotoBaniere.max"; @@ -32,75 +34,7 @@ inline uint8 cleanChar(uint8 c) namespace PIPELINE { namespace MAX { -struct EStorage : public NLMISC::Exception -{ - EStorage() : NLMISC::Exception("PIPELINE::MAX::EStorage") { } - virtual ~EStorage() throw() { } -}; - -// IStorageObject : exposes serial(CStorageStream *stream) and dump(const std::string &pad) -class IStorageObject -{ -public: - virtual void serial(CStorageStream *stream) = 0; - virtual void dump(const std::string &pad) = 0; -}; - -class IStorageStreamable : public NLMISC::IStreamable, public IStorageObject -{ -public: - virtual void serial(CStorageStream *stream); - virtual void serial(NLMISC::IStream &stream) = 0; -}; -void IStorageStreamable::serial(CStorageStream *stream) -{ - serial(*((NLMISC::IStream *)stream)); -} - -// CStorageContainer : serializes a container chunk -class CStorageContainer : public std::vector >, public IStorageObject -{ -public: - virtual void serial(CStorageStream *stream); - virtual void dump(const std::string &pad); - - // override in subclasses, call parent if not handled - virtual IStorageObject *serialChunk(CStorageStream *stream); -}; - -// CStorageRaw : serializes raw data, use for unknown data -class CStorageRaw : public std::vector, public IStorageObject -{ -public: - virtual void serial(CStorageStream *stream); - virtual void dump(const std::string &pad); -}; - -// CStorageUCString : serializes an ucstring chunk -class CStorageUCString : public ucstring, public IStorageObject -{ -public: - virtual void serial(CStorageStream *stream); - virtual void dump(const std::string &pad); -}; - -// CStorageString : serializes a string chunk -class CStorageString : public std::string, public IStorageObject -{ -public: - virtual void serial(CStorageStream *stream); - virtual void dump(const std::string &pad); -}; - -template -class CStorageValue : public IStorageObject -{ -public: - T Value; - virtual void serial(CStorageStream *stream); - virtual void dump(const std::string &pad); -}; - +/* struct CClass_ID : public NLMISC::IStreamable { uint32 A; @@ -145,21 +79,7 @@ std::string CClassDirectoryHeader::getClassName() void CStorageContainer::serial(CStorageStream *stream) { - if (stream->isReading()) - { - while (stream->enterChunk()) - { - uint16 id = stream->getChunkId(); - IStorageObject *storageObject = serialChunk(stream); - push_back(std::pair(id, storageObject)); - if (stream->leaveChunk()) // bytes were skipped while reading - throw EStorage(); - } - } - else - { - throw EStorage(); - } + } IStorageObject *CStorageContainer::serialChunk(CStorageStream *stream) { @@ -291,10 +211,10 @@ void CStorageValue::dump(const std::string &pad) std::string valstr = NLMISC::toString(Value); printf("%s%s\n", pad.c_str(), valstr.c_str()); } - +*/ } } - +/* static void dumpData(PIPELINE::MAX::CStorageStream *in, const std::string &pad) { sint32 size = in->getChunkSize(); @@ -336,7 +256,7 @@ static void dumpContainer(PIPELINE::MAX::CStorageStream *in, const std::string & printf("%sSKIPPED: %i\n", pad.c_str(), skipped); } } - +*/ // int __stdcall WinMain(void *, void *, void *, int) int main(int argc, char **argv) { @@ -382,13 +302,16 @@ int main(int argc, char **argv) g_print("%s\n", streamname); GsfInput *input = gsf_infile_child_by_name(infile, streamname); - //gsf_input_dump(input, 1); // just a regular hex dump of this input stream - PIPELINE::MAX::CStorageStream *instream = new PIPELINE::MAX::CStorageStream(input); - dumpContainer(instream, ""); - //PIPELINE::MAX::CStorageContainer ctr; - //ctr.serial(instream); - //ctr.dump(""); - delete instream; + + { + //gsf_input_dump(input, 1); // just a regular hex dump of this input stream + PIPELINE::MAX::CStorageStream instream(input); + //dumpContainer(instream, ""); + PIPELINE::MAX::CStorageContainer ctr; + ctr.serial(instream); + ctr.toString(std::cout); + //ctr.dump(""); + } g_object_unref(input); g_object_unref(infile);