Files
OpenSceneGraph/src/osgPlugins/flt/Input.cpp
Robert Osfield 8d25f0766a From Paul Marz : "Input.h, Input.cpp -- Here's where support for reading the continuation
record goes. I added a new function to read a continued record body. I added
code in the existing ReadRecord routine to peek ahead for a CONTINUATION_OP
if the current record could possibly be continued.

opcodes.h -- Besides adding the opcode for CONTINUATION_OP, I also added new
15.8 opcodes. I labeled opcodes as "ignored" if I could easily discern that
our loader wasn't doing anything with them. For historical reasons, I added
all obsolete opcodes, prefixed with "OBS_".

LocalVertexPoolRecord.h, LocalVertexPoolRecord.cpp -- This is one of three
types of records that can be continued with a CONTINUATION_OP record. I
removed all invalid assertions that assumed the record length would always
be less than 65535. I replaced the "vertex size" calculation with a more
efficient method based on caching the size from attribute bits, rather than
taking the length of the record and dividing it by numVerts (which would
have been incorrect if the record had been continued)."
2004-03-06 15:03:55 +00:00

264 lines
5.5 KiB
C++

// Input.cpp
#include <string>
// #include <malloc.h>
#include <assert.h>
#include <osg/Notify>
#include <osgDB/FileUtils>
#include "Input.h"
#include "Record.h"
#include "Registry.h"
using namespace flt;
FileInput::FileInput()
{
_init();
}
FileInput::~FileInput()
{
close();
}
void FileInput::_init()
{
_lRecOffset = 0L;
_file = NULL;
_eof = true;
}
size_t FileInput::_read(void *buffer, size_t size)
{
if (_eof) return 0;
size_t nItemsRead = ::fread(buffer, size, 1, _file);
if (nItemsRead != 1)
_eof = true;
return nItemsRead;
}
bool FileInput::eof()
{
return _eof;
}
bool FileInput::open(const std::string& fileName)
{
_file=::fopen( fileName.c_str(), "rb");
if (_file == NULL)
{
// ok havn't found file, resort to using findFile...
std::string newFileName = osgDB::findDataFile(fileName);
if (newFileName.empty()) return false;
_file=::fopen( newFileName.c_str(), "rb");
if (_file == NULL) return false;
}
_eof = false;
return true;
}
void FileInput::close()
{
if (_file) ::fclose(_file);
_init();
}
bool FileInput::rewindLast()
{
if (_file == NULL) return false;
return (fseek(_file, _lRecOffset, SEEK_SET) == 0);
}
long FileInput::offset()
{
return _lRecOffset;
}
// read opcode and size
bool FileInput::_readHeader(SRecHeader* pHdr)
{
int nItemsRead;
// Save file position for rewind operation
_lRecOffset = ::ftell( _file );
// Read record header (4 bytes)
nItemsRead = _read(pHdr, sizeof(SRecHeader));
if (nItemsRead != 1)
return false;
if (isLittleEndianMachine())
pHdr->endian();
if ((unsigned)pHdr->length() < sizeof(SRecHeader))
return false;
return true;
}
bool FileInput::_readBody(SRecHeader* pData)
{
// Read record body
int nBodySize = pData->length() - sizeof(SRecHeader);
if (nBodySize > 0)
{
int nItemsRead = _read(pData+1, nBodySize);
if (nItemsRead != 1)
return false;
}
return true;
}
bool FileInput::_readContinuedBody(char* pData, int nBytes)
{
// Read record body
if (nBytes > 0)
{
int nItemsRead = _read(pData, nBytes);
if (nItemsRead != 1)
return false;
}
return true;
}
SRecHeader* FileInput::readRecord()
{
SRecHeader hdr;
SRecHeader* pData;
if (!_readHeader(&hdr))
return NULL;
// Allocate buffer for record (including header)
// This buffer is extended later in Record::cloneRecord()
// if defined struct is bigger than read.
pData = (SRecHeader*)::malloc(hdr.length());
if (pData == NULL)
return NULL;
*pData = hdr;
// Some records contains only the header
if (hdr.length() == sizeof(SRecHeader))
return pData;
if (!_readBody(pData))
return NULL;
// Add support for OpenFlight 15.7 (1570) continuation records
//
// Record and FaceRecord both want to rewindLast, so save and restore
// the current file offset.
const long lRecOffsetSave = _lRecOffset;
int nTotalLen = hdr.length();
// From spec, in practice only these three records can be continued:
bool bContinuationPossible = (
(hdr.opcode()==COLOR_NAME_PALETTE_OP) ||
(hdr.opcode()==EXTENSION_OP) ||
(hdr.opcode()==LOCAL_VERTEX_POOL_OP) );
while (bContinuationPossible)
{
SRecHeader hdr2;
if (_readHeader( &hdr2 ))
{
if (hdr2.opcode() == CONTINUATION_OP)
{
int nNewChunkLen = hdr2.length() - 4;
size_t nNewLen = nTotalLen + nNewChunkLen;
pData = (SRecHeader*)::realloc( (void*)pData, nNewLen );
if (pData == NULL)
return NULL;
if (!_readContinuedBody( ((char*)pData) + nTotalLen, nNewChunkLen ))
return NULL;
nTotalLen = (int)nNewLen;
}
else
{
// Not a continuation record. Rewind, then exit loop.
rewindLast();
bContinuationPossible = false;
}
}
else
// Probably EOF
bContinuationPossible = false;
}
_lRecOffset = lRecOffsetSave;
//
// END support for continuation records
return pData;
}
Record* Input::readCreateRecord(FltFile* pFltFile)
{
SRecHeader* pData = readRecord();
if (pData == NULL) return NULL;
// find matching record prototype class
Record* pProto = Registry::instance()->getPrototype(pData->opcode());
if (pProto == NULL)
pProto = Registry::instance()->getPrototype(0);
if (pProto == NULL)
{
// Should not be possible to end up here!
osg::notify(osg::INFO) << "UnknownRecord not in registry!" << std::endl;
::free(pData);
return NULL;
}
// clone protoype
Record* pRec = pProto->cloneRecord(pData);
if (pRec == NULL)
{
osg::notify(osg::INFO) << "Can't clone record!" << std::endl;
::free(pData);
return NULL;
}
pRec->_pFltFile = pFltFile;
#if 0
osg::notify(osg::ALWAYS) << "class = " << pRec->className();
osg::notify(osg::ALWAYS) << " op = " << pRec->getOpcode();
osg::notify(osg::ALWAYS) << " name = " << pRec->getName();
osg::notify(osg::ALWAYS) << " offset = " << offset() << std::endl;
#endif
// Perform any post-read initializations.
pRec->postReadInit();
return pRec;
}