720551d549
fopen to osgDB::fopen to facilitate support for wide character filenames using UT8 encoding.
461 lines
9.6 KiB
C++
461 lines
9.6 KiB
C++
/* ************************
|
|
Copyright Terrain Experts Inc.
|
|
Terrain Experts Inc (TERREX) reserves all rights to this source code
|
|
unless otherwise specified in writing by the President of TERREX.
|
|
This copyright may be updated in the future, in which case that version
|
|
supercedes this one.
|
|
-------------------
|
|
Terrex Experts Inc.
|
|
4400 East Broadway #314
|
|
Tucson, AZ 85711
|
|
info@terrex.com
|
|
Tel: (520) 323-7990
|
|
************************
|
|
*/
|
|
|
|
#include <osgDB/FileUtils>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
/* trpage_writebuf.cpp
|
|
This source file contains the implementation of trpgMemWriteBuffer.
|
|
That is a subclass of trpgWriteBuffer, which implements an interface
|
|
definition for an object which can accept data to be written.
|
|
The Mem version is used to write (for example) a tile's worth of data.
|
|
That data can then be written to a file (or sent over the network).
|
|
You should not need to change this implementation. Simply sublcass
|
|
trpgWriteBuffer and implement all of the required methods. The
|
|
resulting class can then be used in all the places a trpgWriteBuffer
|
|
is required.
|
|
*/
|
|
|
|
#include <trpage_io.h>
|
|
#include <trpage_swap.h>
|
|
|
|
/* **********************
|
|
Memory Write Buffer functions
|
|
**********************
|
|
*/
|
|
// Constructor
|
|
trpgMemWriteBuffer::trpgMemWriteBuffer(trpgEndian in_ness)
|
|
{
|
|
ness = in_ness;
|
|
cpuNess = trpg_cpu_byte_order();
|
|
data = NULL;
|
|
curLen = totLen = 0;
|
|
}
|
|
|
|
// Destructor
|
|
trpgMemWriteBuffer::~trpgMemWriteBuffer()
|
|
{
|
|
if (data)
|
|
delete [] data;
|
|
data = NULL;
|
|
}
|
|
|
|
/* Length()
|
|
Return the length of the given buffer.
|
|
*/
|
|
int trpgMemWriteBuffer::length() const
|
|
{
|
|
return curLen;
|
|
}
|
|
|
|
/* getData()
|
|
Return a pointer to the memory buffer.
|
|
*/
|
|
const char *trpgMemWriteBuffer::getData() const
|
|
{
|
|
return data;
|
|
}
|
|
|
|
/* Length()
|
|
Set the maximum buffer length.
|
|
*/
|
|
void trpgMemWriteBuffer::setLength(unsigned int len)
|
|
{
|
|
if ((int)len > totLen) {
|
|
char *old_data = data;
|
|
int oldLen = totLen;
|
|
totLen = 2*len;
|
|
data = new char[totLen];
|
|
|
|
if (old_data) {
|
|
memcpy(data,old_data,oldLen);
|
|
delete [] old_data;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* append()
|
|
Append the given data to our buffer.
|
|
*/
|
|
void trpgMemWriteBuffer::append(unsigned int len,const char *val)
|
|
{
|
|
if (len == 0) return;
|
|
setLength(curLen+len);
|
|
memcpy(&data[curLen],val,len);
|
|
curLen += len;
|
|
}
|
|
|
|
/* set()
|
|
Set a specific portion of the buffer to a given value.
|
|
*/
|
|
void trpgMemWriteBuffer::set(unsigned int pos,unsigned int len,const char *val)
|
|
{
|
|
if (len == 0) return;
|
|
if (pos+len > (unsigned int)curLen) return;
|
|
|
|
memcpy(&data[pos],val,len);
|
|
}
|
|
|
|
/* --- replacement virtual functions --- */
|
|
|
|
/* Reset()
|
|
Drop whatever's being stored.
|
|
*/
|
|
void trpgMemWriteBuffer::Reset()
|
|
{
|
|
curLen = 0;
|
|
}
|
|
|
|
// Add(Int32)
|
|
void trpgMemWriteBuffer::Add(int32 val)
|
|
{
|
|
if (ness != cpuNess)
|
|
val = trpg_byteswap_int(val);
|
|
append(sizeof(int32),(const char *)&val);
|
|
}
|
|
|
|
// Add(int64)
|
|
void trpgMemWriteBuffer::Add(int64 val)
|
|
{
|
|
if (ness != cpuNess)
|
|
val = trpg_byteswap_llong(val);
|
|
append(sizeof(int64),(const char *)&val);
|
|
}
|
|
|
|
// Add(string)
|
|
// [len] [value...]
|
|
void trpgMemWriteBuffer::Add(const char *val)
|
|
{
|
|
int32 len = (val ? strlen(val) : 0),vlen = len;
|
|
if (ness != cpuNess)
|
|
vlen = trpg_byteswap_int(vlen);
|
|
append(sizeof(int32),(const char *)&vlen);
|
|
append(len,val);
|
|
}
|
|
|
|
// Add(std::string)
|
|
void trpgMemWriteBuffer::Add(std::string &val)
|
|
{
|
|
Add(val.c_str());
|
|
}
|
|
|
|
// Add(float32)
|
|
void trpgMemWriteBuffer::Add(float32 val)
|
|
{
|
|
char cval[4];
|
|
if (ness != cpuNess)
|
|
trpg_byteswap_float_to_4bytes(val,cval);
|
|
else
|
|
memcpy(cval,&val,4);
|
|
|
|
append(sizeof(float32),cval);
|
|
}
|
|
|
|
// Add(float64)
|
|
void trpgMemWriteBuffer::Add(float64 val)
|
|
{
|
|
char cval[8];
|
|
if (ness != cpuNess)
|
|
trpg_byteswap_double_to_8bytes(val,cval);
|
|
else
|
|
memcpy(cval,&val,8);
|
|
|
|
append(sizeof(float64),cval);
|
|
}
|
|
|
|
// Add(int8)
|
|
void trpgMemWriteBuffer::Add(uint8 val)
|
|
{
|
|
// No byte swapping needed
|
|
append(sizeof(uint8),(const char *)&val);
|
|
}
|
|
|
|
//#if (bool != int32)
|
|
// Add(bool)
|
|
void trpgMemWriteBuffer::Add(bool val)
|
|
{
|
|
uint8 ival;
|
|
|
|
ival = (val ? 1 : 0);
|
|
Add(ival);
|
|
}
|
|
//#endif
|
|
|
|
#if (trpgDiskRef != int64)
|
|
// Add(trpgDiskRef)
|
|
void trpgMemWriteBuffer::Add(trpgDiskRef val)
|
|
{
|
|
if (ness != cpuNess)
|
|
val = trpg_byteswap_llong(val);
|
|
|
|
append(sizeof(trpgDiskRef),(const char *)&val);
|
|
}
|
|
#endif
|
|
|
|
// Add(trpgToken)
|
|
void trpgMemWriteBuffer::Add(trpgToken val)
|
|
{
|
|
if (ness != cpuNess)
|
|
val = trpg_byteswap_short(val);
|
|
|
|
append(sizeof(trpgToken),(const char *)&val);
|
|
}
|
|
|
|
// Add(tx2iPoint)
|
|
void trpgWriteBuffer::Add(const trpg2iPoint &val)
|
|
{
|
|
Add((int32)val.x);
|
|
Add((int32)val.y);
|
|
}
|
|
|
|
// Add(tx2dPoint)
|
|
void trpgWriteBuffer::Add(const trpg2dPoint &val)
|
|
{
|
|
Add((float64)val.x);
|
|
Add((float64)val.y);
|
|
}
|
|
|
|
// Add(trpg3dPoint)
|
|
void trpgWriteBuffer::Add(const trpg3dPoint &val)
|
|
{
|
|
Add((float64)val.x);
|
|
Add((float64)val.y);
|
|
Add((float64)val.z);
|
|
}
|
|
|
|
// Add(trpgColor)
|
|
void trpgWriteBuffer::Add(const trpgColor &val)
|
|
{
|
|
Add(val.red);
|
|
Add(val.green);
|
|
Add(val.blue);
|
|
}
|
|
|
|
// Add(std::string)
|
|
void trpgWriteBuffer::Add(const std::string &val)
|
|
{
|
|
Add(val.c_str());
|
|
}
|
|
|
|
/* Push()
|
|
Starts defining a new object.
|
|
Need to keep track of where length goes.
|
|
*/
|
|
void trpgMemWriteBuffer::Begin(trpgToken tok)
|
|
{
|
|
Add(tok);
|
|
lengths.push_back(curLen);
|
|
Add((int32)0);
|
|
}
|
|
|
|
/* Push()
|
|
Pushes a level on the stack. For defining children.
|
|
*/
|
|
void trpgMemWriteBuffer::Push()
|
|
{
|
|
Add((trpgToken)TRPG_PUSH);
|
|
}
|
|
|
|
/* Pop()
|
|
Pops a level off the "stack".
|
|
*/
|
|
void trpgMemWriteBuffer::Pop()
|
|
{
|
|
Add((trpgToken)TRPG_POP);
|
|
}
|
|
|
|
/* Will take out a pop from the end of the buffer, if there is one */
|
|
bool trpgMemWriteBuffer::UnPop()
|
|
{
|
|
//Check to see if there is a pop token ant the end
|
|
trpgToken tk;
|
|
memcpy(&tk, &data[curLen - sizeof(trpgToken)], sizeof(trpgToken));
|
|
if(tk == TRPG_POP)
|
|
{
|
|
curLen -= sizeof(trpgToken);
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
/* Will take out a push from the end of the buffer, if there is one */
|
|
bool trpgMemWriteBuffer::UnPush()
|
|
{
|
|
//Check to see if there is a push token ant the end
|
|
trpgToken tk;
|
|
memcpy(&tk, &data[curLen - sizeof(trpgToken)], sizeof(trpgToken));
|
|
if(tk == TRPG_PUSH)
|
|
{
|
|
curLen -= sizeof(trpgToken);
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/* End()
|
|
Finished defining an object.
|
|
Write the length out where appropriate.
|
|
*/
|
|
void trpgMemWriteBuffer::End()
|
|
{
|
|
if (lengths.size() == 0)
|
|
// Note: say something clever here
|
|
return;
|
|
|
|
int id = lengths.size()-1;
|
|
int32 len = curLen - lengths[id];
|
|
int32 rlen = len-sizeof(int32);
|
|
if (ness != cpuNess)
|
|
rlen = trpg_byteswap_int(rlen);
|
|
set(curLen - len,sizeof(int32),(const char *)&rlen);
|
|
lengths.resize(id);
|
|
}
|
|
|
|
/* Appendable File
|
|
This class is used as a simple appendable file. It's used
|
|
for dumping tile and texture (or most anything) into.
|
|
*/
|
|
|
|
trpgwAppFile::trpgwAppFile(trpgEndian inNess,const char *fileName,bool reuse)
|
|
{
|
|
Init(inNess,fileName,reuse);
|
|
}
|
|
|
|
void trpgwAppFile::Init(trpgEndian inNess,const char *fileName,bool reuse)
|
|
{
|
|
valid = false;
|
|
ness = inNess;
|
|
cpuNess = trpg_cpu_byte_order();
|
|
|
|
if (reuse==false) {
|
|
if (!(fp = osgDB::fopen(fileName,"wb")))
|
|
return;
|
|
lengthSoFar = 0;
|
|
valid = true;
|
|
} else {
|
|
if (!(fp = osgDB::fopen(fileName,"ab")))
|
|
return;
|
|
// ftell is still zero, dammit. Arg.
|
|
fseek(fp,0,SEEK_END);
|
|
lengthSoFar = ftell(fp);
|
|
valid = true;
|
|
}
|
|
}
|
|
|
|
trpgwAppFile::~trpgwAppFile()
|
|
{
|
|
if (fp)
|
|
fclose(fp);
|
|
valid = false;
|
|
}
|
|
|
|
// Return the amount of data written so far (in total)
|
|
int trpgwAppFile::GetLengthWritten()
|
|
{
|
|
return lengthSoFar;
|
|
}
|
|
|
|
// Append the given buffer to our appendable file
|
|
bool trpgwAppFile::Append(const trpgMemWriteBuffer *buf1,const trpgMemWriteBuffer *buf2)
|
|
{
|
|
if (!isValid()) return false;
|
|
|
|
// Get the total length
|
|
int totLen = buf1->length() + (buf2 ? buf2->length() : 0);
|
|
|
|
// Write the length out
|
|
if (fwrite(&totLen,sizeof(int32),1,fp) != 1) {
|
|
valid = false;
|
|
return false;
|
|
}
|
|
|
|
// Write the data out
|
|
const char *data = buf1->getData();
|
|
unsigned int len = buf1->length();
|
|
if (fwrite(data,sizeof(char),len,fp) != len) {
|
|
valid = false;
|
|
return false;
|
|
}
|
|
if (buf2) {
|
|
data = buf2->getData();
|
|
len = buf2->length();
|
|
if (fwrite(data,sizeof(char),len,fp) != len) {
|
|
valid = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
lengthSoFar += totLen;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Append the given raw data to our appendable file
|
|
bool trpgwAppFile::Append(const char *data,int size)
|
|
{
|
|
if (!isValid()) return false;
|
|
|
|
if (!data)
|
|
return false;
|
|
|
|
// Write the length out
|
|
if (fwrite(&size,sizeof(int32),1,fp) != 1) {
|
|
valid = false;
|
|
return false;
|
|
}
|
|
|
|
// Write the data out
|
|
if (fwrite(data,sizeof(char),size,fp) != (size_t)size) {
|
|
valid = false;
|
|
return false;
|
|
}
|
|
|
|
lengthSoFar += size;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Flushes the current tile file
|
|
bool trpgwAppFile::Flush()
|
|
{
|
|
// Flush the File *
|
|
if (fp)
|
|
fflush(fp);
|
|
|
|
return true;
|
|
}
|
|
|
|
// Return the current file position
|
|
int64 trpgwAppFile::Pos() const
|
|
{
|
|
if (!isValid())
|
|
return 0;
|
|
|
|
// Note: This means an appendable file is capped at 2GB
|
|
long pos = ftell(fp);
|
|
|
|
return pos;
|
|
}
|
|
|
|
// Validity check
|
|
bool trpgwAppFile::isValid() const
|
|
{
|
|
return valid;
|
|
}
|