/**
* \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
}
#ifdef NL_DEBUG_STORAGE
nldebug("Entered reading chunk of size %i", chunk->Size);
#endif
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())
{
#ifdef NL_DEBUG_STORAGE
nldebug("Writing, enter chunk");
#endif
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
{
#ifdef NL_DEBUG_STORAGE
nldebug("Writing, leave chunk");
#endif
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);
#ifdef NL_DEBUG_STORAGE
nldebug("Size: %i, Field: %x", sizeWithHeader, sizeField);
#endif
return sizeWithHeader;
}
}
} /* namespace MAX */
} /* namespace PIPELINE */
/* end of file */