From 4b1a310dfb2ec1facc9627e797bfb2f83f82017c Mon Sep 17 00:00:00 2001 From: kaetemi Date: Sat, 18 Aug 2012 10:26:07 +0200 Subject: [PATCH] Added: #1440 Max file utility library --HG-- branch : build_pipeline_v3 --- code/nel/tools/pipeline/CMakeLists.txt | 1 + code/nel/tools/pipeline/max/CMakeLists.txt | 39 +++ .../nel/tools/pipeline/max/storage_stream.cpp | 236 ++++++++++++++++++ code/nel/tools/pipeline/max/storage_stream.h | 121 +++++++++ .../tools/pipeline/max_dump/CMakeLists.txt | 1 + code/nel/tools/pipeline/max_dump/info.txt | 8 +- code/nel/tools/pipeline/max_dump/main.cpp | 14 +- .../pipeline/max_dump/storage_stream.cpp | 4 +- .../tools/pipeline/max_dump/storage_stream.h | 4 +- 9 files changed, 413 insertions(+), 15 deletions(-) create mode 100644 code/nel/tools/pipeline/max/CMakeLists.txt create mode 100644 code/nel/tools/pipeline/max/storage_stream.cpp create mode 100644 code/nel/tools/pipeline/max/storage_stream.h diff --git a/code/nel/tools/pipeline/CMakeLists.txt b/code/nel/tools/pipeline/CMakeLists.txt index 4fd5f159a..719c0a6e3 100644 --- a/code/nel/tools/pipeline/CMakeLists.txt +++ b/code/nel/tools/pipeline/CMakeLists.txt @@ -1,4 +1,5 @@ SUBDIRS( + max max_dump plugin_library plugin_nel diff --git a/code/nel/tools/pipeline/max/CMakeLists.txt b/code/nel/tools/pipeline/max/CMakeLists.txt new file mode 100644 index 000000000..4f4b5b5ac --- /dev/null +++ b/code/nel/tools/pipeline/max/CMakeLists.txt @@ -0,0 +1,39 @@ + +FIND_PACKAGE(LIBGSF) + +IF (NOT (LIBGSF_INCLUDE_DIR AND LIBGSF_LIBRARIES)) + MESSAGE(FATAL_ERROR "LIBGSF not found!") +ENDIF (NOT (LIBGSF_INCLUDE_DIR AND LIBGSF_LIBRARIES)) + +FIND_PACKAGE(GLIB2) + +if (NOT GLIB2_FOUND) + MESSAGE(FATAL_ERROR "GLIB2 not found!") +ENDIF (NOT GLIB2_FOUND) + +INCLUDE_DIRECTORIES(${GLIB2_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(${LIBGSF_INCLUDE_DIR}) + +FILE(GLOB SRCS *.cpp) +FILE(GLOB HDRS *.h) + +NL_TARGET_LIB(pipeline_max + ${SRCS} + ${HDRS} + ) + +TARGET_LINK_LIBRARIES(pipeline_max + ${LIBGSF_LIBRARIES} + ${GLIB2_LIBRARIES} + nelmisc +) + +SET_TARGET_PROPERTIES(pipeline_max PROPERTIES LINK_INTERFACE_LIBRARIES "") + +NL_DEFAULT_PROPS(pipeline_max "NeL, Tools, Pipeline: Max (Library)") +NL_ADD_LIB_SUFFIX(pipeline_max) +NL_ADD_RUNTIME_FLAGS(pipeline_max) + +IF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC) + INSTALL(TARGETS pipeline_max LIBRARY DESTINATION lib ARCHIVE DESTINATION lib COMPONENT libraries) +ENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC) diff --git a/code/nel/tools/pipeline/max/storage_stream.cpp b/code/nel/tools/pipeline/max/storage_stream.cpp new file mode 100644 index 000000000..35ac771a8 --- /dev/null +++ b/code/nel/tools/pipeline/max/storage_stream.cpp @@ -0,0 +1,236 @@ +/** + * \file storage_stream.cpp + * \brief CStorageStream + * \date 2012-08-16 22:06GMT + * \author Jan Boon (Kaetemi) + * CStorageStream + */ + +/* + * 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_stream.h" + +// STL includes + +// 3rd Party includes +#include + +// NeL includes +// #include + +// Project includes + +using namespace std; +// using namespace NLMISC; + +// #define NL_DEBUG_STORAGE_STREAM + +namespace PIPELINE { +namespace MAX { + +CStorageStream::CStorageStream(GsfInput *input) : NLMISC::IStream(true), m_Input(input), m_Output(NULL), m_Is64Bit(false) +{ + 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() +{ + +} + +bool CStorageStream::seek(sint32 offset, NLMISC::IStream::TSeekOrigin origin) const +{ + if (m_Input) + { + switch (origin) + { + case begin: + return gsf_input_seek(m_Input, offset, G_SEEK_SET); + case current: + return gsf_input_seek(m_Input, offset, G_SEEK_CUR); + case end: + return gsf_input_seek(m_Input, offset, G_SEEK_END); + } + } + return NLMISC::IStream::seek(offset, origin); +} + +sint32 CStorageStream::getPos() const +{ + if (m_Input) + { + gsf_off_t res = gsf_input_tell(m_Input); + if (res < 2147483647L) // exception when larger + return (sint32)res; + } + return NLMISC::IStream::getPos(); +} + +void CStorageStream::serialBuffer(uint8 *buf, uint len) +{ + if (!len) + { +#ifdef NL_DEBUG_STORAGE_STREAM + nldebug("Serial 0 size buffer"); +#endif + return; + } + if (m_Input) + { + if (!gsf_input_read(m_Input, len, buf)) + { +#ifdef NL_DEBUG_STORAGE_STREAM + nldebug("Cannot read from input, throw exception"); +#endif + throw NLMISC::EStream(); + } + } + else if (m_Output) + { + throw NLMISC::EStream(); // not yet implemented + } + else + { +#ifdef NL_DEBUG_STORAGE_STREAM + nldebug("No input or output, should not happen, throw exception"); +#endif + throw NLMISC::EStream(); + } +} + +void CStorageStream::serialBit(bool &bit) +{ + uint8 var = (uint8)bit; + serial(var); + bit = (bool)var; +} + +bool CStorageStream::eof() +{ + return gsf_input_eof(m_Input); +} + +bool CStorageStream::enterChunk() +{ + 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; + } + else + { +#ifdef NL_DEBUG_STORAGE_STREAM + nldebug("No input, this function cannot output, throw exception"); +#endif + throw NLMISC::EStream(); + } +} + +bool CStorageStream::enterChunk(uint16 id) +{ + if (m_Output) + { + throw NLMISC::EStream(); // not yet implemented + } + 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) + { + throw NLMISC::EStream(); // not yet implemented + } + else + { +#ifdef NL_DEBUG_STORAGE_STREAM + nldebug("No input or output, should not happen, throw exception"); +#endif + throw NLMISC::EStream(); + } +} + +} /* namespace MAX */ +} /* namespace PIPELINE */ + +/* end of file */ diff --git a/code/nel/tools/pipeline/max/storage_stream.h b/code/nel/tools/pipeline/max/storage_stream.h new file mode 100644 index 000000000..46a342752 --- /dev/null +++ b/code/nel/tools/pipeline/max/storage_stream.h @@ -0,0 +1,121 @@ +/** + * \file storage_stream.h + * \brief CStorageStream + * \date 2012-08-16 22:06GMT + * \author Jan Boon (Kaetemi) + * CStorageStream + */ + +/* + * 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_STREAM_H +#define PIPELINE_STORAGE_STREAM_H +#include + +// STL includes +#include + +// 3rd Party includes +#include + +// NeL includes +#include + +// Project includes + +namespace PIPELINE { +namespace MAX { + +/** + * \brief CStorageStream + * \date 2012-08-16 22:06GMT + * \author Jan Boon (Kaetemi) + * CStorageStream + */ +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); + virtual ~CStorageStream(); + + virtual bool seek(sint32 offset, TSeekOrigin origin) const; + virtual sint32 getPos() const; + // virtual std::string getStreamName() const; // char const * gsf_input_name (GsfInput *input); + virtual void serialBuffer(uint8 *buf, uint len); + virtual void serialBit(bool &bit); + + 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; + void *m_Output; // todo + 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); +*/ + +}; /* class CStorageStream */ + +} /* namespace MAX */ +} /* namespace PIPELINE */ + +#endif /* #ifndef PIPELINE_STORAGE_STREAM_H */ + +/* end of file */ diff --git a/code/nel/tools/pipeline/max_dump/CMakeLists.txt b/code/nel/tools/pipeline/max_dump/CMakeLists.txt index 0a7c617cd..742d5684e 100644 --- a/code/nel/tools/pipeline/max_dump/CMakeLists.txt +++ b/code/nel/tools/pipeline/max_dump/CMakeLists.txt @@ -25,6 +25,7 @@ ADD_EXECUTABLE(pipeline_max_dump TARGET_LINK_LIBRARIES(pipeline_max_dump ${LIBGSF_LIBRARIES} ${GLIB2_LIBRARIES} + pipeline_max nelmisc ) diff --git a/code/nel/tools/pipeline/max_dump/info.txt b/code/nel/tools/pipeline/max_dump/info.txt index 54a3e0e80..0cd24f236 100644 --- a/code/nel/tools/pipeline/max_dump/info.txt +++ b/code/nel/tools/pipeline/max_dump/info.txt @@ -37,17 +37,17 @@ f 2320 DocumentSummaryInformation kaetemi@benzaiten ~/source/minimax/build $ gsf dump /home/kaetemi/source/minimax/GE_Acc_MikotoBaniere.max VideoPostQueue VideoPostQueue [ - 50 00 (id: 80) + 50 00 (id: 0x0050) 0a 00 00 00 (size: 10 - 6 = 4) [ 01 00 00 00 (value: 1) ] ] [ - 60 00 (id: 96) + 60 00 (id: 0x0060) 2a 00 00 80 (size: 42 - 6 = 36) (note: negative bit = container) [ - 10 00 (id: 16) + 10 00 (id: 0x0010) 1e 00 00 00 (size: 30 - 6 = 24) [ 07 00 00 00 (value: 7) @@ -57,7 +57,7 @@ VideoPostQueue 20 12 00 00 (value: 4610) 00 00 00 00 ] - 20 00 (id: 32) + 20 00 (id: 0x0020) 06 00 00 00 (size: 6 - 6 = 0) ] ] diff --git a/code/nel/tools/pipeline/max_dump/main.cpp b/code/nel/tools/pipeline/max_dump/main.cpp index 9443c4561..7ffe984dd 100644 --- a/code/nel/tools/pipeline/max_dump/main.cpp +++ b/code/nel/tools/pipeline/max_dump/main.cpp @@ -15,13 +15,13 @@ #include #include -#include "storage_stream.h" +#include "../max/storage_stream.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"; -static const char *filename = "/home/kaetemi/3dsMax/scenes/test2008.max"; +static const char *filename = "/home/kaetemi/source/minimax/GE_Acc_MikotoBaniere.max"; +//static const char *filename = "/home/kaetemi/3dsMax/scenes/test2008.max"; //static const char *filename = "/home/kaetemi/3dsMax/scenes/teapot_test_scene.max"; -static const char *streamname = "Scene"; +static const char *streamname = "DllDirectory"; inline uint8 cleanChar(uint8 c) { @@ -295,7 +295,7 @@ void CStorageValue::dump(const std::string &pad) } } -static void dumpData(PIPELINE::CStorageStream *in, const std::string &pad) +static void dumpData(PIPELINE::MAX::CStorageStream *in, const std::string &pad) { sint32 size = in->getChunkSize(); std::vector buffer; @@ -319,7 +319,7 @@ static void dumpData(PIPELINE::CStorageStream *in, const std::string &pad) } } -static void dumpContainer(PIPELINE::CStorageStream *in, const std::string &pad) +static void dumpContainer(PIPELINE::MAX::CStorageStream *in, const std::string &pad) { while (in->enterChunk()) { @@ -383,7 +383,7 @@ int main(int argc, char **argv) GsfInput *input = gsf_infile_child_by_name(infile, streamname); //gsf_input_dump(input, 1); // just a regular hex dump of this input stream - PIPELINE::CStorageStream *instream = new PIPELINE::CStorageStream(input); + PIPELINE::MAX::CStorageStream *instream = new PIPELINE::MAX::CStorageStream(input); dumpContainer(instream, ""); //PIPELINE::MAX::CStorageContainer ctr; //ctr.serial(instream); diff --git a/code/nel/tools/pipeline/max_dump/storage_stream.cpp b/code/nel/tools/pipeline/max_dump/storage_stream.cpp index e6bfab12e..3dbe005f8 100644 --- a/code/nel/tools/pipeline/max_dump/storage_stream.cpp +++ b/code/nel/tools/pipeline/max_dump/storage_stream.cpp @@ -42,7 +42,7 @@ using namespace std; // using namespace NLMISC; namespace PIPELINE { - +#if 0 CStorageStream::CStorageStream(GsfInput *input) : NLMISC::IStream(true), m_Input(input) { m_RootChunk.OffsetBegin = -6; @@ -168,7 +168,7 @@ void CStorageStream::findChunkById(uint16 id) { } - +#endif } /* namespace PIPELINE */ /* end of file */ diff --git a/code/nel/tools/pipeline/max_dump/storage_stream.h b/code/nel/tools/pipeline/max_dump/storage_stream.h index adf3c5968..0cb2807a5 100644 --- a/code/nel/tools/pipeline/max_dump/storage_stream.h +++ b/code/nel/tools/pipeline/max_dump/storage_stream.h @@ -41,7 +41,7 @@ // Project includes namespace PIPELINE { - +#if 0 struct CChunk { CChunk() : Parent(NULL) { } @@ -114,7 +114,7 @@ GsfInput * gsf_input_uncompress (GsfInput *src); */ }; /* class CStorageStream */ - +#endif } /* namespace PIPELINE */ #endif /* #ifndef PIPELINE_STORAGE_STREAM_H */