enderalse/SKSE/Plugins/fs_skse_plugin_functions/common/IDataStream.cpp
2021-10-06 02:45:46 +02:00

473 lines
8.0 KiB
C++

#include "IDataStream.h"
/**** IDataStream *************************************************************/
IDataStream::IDataStream()
:streamLength(0), streamOffset(0), swapBytes(false)
{
}
IDataStream::~IDataStream()
{
}
/**
* Reads and returns an 8-bit value from the stream
*/
UInt8 IDataStream::Read8(void)
{
UInt8 out;
ReadBuf(&out, sizeof(UInt8));
return out;
}
/**
* Reads and returns a 16-bit value from the stream
*/
UInt16 IDataStream::Read16(void)
{
UInt16 out;
ReadBuf(&out, sizeof(UInt16));
if(swapBytes)
out = Swap16(out);
return out;
}
/**
* Reads and returns a 32-bit value from the stream
*/
UInt32 IDataStream::Read32(void)
{
UInt32 out;
ReadBuf(&out, sizeof(UInt32));
if(swapBytes)
out = Swap32(out);
return out;
}
/**
* Reads and returns a 64-bit value from the stream
*/
UInt64 IDataStream::Read64(void)
{
UInt64 out;
ReadBuf(&out, sizeof(UInt64));
if(swapBytes)
out = Swap64(out);
return out;
}
/**
* Reads and returns a 32-bit floating point value from the stream
*/
float IDataStream::ReadFloat(void)
{
UInt32 out = Read32();
return *((float *)&out);
}
/**
* Reads a null-or-return-terminated string from the stream
*
* If the buffer is too small to hold the entire string, it is truncated and
* properly terminated.
*
* @param buf the output buffer
* @param bufLength the size of the output buffer
* @return the number of characters written to the buffer
*/
UInt32 IDataStream::ReadString(char * buf, UInt32 bufLength, char altTerminator, char altTerminator2)
{
char * traverse = buf;
bool breakOnReturns = false;
if((altTerminator == '\n') || (altTerminator2 == '\n'))
breakOnReturns = true;
ASSERT_STR(bufLength > 0, "IDataStream::ReadString: zero-sized buffer");
if(bufLength == 1)
{
buf[0] = 0;
return 0;
}
bufLength--;
for(UInt32 i = 0; i < bufLength; i++)
{
if(HitEOF()) break;
UInt8 data = Read8();
if(breakOnReturns)
{
if(data == 0x0D)
{
if(Peek8() == 0x0A)
Skip(1);
break;
}
}
if(!data || (data == altTerminator) || (data == altTerminator2))
{
break;
}
*traverse++ = data;
}
*traverse++ = 0;
return traverse - buf - 1;
}
/**
* Reads and returns an 8-bit value from the stream without advancing the stream's position
*/
UInt8 IDataStream::Peek8(void)
{
IDataStream_PositionSaver saver(this);
return Read8();
}
/**
* Reads and returns a 16-bit value from the stream without advancing the stream's position
*/
UInt16 IDataStream::Peek16(void)
{
IDataStream_PositionSaver saver(this);
return Read16();
}
/**
* Reads and returns a 32-bit value from the stream without advancing the stream's position
*/
UInt32 IDataStream::Peek32(void)
{
IDataStream_PositionSaver saver(this);
return Read32();
}
/**
* Reads and returns a 32-bit value from the stream without advancing the stream's position
*/
UInt64 IDataStream::Peek64(void)
{
IDataStream_PositionSaver saver(this);
return Read64();
}
/**
* Reads and returns a 32-bit floating point value from the stream without advancing the stream's position
*/
float IDataStream::PeekFloat(void)
{
IDataStream_PositionSaver saver(this);
return ReadFloat();
}
/**
* Reads raw data into a buffer without advancing the stream's position
*/
void IDataStream::PeekBuf(void * buf, UInt32 inLength)
{
IDataStream_PositionSaver saver(this);
ReadBuf(buf, inLength);
}
/**
* Skips a specified number of bytes down the stream
*/
void IDataStream::Skip(SInt64 inBytes)
{
SetOffset(GetOffset() + inBytes);
}
/**
* Writes an 8-bit value to the stream.
*/
void IDataStream::Write8(UInt8 inData)
{
WriteBuf(&inData, sizeof(UInt8));
}
/**
* Writes a 16-bit value to the stream.
*/
void IDataStream::Write16(UInt16 inData)
{
if(swapBytes)
inData = Swap16(inData);
WriteBuf(&inData, sizeof(UInt16));
}
/**
* Writes a 32-bit value to the stream.
*/
void IDataStream::Write32(UInt32 inData)
{
if(swapBytes)
inData = Swap32(inData);
WriteBuf(&inData, sizeof(UInt32));
}
/**
* Writes a 64-bit value to the stream.
*/
void IDataStream::Write64(UInt64 inData)
{
if(swapBytes)
inData = Swap64(inData);
WriteBuf(&inData, sizeof(UInt64));
}
/**
* Writes a 32-bit floating point value to the stream.
*/
void IDataStream::WriteFloat(float inData)
{
if(swapBytes)
{
UInt32 temp = *((UInt32 *)&inData);
temp = Swap32(temp);
WriteBuf(&temp, sizeof(UInt32));
}
else
{
WriteBuf(&inData, sizeof(float));
}
}
/**
* Writes a null-terminated string to the stream.
*/
void IDataStream::WriteString(const char * buf)
{
WriteBuf(buf, std::strlen(buf) + 1);
}
/**
* Returns the length of the stream
*/
SInt64 IDataStream::GetLength(void)
{
return streamLength;
}
/**
* Returns the number of bytes remaining in the stream
*/
SInt64 IDataStream::GetRemain(void)
{
return streamLength - streamOffset;
}
/**
* Returns the current offset into the stream
*/
SInt64 IDataStream::GetOffset(void)
{
return streamOffset;
}
/**
* Returns whether we have reached the end of the stream or not
*/
bool IDataStream::HitEOF(void)
{
return streamOffset >= streamLength;
}
/**
* Moves the current offset into the stream
*/
void IDataStream::SetOffset(SInt64 inOffset)
{
streamOffset = inOffset;
}
/**
* Enables or disables byte swapping for basic data transfers
*/
void IDataStream::SwapBytes(bool inSwapBytes)
{
swapBytes = inSwapBytes;
}
IDataStream * IDataStream::GetRootParent(void)
{
IDataStream * parent = GetParent();
if(parent)
return parent->GetRootParent();
else
return this;
}
void IDataStream::CopyStreams(IDataStream * out, IDataStream * in, UInt64 bufferSize, UInt8 * buf)
{
in->Rewind();
bool ourBuffer = false;
if(!buf)
{
buf = new UInt8[bufferSize];
ourBuffer = true;
}
UInt64 remain = in->GetLength();
while(remain > 0)
{
UInt64 transferSize = remain;
if(transferSize > bufferSize)
transferSize = bufferSize;
in->ReadBuf(buf, transferSize);
out->WriteBuf(buf, transferSize);
remain -= transferSize;
}
if(ourBuffer)
delete [] buf;
}
void IDataStream::CopySubStreams(IDataStream * out, IDataStream * in, UInt64 remain, UInt64 bufferSize, UInt8 * buf)
{
bool ourBuffer = false;
if(!buf)
{
buf = new UInt8[bufferSize];
ourBuffer = true;
}
while(remain > 0)
{
UInt64 transferSize = remain;
if(transferSize > bufferSize)
transferSize = bufferSize;
in->ReadBuf(buf, transferSize);
out->WriteBuf(buf, transferSize);
remain -= transferSize;
}
if(ourBuffer)
delete [] buf;
}
/**** IDataStream_PositionSaver ***********************************************/
/**
* The constructor; save the stream's position
*/
IDataStream_PositionSaver::IDataStream_PositionSaver(IDataStream * tgt)
{
stream = tgt;
offset = tgt->GetOffset();
}
/**
* The destructor; restore the stream's saved position
*/
IDataStream_PositionSaver::~IDataStream_PositionSaver()
{
stream->SetOffset(offset);
}
/**** IDataSubStream **********************************************************/
IDataSubStream::IDataSubStream()
:stream(NULL), subBase(0)
{
//
}
IDataSubStream::IDataSubStream(IDataStream * inStream, SInt64 inOffset, SInt64 inLength)
{
stream = inStream;
subBase = inOffset;
streamLength = inLength;
stream->SetOffset(inOffset);
}
IDataSubStream::~IDataSubStream()
{
}
void IDataSubStream::Attach(IDataStream * inStream, SInt64 inOffset, SInt64 inLength)
{
stream = inStream;
subBase = inOffset;
streamLength = inLength;
stream->SetOffset(inOffset);
}
void IDataSubStream::ReadBuf(void * buf, UInt32 inLength)
{
ASSERT_STR(inLength <= GetRemain(), "IDataSubStream::ReadBuf: hit eof");
if(stream->GetOffset() != subBase + streamOffset)
stream->SetOffset(subBase + streamOffset);
stream->ReadBuf(buf, inLength);
streamOffset += inLength;
}
void IDataSubStream::WriteBuf(const void * buf, UInt32 inLength)
{
if(stream->GetOffset() != subBase + streamOffset)
stream->SetOffset(subBase + streamOffset);
stream->WriteBuf(buf, inLength);
streamOffset += inLength;
if(streamLength < streamOffset)
streamLength = streamOffset;
}
void IDataSubStream::SetOffset(SInt64 inOffset)
{
stream->SetOffset(subBase + inOffset);
streamOffset = inOffset;
}