//---------------------------------------------------------------------
//
// 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 Text {
inline void FastGetBytes(IN bool bigEndian, IN const wchar_t* chars, IN int charCount,
OUT byte* bytes)
{
if (bigEndian)
{
int charIndex = 0, byteIndex = 0;
while (charIndex < charCount)
{
wchar_t ch = chars[charIndex++];
bytes[byteIndex++] = (byte)(ch >> 8);
bytes[byteIndex++] = (byte)ch;
}
}
else
{
memcpy(bytes, chars, charCount * 2);
}
}
inline void FastGetChars(IN bool bigEndian, IN const byte* bytes, IN int byteCount,
OUT wchar_t* chars)
{
ACFASSERT(byteCount % 2 == 0);
if (bigEndian)
{
int byteIndex = 0, charIndex = 0;
while (byteIndex < byteCount)
{
ushort hi = bytes[byteIndex++];
byte lo = bytes[byteIndex++];
chars[charIndex++] = (wchar_t)(hi << 8 | lo);
}
}
else
{
memcpy(chars, bytes, byteCount);
}
}
//---------------------------------------------------------------------
// class UnicodeDecoder
class UnicodeDecoder : public Decoder
{
private:
bool _bigEndian;
int _lastByte;
public:
UnicodeDecoder(bool bigEndian)
{
this->_bigEndian = bigEndian;
this->_lastByte = -1;
}
override int GetCharCount(Array<byte>* bytes, int index, int count)
{
Acf::VerifyArrayRange(bytes, index, count);
if (this->_lastByte >= 0)
count++;
return count / 2;
}
override int GetChars(Array<byte>* bytes, int byteIndex, int byteCount,
Array<wchar_t>* chars, int charIndex)
{
Acf::VerifyArrayRange(bytes, byteIndex, byteCount);
int charCount = GetCharCount(bytes, byteIndex, byteCount);
if (charCount == 0)
return charCount; // byteCount <= 1
Acf::VerifyArrayRange(chars, charIndex, charCount);
if (this->_lastByte >= 0)
{
int nextByte = bytes->Item[byteIndex++];
byteCount--;
byte oneCharBytes[] = { this->_lastByte, nextByte };
FastGetChars(this->_bigEndian, oneCharBytes, 2,
chars->GetItemAddress(charIndex));
charIndex++;
this->_lastByte = -1;
}
if ((byteCount & 1) != 0)
this->_lastByte = bytes->Item[byteIndex + --byteCount];
FastGetChars(this->_bigEndian, bytes->GetItemAddress(byteIndex), byteCount,
chars->GetItemAddress(charIndex));
return charCount;
}
};
//---------------------------------------------------------------------
// class UnicodeEncoding
// Constructors
UnicodeEncoding::UnicodeEncoding(bool bigEndian, bool byteOrderMark)
{
this->_bigEndian = bigEndian;
this->_byteOrderMark = byteOrderMark;
}
// Methods
/*override*/ RefPtr< Array<byte> > UnicodeEncoding::GetPreamble()
{
if (this->_byteOrderMark)
{
if (this->_bigEndian)
return Array<byte>::Build(0xFE, 0xFF);
else
return Array<byte>::Build(0xFF, 0xFE);
}
else
{
return new Array<byte>(0);
}
}
/*override*/ DecoderPtr UnicodeEncoding::GetDecoder()
{
return new UnicodeDecoder(this->_bigEndian);
}
/*override*/ int UnicodeEncoding::GetByteCount(Array<wchar_t>* chars, int index, int count)
{
Acf::VerifyArrayRange(chars, index, count);
int byteCount = count * 2;
// Check for overflow
if (byteCount < 0)
throw ArgumentOutOfRangeException();
return byteCount;
}
/*override*/ int UnicodeEncoding::GetByteCount(String* s)
{
if (s == null)
throw ArgumentNullException();
int byteCount = s->Length * 2;
// Check for overflow
if (byteCount < 0)
throw ArgumentOutOfRangeException();
return byteCount;
}
/*override*/ int UnicodeEncoding::GetBytes(Array<wchar_t>* chars, int charIndex, int charCount,
Array<byte>* bytes, int byteIndex)
{
Acf::VerifyArrayRange(chars, charIndex, charCount);
if (charCount == 0)
return 0;
int byteCount = charCount * 2;
// Check for overflow
if (byteCount < 0)
throw ArgumentOutOfRangeException();
Acf::VerifyArrayRange(bytes, byteIndex, byteCount);
FastGetBytes(this->_bigEndian, chars->GetItemAddress(charIndex), charCount,
bytes->GetItemAddress(byteIndex));
return byteCount;
}
/*override*/ RefPtr< Array<byte> > UnicodeEncoding::GetBytes(String* s)
{
if (s == null)
throw ArgumentNullException();
int byteCount = GetByteCount(s);
RefPtr< Array<byte> > bytes = new Array<byte>(byteCount);
GetBytes(s, 0, s->Length, bytes, 0);
return bytes;
}
/*override*/ int UnicodeEncoding::GetBytes(String* s, int charIndex, int charCount,
Array<byte>* bytes, int byteIndex)
{
Acf::VerifyStringRange(s, charIndex, charCount);
if (charCount == 0)
return 0;
int byteCount = charCount * 2;
// Check for overflow
if (byteCount < 0)
throw ArgumentOutOfRangeException();
Acf::VerifyArrayRange(bytes, byteIndex, byteCount);
FastGetBytes(this->_bigEndian, s->GetCString() + charIndex, charCount,
bytes->GetItemAddress(byteIndex));
return byteCount;
}
/*override*/ int UnicodeEncoding::GetCharCount(Array<byte>* bytes, int index, int count)
{
Acf::VerifyArrayRange(bytes, index, count);
return (count / 2);
}
/*override*/ int UnicodeEncoding::GetChars(Array<byte>* bytes, int byteIndex,
int byteCount, Array<wchar_t>* chars, int charIndex)
{
Acf::VerifyArrayRange(bytes, byteIndex, byteCount);
int charCount = byteCount / 2;
if (charCount == 0)
return 0;
Acf::VerifyArrayRange(chars, charIndex, charCount);
byteCount = charCount * 2;
FastGetChars(this->_bigEndian, bytes->GetItemAddress(byteIndex), byteCount,
chars->GetItemAddress(charIndex));
return charCount;
}
/*override*/ int UnicodeEncoding::GetMaxByteCount(int charCount)
{
if (charCount < 0)
throw ArgumentOutOfRangeException();
int byteCount = charCount * 2;
// Check for overflow
if (byteCount < 0)
throw ArgumentOutOfRangeException();
return byteCount;
}
/*override*/ int UnicodeEncoding::GetMaxCharCount(int byteCount)
{
if (byteCount < 0)
throw ArgumentOutOfRangeException();
int result = (byteCount + 1) / 2;
// Check for overflow
if (result < 0)
throw ArgumentOutOfRangeException();
return result;
}
} // namespace Text
} // namespace Acf