Added IndexBlock inner class to osgDB::Archive
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include <osgDB/ReaderWriter>
|
||||
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
|
||||
namespace osgDB {
|
||||
|
||||
@@ -67,14 +68,75 @@ class OSGDB_EXPORT Archive : public ReaderWriter
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::istream::pos_type pos_type;
|
||||
|
||||
typedef std::map<std::string, pos_type> FileNamePositionMap;
|
||||
|
||||
typedef std::istream::pos_type pos_type;
|
||||
typedef std::map<std::string, pos_type> FileNamePositionMap;
|
||||
|
||||
class IndexBlock : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
IndexBlock(unsigned int blockSize=0);
|
||||
|
||||
inline pos_type getPosition() const { return _filePosition; }
|
||||
|
||||
inline unsigned int getBlockSize() const { return _blockSize; }
|
||||
|
||||
|
||||
void setPositionNextIndexBlock(pos_type position);
|
||||
|
||||
inline pos_type getPositionNextIndexBlock() const { return _filePositionNextIndexBlock; }
|
||||
|
||||
|
||||
void read(std::istream& in);
|
||||
|
||||
bool getFileReferences(FileNamePositionMap& indexMap);
|
||||
|
||||
|
||||
inline bool requiresWrite() const { return _requiresWrite; }
|
||||
|
||||
void write(std::ostream& out);
|
||||
|
||||
inline bool spaceAvailable(pos_type position, const std::string& filename) const
|
||||
{
|
||||
unsigned requiredSize = sizeof(position)+sizeof(unsigned int)+filename.size();
|
||||
return (_offsetOfNextAvailableSpace + requiredSize)<_blockSize;
|
||||
}
|
||||
|
||||
bool addFileReference(pos_type position, const std::string& filename);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void allocateData(unsigned int blockSize);
|
||||
|
||||
virtual ~IndexBlock();
|
||||
bool _requiresWrite;
|
||||
pos_type _filePosition;
|
||||
|
||||
unsigned int _blockSize;
|
||||
pos_type _filePositionNextIndexBlock;
|
||||
unsigned int _offsetOfNextAvailableSpace;
|
||||
unsigned char* _data;
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef std::list< osg::ref_ptr<IndexBlock> > IndexBlockList;
|
||||
|
||||
void readIndexBlocks();
|
||||
|
||||
void writeIndexBlocks();
|
||||
|
||||
bool addFileReference(pos_type position, const std::string& fileName);
|
||||
|
||||
static float s_currentSupportedVersion;
|
||||
float _version;
|
||||
Status _status;
|
||||
std::ifstream _input;
|
||||
std::ofstream _output;
|
||||
|
||||
IndexBlockList _indexBlockList;
|
||||
FileNamePositionMap _indexMap;
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,129 @@
|
||||
|
||||
using namespace osgDB;
|
||||
|
||||
float Archive::s_currentSupportedVersion = 0.0;
|
||||
|
||||
Archive::IndexBlock::IndexBlock(unsigned int blockSize):
|
||||
_requiresWrite(false),
|
||||
_filePosition(0),
|
||||
_blockSize(0),
|
||||
_offsetOfNextAvailableSpace(0),
|
||||
_data(0)
|
||||
{
|
||||
allocateData(blockSize);
|
||||
}
|
||||
|
||||
Archive::IndexBlock::~IndexBlock()
|
||||
{
|
||||
delete [] _data;
|
||||
}
|
||||
|
||||
void Archive::IndexBlock::allocateData(unsigned int blockSize)
|
||||
{
|
||||
_data = (blockSize!=0) ? new unsigned char[blockSize] : 0;
|
||||
if (_data)
|
||||
{
|
||||
_blockSize = blockSize;
|
||||
|
||||
// initialize the array
|
||||
unsigned char* end = _data + _blockSize;
|
||||
for(unsigned char* ptr=_data; ptr < end; ++ptr) *ptr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_blockSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Archive::IndexBlock::read(std::istream& in)
|
||||
{
|
||||
_filePosition = in.tellg();
|
||||
in.read(reinterpret_cast<char*>(&_blockSize), sizeof(_blockSize));
|
||||
in.read(reinterpret_cast<char*>(&_filePositionNextIndexBlock), sizeof(_filePositionNextIndexBlock));
|
||||
in.read(reinterpret_cast<char*>(&_offsetOfNextAvailableSpace), sizeof(_offsetOfNextAvailableSpace));
|
||||
|
||||
allocateData(_blockSize);
|
||||
if (_data)
|
||||
{
|
||||
in.read(reinterpret_cast<char*>(_data),_blockSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Allocation Problem in Archive::IndexBlock::read(std::istream& in)"<<std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Archive::IndexBlock::getFileReferences(FileNamePositionMap& indexMap)
|
||||
{
|
||||
if (!_data || _offsetOfNextAvailableSpace==0) return false;
|
||||
unsigned char* ptr = _data;
|
||||
unsigned char* end_ptr = _data + _offsetOfNextAvailableSpace;
|
||||
while (ptr<end_ptr)
|
||||
{
|
||||
pos_type position = *(reinterpret_cast<pos_type*>(ptr));
|
||||
ptr += sizeof(pos_type);
|
||||
|
||||
unsigned int filename_size = *(reinterpret_cast<unsigned int*>(ptr));
|
||||
ptr += sizeof(unsigned int);
|
||||
|
||||
std::string filename(ptr, ptr+filename_size);
|
||||
|
||||
ptr += filename_size;
|
||||
}
|
||||
}
|
||||
|
||||
void Archive::IndexBlock::write(std::ostream& out)
|
||||
{
|
||||
if (_filePosition==pos_type(0))
|
||||
{
|
||||
_filePosition = out.tellp();
|
||||
}
|
||||
else
|
||||
{
|
||||
out.seekp(_filePosition);
|
||||
}
|
||||
|
||||
out.write(reinterpret_cast<char*>(&_blockSize), sizeof(_blockSize));
|
||||
out.write(reinterpret_cast<char*>(&_filePositionNextIndexBlock), sizeof(_filePositionNextIndexBlock));
|
||||
out.write(reinterpret_cast<char*>(&_offsetOfNextAvailableSpace), sizeof(_offsetOfNextAvailableSpace));
|
||||
|
||||
out.write(reinterpret_cast<char*>(_data),_blockSize);
|
||||
|
||||
osg::notify(osg::NOTICE)<<"Archive::IndexBlock::write()"<<std::endl;
|
||||
}
|
||||
|
||||
|
||||
bool Archive::IndexBlock::addFileReference(pos_type position, const std::string& filename)
|
||||
{
|
||||
if (spaceAvailable(position, filename))
|
||||
{
|
||||
unsigned char* ptr = _data+_offsetOfNextAvailableSpace;
|
||||
|
||||
*(reinterpret_cast<pos_type*>(ptr)) = position;
|
||||
ptr += sizeof(pos_type);
|
||||
|
||||
*(reinterpret_cast<unsigned int*>(ptr)) = filename.size();
|
||||
ptr += sizeof(unsigned int);
|
||||
|
||||
for(unsigned int i=0;i<filename.size();++i, ++ptr)
|
||||
{
|
||||
*ptr = filename[i];
|
||||
}
|
||||
|
||||
_requiresWrite = true;
|
||||
|
||||
osg::notify(osg::NOTICE)<<"Archive::IndexBlock::addFileReference("<<(unsigned int)position<<", "<<filename<<")"<<std::endl;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Archive::IndexBlock::setPositionNextIndexBlock(pos_type position)
|
||||
{
|
||||
_filePositionNextIndexBlock = position;
|
||||
_requiresWrite = true;
|
||||
}
|
||||
|
||||
Archive::Archive()
|
||||
{
|
||||
}
|
||||
@@ -32,6 +155,15 @@ void Archive::create(const std::string& filename, unsigned int indexBlockSize)
|
||||
{
|
||||
_status = WRITE;
|
||||
_output.open(filename.c_str());
|
||||
_output<<"osga";
|
||||
_output.write(reinterpret_cast<char*>(&s_currentSupportedVersion),sizeof(float));
|
||||
|
||||
IndexBlock *indexBlock = new IndexBlock(indexBlockSize);
|
||||
if (indexBlock)
|
||||
{
|
||||
indexBlock->write(_output);
|
||||
_indexBlockList.push_back(indexBlock);
|
||||
}
|
||||
}
|
||||
|
||||
void Archive::open(const std::string& filename, Status status)
|
||||
@@ -51,7 +183,20 @@ void Archive::open(const std::string& filename, Status status)
|
||||
void Archive::close()
|
||||
{
|
||||
_input.close();
|
||||
_output.close();
|
||||
|
||||
if (_status==WRITE)
|
||||
{
|
||||
for(IndexBlockList::iterator itr=_indexBlockList.begin();
|
||||
itr!=_indexBlockList.end();
|
||||
++itr)
|
||||
{
|
||||
if ((*itr)->requiresWrite())
|
||||
{
|
||||
(*itr)->write(_output);
|
||||
}
|
||||
}
|
||||
_output.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +205,52 @@ bool Archive::fileExists(const std::string& filename) const
|
||||
return (_indexMap.count(filename)!=0);
|
||||
}
|
||||
|
||||
bool Archive::addFileReference(pos_type position, const std::string& fileName)
|
||||
{
|
||||
if (_status==READ)
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Archive::getPositionForNewEntry("<<fileName<<") failed, archive opened as read only."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_output)
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"Archive::getPositionForNewEntry("<<fileName<<") failed, _output set up."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// get an IndexBlock with space available if possible
|
||||
unsigned int blockSize = 4096;
|
||||
osg::ref_ptr<IndexBlock> indexBlock = _indexBlockList.empty() ? 0 : _indexBlockList.back();
|
||||
osg::ref_ptr<IndexBlock> previousBlock = indexBlock;
|
||||
if (indexBlock.valid())
|
||||
{
|
||||
blockSize = indexBlock->getBlockSize();
|
||||
if (!(indexBlock->spaceAvailable(position, fileName)))
|
||||
{
|
||||
previousBlock = indexBlock;
|
||||
indexBlock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// if not one available create a new block.
|
||||
if (!indexBlock)
|
||||
{
|
||||
if (previousBlock.valid()) previousBlock->setPositionNextIndexBlock(_output.tellp());
|
||||
|
||||
indexBlock = new IndexBlock(blockSize);
|
||||
indexBlock->write(_output);
|
||||
_indexBlockList.push_back(indexBlock.get());
|
||||
}
|
||||
|
||||
if (indexBlock.valid())
|
||||
{
|
||||
return indexBlock->addFileReference(position, fileName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ReaderWriter::ReadResult Archive::readObject(const std::string& fileName,const Options* options)
|
||||
{
|
||||
if (_status!=READ)
|
||||
@@ -109,7 +300,14 @@ ReaderWriter::WriteResult Archive::writeObject(const osg::Object& obj,const std:
|
||||
}
|
||||
|
||||
osg::notify(osg::NOTICE)<<"Archive::writeObject(obj, "<<fileName<<")"<<std::endl;
|
||||
return rw->writeObject(obj, _output, options);
|
||||
|
||||
pos_type position = _output.tellp();
|
||||
|
||||
WriteResult result = rw->writeObject(obj, _output, options);
|
||||
|
||||
if (result.success()) addFileReference(position, fileName);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ReaderWriter::WriteResult Archive::writeImage(const osg::Image& /*image*/,const std::string& fileName,const Options* options)
|
||||
|
||||
Reference in New Issue
Block a user