//---------------------------------------------------------------------
//
// Copyright (C) 2004 Yingle Jia
//
// Permission to copy, use, modify, sell and distribute this software is
// granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.
//
#include "stdafx.h"
namespace Acf {
namespace IO {
// Constructors
BinaryReader::BinaryReader(Stream* stream, Encoding* encoding)
{
if (stream == null)
throw ArgumentNullException();
if (encoding == null)
throw ArgumentNullException();
if (!stream->CanRead)
throw ArgumentException();
this->_stream = stream;
this->_primitiveBuffer = new Array<byte>(16);
this->_decoder = encoding->GetDecoder();
this->_charBytes = null;
this->_oneCharBuffer = new Array<wchar_t>(1);
}
// Destructor
/*virtual*/ BinaryReader::~BinaryReader()
{
Close();
}
// Properties
/*virtual*/ StreamPtr BinaryReader::get_BaseStream()
{
return this->_stream;
}
// Methods
/*virtual*/ int BinaryReader::PeekChar()
{
if (this->_stream == null)
throw InvalidOperationException();
if (!this->_stream->CanSeek)
return -1;
int64 origPos = this->_stream->Position;
int ch = Read();
this->_stream->Position = origPos;
return ch;
}
/*virtual*/ int BinaryReader::Read()
{
int n = Read(this->_oneCharBuffer, 0, 1);
if (n == 0)
return -1;
else
return this->_oneCharBuffer->Item[0];
}
/*virtual*/ bool BinaryReader::ReadBoolean()
{
FillBuffer(1);
return (this->_primitiveBuffer->Item[0] != 0);
}
/*virtual*/ byte BinaryReader::ReadByte()
{
FillBuffer(1);
return (this->_primitiveBuffer->Item[0]);
}
/*virtual*/ sbyte BinaryReader::ReadSByte()
{
FillBuffer(1);
return (sbyte) (this->_primitiveBuffer->Item[0]);
}
/*virtual*/ wchar_t BinaryReader::ReadChar()
{
int value = Read();
if (value == -1)
throw EndOfStreamException();
return (wchar_t) value;
}
/*virtual*/ short BinaryReader::ReadInt16()
{
FillBuffer(2);
return (short) (this->_primitiveBuffer->Item[0] & 0xFF | this->_primitiveBuffer->Item[1] << 8);
}
/*virtual*/ ushort BinaryReader::ReadUInt16()
{
FillBuffer(2);
return (ushort) (this->_primitiveBuffer->Item[0] & 0xFF | this->_primitiveBuffer->Item[1] << 8);
}
/*virtual*/ int BinaryReader::ReadInt32()
{
FillBuffer(4);
return (int) ((this->_primitiveBuffer->Item[0] & 0xFF) | this->_primitiveBuffer->Item[1] << 8 |
this->_primitiveBuffer->Item[2] << 16 | this->_primitiveBuffer->Item[3] << 24);
}
/*virtual*/ uint BinaryReader::ReadUInt32()
{
FillBuffer(4);
return (uint) ((this->_primitiveBuffer->Item[0] & 0xFF) | this->_primitiveBuffer->Item[1] << 8 |
this->_primitiveBuffer->Item[2] << 16 | this->_primitiveBuffer->Item[3] << 24);
}
/*virtual*/ int64 BinaryReader::ReadInt64()
{
FillBuffer(8);
uint lo = (uint) (this->_primitiveBuffer->Item[0] | (this->_primitiveBuffer->Item[1]) << 8 |
(this->_primitiveBuffer->Item[2]) << 16 | this->_primitiveBuffer->Item[3] << 24);
uint hi = (uint) (this->_primitiveBuffer->Item[4] | (this->_primitiveBuffer->Item[5]) << 8 |
(this->_primitiveBuffer->Item[6]) << 16 | this->_primitiveBuffer->Item[7] << 24);
return (int64) ((uint64) hi) << 32 | lo;
}
/*virtual*/ uint64 BinaryReader::ReadUInt64()
{
FillBuffer(8);
uint lo = (uint) (this->_primitiveBuffer->Item[0] | (this->_primitiveBuffer->Item[1]) << 8 |
(this->_primitiveBuffer->Item[2]) << 16 | this->_primitiveBuffer->Item[3] << 24);
uint hi = (uint) (this->_primitiveBuffer->Item[4] | (this->_primitiveBuffer->Item[5]) << 8 |
(this->_primitiveBuffer->Item[6]) << 16 | this->_primitiveBuffer->Item[7] << 24);
return ((uint64) hi) << 32 | lo;
}
/*virtual*/ float BinaryReader::ReadSingle()
{
FillBuffer(4);
uint value = (uint) (this->_primitiveBuffer->Item[0] | (this->_primitiveBuffer->Item[1]) << 8 |
(this->_primitiveBuffer->Item[2]) << 16 | this->_primitiveBuffer->Item[3] << 24);
return *((float*) &value);
}
/*virtual*/ double BinaryReader::ReadDouble()
{
FillBuffer(8);
uint lo = (uint) (this->_primitiveBuffer->Item[0] | (this->_primitiveBuffer->Item[1]) << 8 |
(this->_primitiveBuffer->Item[2]) << 16 | this->_primitiveBuffer->Item[3] << 24);
uint hi = (uint) (this->_primitiveBuffer->Item[4] | (this->_primitiveBuffer->Item[5]) << 8 |
(this->_primitiveBuffer->Item[6]) << 16 | this->_primitiveBuffer->Item[7] << 24);
uint64 value = ((uint64) hi) << 32 | lo;
return *((double*) &value);
}
/*virtual*/ StringPtr BinaryReader::ReadString()
{
int byteLength = Read7BitEncodedInt();
if (byteLength == 0)
return String::Empty;
RefPtr< Array<byte> > bytes = new Array<byte>(byteLength);
int readLength = this->_stream->Read(bytes, 0, bytes->Length);
RefPtr< Array<wchar_t> > chars = new Array<wchar_t>(readLength);
int n = this->_decoder->GetChars(bytes, 0, readLength, chars, 0);
return new String(chars, 0, n);
}
/*virtual*/ int BinaryReader::Read(Array<byte>* buffer, int index, int count)
{
if (this->_stream == null)
throw InvalidOperationException();
return this->_stream->Read(buffer, index, count);
}
/*virtual*/ RefPtr< Array<byte> > BinaryReader::ReadBytes(int count)
{
if (count < 0)
throw ArgumentOutOfRangeException();
if (this->_stream == null)
throw InvalidOperationException();
RefPtr< Array<byte> > result = new Array<byte>(count);
int numRead = 0;
do
{
int n = this->_stream->Read(result, numRead, count);
if (n == 0)
break;
numRead += n;
count -= n;
} while (count > 0);
if (numRead != result->Length)
{
// Trim array. This should happen on EOF & possibly net streams.
RefPtr< Array<byte> > copy = new Array<byte>(numRead);
Array<byte>::Copy(result, copy, numRead);
result = copy;
}
return result;
}
/*virtual*/ int BinaryReader::Read(Array<wchar_t>* buffer, int index, int count)
{
Acf::VerifyArrayRange(buffer, index, count);
if (this->_stream == null)
throw InvalidOperationException();
int charsRead = 0;
int numBytes = 0;
int charsRemaining = count;
if (this->_charBytes == null)
this->_charBytes = new Array<byte>(128);
while (charsRemaining > 0)
{
numBytes = charsRemaining;
if (numBytes > this->_charBytes->Length)
numBytes = this->_charBytes->Length;
numBytes = this->_stream->Read(this->_charBytes, 0, numBytes);
if (numBytes == 0)
return (count - charsRemaining);
charsRead = this->_decoder->GetChars(this->_charBytes, 0, numBytes, buffer, index);
charsRemaining -= charsRead;
index += charsRead;
}
return count;
}
/*virtual*/ RefPtr< Array<wchar_t> > BinaryReader::ReadChars(int count)
{
RefPtr< Array<wchar_t> > chars = new Array<wchar_t>(count);
int n = Read(chars, 0, count);
if (n != count)
{
RefPtr< Array<wchar_t> > copy = new Array<wchar_t>(n);
Array<wchar_t>::Copy(chars, 0, copy, 0, n);
chars = copy;
}
return chars;
}
/*virtual*/ void BinaryReader::Close()
{
if (this->_stream != null)
{
this->_stream->Close();
this->_stream = null;
this->_primitiveBuffer = null;
this->_decoder = null;
this->_charBytes = null;
this->_oneCharBuffer = null;
}
}
void BinaryReader::FillBuffer(int numBytes)
{
ACFASSERT(this->_primitiveBuffer == null ||
(numBytes > 0 && numBytes <= this->_primitiveBuffer->Length));
int bytesRead = 0;
int n = 0;
if (this->_stream == null)
throw InvalidOperationException();
do
{
n = this->_stream->Read(this->_primitiveBuffer, bytesRead, numBytes - bytesRead);
if (n == 0)
throw EndOfStreamException();
bytesRead += n;
} while (bytesRead < numBytes);
}
int BinaryReader::Read7BitEncodedInt()
{
// Read out an int 7 bits at a time. The high bit
// of the byte when on means to continue reading more bytes.
int count = 0;
int shift = 0;
byte b;
do {
b = ReadByte();
count |= (b & 0x7F) << shift;
shift += 7;
} while ((b & 0x80) != 0);
return count;
}
} // namespace IO
} // namespace Acf