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