2002-08-15 19:25:23 +08:00
|
|
|
// Input.cpp
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
// #include <malloc.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
2001-01-11 00:32:10 +08:00
|
|
|
#include <osg/Notify>
|
2001-10-08 16:35:06 +08:00
|
|
|
#include <osgDB/FileUtils>
|
2001-01-11 00:32:10 +08:00
|
|
|
|
|
|
|
#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");
|
2004-11-23 07:54:45 +08:00
|
|
|
if (_file == NULL) return false;
|
2001-01-11 00:32:10 +08:00
|
|
|
_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;
|
|
|
|
|
2001-09-20 05:08:56 +08:00
|
|
|
// Save file position for rewind operation
|
|
|
|
_lRecOffset = ::ftell( _file );
|
2001-01-11 00:32:10 +08:00
|
|
|
|
|
|
|
// Read record header (4 bytes)
|
|
|
|
nItemsRead = _read(pHdr, sizeof(SRecHeader));
|
|
|
|
if (nItemsRead != 1)
|
2001-09-20 05:08:56 +08:00
|
|
|
return false;
|
2001-01-11 00:32:10 +08:00
|
|
|
|
|
|
|
if (isLittleEndianMachine())
|
|
|
|
pHdr->endian();
|
|
|
|
|
|
|
|
if ((unsigned)pHdr->length() < sizeof(SRecHeader))
|
|
|
|
return false;
|
|
|
|
|
2001-09-20 05:08:56 +08:00
|
|
|
return true;
|
2001-01-11 00:32:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool FileInput::_readBody(SRecHeader* pData)
|
|
|
|
{
|
2001-09-20 05:08:56 +08:00
|
|
|
// Read record body
|
2001-01-11 00:32:10 +08:00
|
|
|
int nBodySize = pData->length() - sizeof(SRecHeader);
|
|
|
|
if (nBodySize > 0)
|
|
|
|
{
|
|
|
|
int nItemsRead = _read(pData+1, nBodySize);
|
2001-09-20 05:08:56 +08:00
|
|
|
if (nItemsRead != 1)
|
|
|
|
return false;
|
2001-01-11 00:32:10 +08:00
|
|
|
}
|
|
|
|
|
2001-09-20 05:08:56 +08:00
|
|
|
return true;
|
2001-01-11 00:32:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-06 23:03:55 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-01-11 00:32:10 +08:00
|
|
|
SRecHeader* FileInput::readRecord()
|
|
|
|
{
|
|
|
|
SRecHeader hdr;
|
|
|
|
SRecHeader* pData;
|
|
|
|
|
|
|
|
if (!_readHeader(&hdr))
|
|
|
|
return NULL;
|
|
|
|
|
2001-09-20 05:08:56 +08:00
|
|
|
// Allocate buffer for record (including header)
|
|
|
|
// This buffer is extended later in Record::cloneRecord()
|
|
|
|
// if defined struct is bigger than read.
|
2001-01-11 00:32:10 +08:00
|
|
|
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;
|
|
|
|
|
2004-03-06 23:03:55 +08:00
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
|
2001-01-11 00:32:10 +08:00
|
|
|
return pData;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-12-05 00:03:10 +08:00
|
|
|
Record* Input::readCreateRecord(FltFile* pFltFile)
|
2001-01-11 00:32:10 +08:00
|
|
|
{
|
|
|
|
SRecHeader* pData = readRecord();
|
|
|
|
|
|
|
|
if (pData == NULL) return NULL;
|
|
|
|
|
|
|
|
// find matching record prototype class
|
2001-11-02 00:35:26 +08:00
|
|
|
Record* pProto = Registry::instance()->getPrototype(pData->opcode());
|
2001-01-11 00:32:10 +08:00
|
|
|
if (pProto == NULL)
|
2001-11-02 00:35:26 +08:00
|
|
|
pProto = Registry::instance()->getPrototype(0);
|
2001-01-11 00:32:10 +08:00
|
|
|
|
|
|
|
if (pProto == NULL)
|
|
|
|
{
|
|
|
|
// Should not be possible to end up here!
|
2001-12-15 07:18:28 +08:00
|
|
|
osg::notify(osg::INFO) << "UnknownRecord not in registry!" << std::endl;
|
2001-01-11 00:32:10 +08:00
|
|
|
::free(pData);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clone protoype
|
|
|
|
Record* pRec = pProto->cloneRecord(pData);
|
|
|
|
if (pRec == NULL)
|
|
|
|
{
|
2001-12-15 07:18:28 +08:00
|
|
|
osg::notify(osg::INFO) << "Can't clone record!" << std::endl;
|
2001-01-11 00:32:10 +08:00
|
|
|
::free(pData);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-12-05 00:03:10 +08:00
|
|
|
pRec->_pFltFile = pFltFile;
|
|
|
|
|
2001-09-20 05:08:56 +08:00
|
|
|
#if 0
|
2002-08-15 19:25:23 +08:00
|
|
|
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;
|
2001-09-20 05:08:56 +08:00
|
|
|
#endif
|
2001-01-11 00:32:10 +08:00
|
|
|
|
2002-08-15 19:25:23 +08:00
|
|
|
// Perform any post-read initializations.
|
|
|
|
pRec->postReadInit();
|
2001-01-11 00:32:10 +08:00
|
|
|
|
|
|
|
return pRec;
|
|
|
|
}
|