//---------------------------------------------------------------------
//
// 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 int GetEndLeadByteCount(int codePage, byte* bytes, int count)
{
int i = count;
while (i > 0 && Pal::IsDbcsLeadByte(codePage, bytes[i - 1]))
i--;
return (count - i);
}
//---------------------------------------------------------------------
// class CodePageDecoder
class CodePageDecoder : public Decoder
{
private:
int _codePage;
int _maxCharSize;
int _leadingByte;
RefPtr<Array<byte> > _byteBuffer;
public:
CodePageDecoder(int codePage, int maxCharSize)
{
this->_codePage = codePage;
this->_maxCharSize = maxCharSize;
this->_leadingByte = -1;
this->_byteBuffer = new Array<byte>(2);
}
override int GetCharCount(Array<byte>* bytes, int index, int count)
{
Acf::VerifyArrayRange(bytes, index, count);
if (this->_maxCharSize == 1 || count == 0)
return count;
int result = 0;
// If we stored a leading byte in previous call...
if (this->_leadingByte >= 0)
{
index++;
count--;
result = 1;
if (count == 0)
return result;
}
// If the last byte is the leading byte of a character, ignore it
int leadByteCount = GetEndLeadByteCount(this->_codePage,
bytes->GetItemAddress(index), count);
if ((leadByteCount & 1) != 0)
{
count--;
if (count == 0)
return result;
}
// Delegate the hard work to MultiByteToWideChar
return (result + Pal::MultiByteToWideChar(this->_codePage, 0,
bytes->GetItemAddress(index), count, null, 0));
}
override int GetChars(Array<byte>* bytes, int byteIndex, int byteCount,
Array<wchar_t>* chars, int charIndex)
{
Acf::VerifyArrayRange(bytes, byteIndex, byteCount);
if (chars == null)
throw ArgumentNullException();
if (charIndex < 0 || charIndex > chars->Length)
throw ArgumentOutOfRangeException();
int result = 0;
if (byteCount == 0)
return result;
// If we stored a leading byte in previous call...
if (this->_leadingByte >= 0)
{
if (charIndex == chars->Length)
throw ArgumentException();
this->_byteBuffer->Item[0] = (byte) this->_leadingByte;
this->_byteBuffer->Item[1] = bytes->Item[byteIndex];
Pal::MultiByteToWideChar(this->_codePage, 0,
this->_byteBuffer->GetItemAddress(0), 2,
chars->GetItemAddress(charIndex), 1);
byteIndex++;
byteCount--;
charIndex++;
this->_leadingByte = -1;
result = 1;
if (byteCount == 0)
return result;
}
// If the last byte is the leading byte of a character, store it for next call
if (this->_maxCharSize > 1)
{
int leadByteCount = GetEndLeadByteCount(this->_codePage,
bytes->GetItemAddress(byteIndex), byteCount);
if ((leadByteCount & 1) != 0)
{
this->_leadingByte = bytes->Item[byteIndex + --byteCount];
if (byteCount == 0)
return result;
}
}
if (charIndex == chars->Length)
throw ArgumentException();
// Delegate the hard work to MultiByteToWideChar
int n = Pal::MultiByteToWideChar(this->_codePage, 0,
bytes->GetItemAddress(byteIndex), byteCount,
chars->GetItemAddress(charIndex), chars->Length - charIndex);
if (n == 0)
throw ArgumentException();
return (result + n);
}
};
//---------------------------------------------------------------------
// class CodePageEncoding
// Constructors
CodePageEncoding::CodePageEncoding(int codePage)
: _codePage(codePage)
{
Pal::CodePageInfo cpi;
bool ret = Pal::GetCodePageInfo(codePage, &cpi);
if (ret)
this->_maxCharSize = cpi.MaxCharSize;
else
this->_maxCharSize = 4;
}
// Methods
/*override*/ DecoderPtr CodePageEncoding::GetDecoder()
{
return new CodePageDecoder(this->_codePage, this->_maxCharSize);
}
/*override*/ int CodePageEncoding::GetByteCount(Array<wchar_t>* chars,
int index, int count)
{
Acf::VerifyArrayRange(chars, index, count);
if (this->_maxCharSize == 1)
return count;
int byteCount = Pal::WideCharToMultiByte(this->_codePage, 0,
chars->GetItemAddress(index), count, null, 0, 0, null);
// Check for overflow
if (byteCount < 0)
throw ArgumentOutOfRangeException();
return byteCount;
}
/*override*/ int CodePageEncoding::GetBytes(Array<wchar_t>* chars, int charIndex,
int charCount, Array<byte>* bytes, int byteIndex)
{
Acf::VerifyArrayRange(chars, charIndex, charCount);
if (bytes == null)
throw ArgumentNullException();
if (byteIndex < 0 || byteIndex >= bytes->Length)
throw ArgumentOutOfRangeException();
if (charCount == 0)
return 0;
int result = Pal::WideCharToMultiByte(this->_codePage, 0,
chars->GetItemAddress(charIndex), charCount,
bytes->GetItemAddress(byteIndex), bytes->Length - byteIndex,
0, null);
if (result == 0)
throw ArgumentException();
return result;
}
/*override*/ int CodePageEncoding::GetCharCount(Array<byte>* bytes, int index, int count)
{
Acf::VerifyArrayRange(bytes, index, count);
if (this->_maxCharSize == 1)
return count;
return Pal::MultiByteToWideChar(this->_codePage, 0,
bytes->GetItemAddress(index), count, null, 0);
}
/*override*/ int CodePageEncoding::GetChars(Array<byte>* bytes, int byteIndex,
int byteCount, Array<wchar_t>* chars, int charIndex)
{
Acf::VerifyArrayRange(bytes, byteIndex, byteCount);
if (chars == null)
throw ArgumentNullException();
if (charIndex < 0 || charIndex >= chars->Length)
throw ArgumentOutOfRangeException();
if (byteCount == 0)
return 0;
int result = Pal::MultiByteToWideChar(this->_codePage, 0,
bytes->GetItemAddress(byteIndex), byteCount,
chars->GetItemAddress(charIndex), chars->Length - charIndex);
if (result == 0)
throw ArgumentException();
return result;
}
/*override*/ int CodePageEncoding::GetMaxByteCount(int charCount)
{
if (charCount < 0)
throw ArgumentOutOfRangeException();
int byteCount = charCount * this->_maxCharSize;
// Check for overflow
if (byteCount < 0)
throw ArgumentOutOfRangeException();
return byteCount;
}
/*override*/ int CodePageEncoding::GetMaxCharCount(int byteCount)
{
if (byteCount < 0)
throw ArgumentOutOfRangeException();
return byteCount;
}
} // namespace Text
} // namespace Acf