blob: 7bf2f3415602e57ec2b5844d79164251055334fb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id$
*/
// ---------------------------------------------------------------------------
// Includes
// ---------------------------------------------------------------------------
#include <xercesc/util/TransService.hpp>
#include <xercesc/util/XML88591Transcoder.hpp>
#include <xercesc/util/XMLASCIITranscoder.hpp>
#include <xercesc/util/XMLChTranscoder.hpp>
#include <xercesc/util/XMLEBCDICTranscoder.hpp>
#include <xercesc/util/XMLIBM1047Transcoder.hpp>
#include <xercesc/util/XMLIBM1140Transcoder.hpp>
#include <xercesc/util/XMLUCS4Transcoder.hpp>
#include <xercesc/util/XMLUTF8Transcoder.hpp>
#include <xercesc/util/XMLUTF16Transcoder.hpp>
#include <xercesc/util/XMLWin1252Transcoder.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <xercesc/util/EncodingValidator.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/TransENameMap.hpp>
#include <xercesc/util/XMLInitializer.hpp>
#include <xercesc/util/TranscodingException.hpp>
namespace XERCES_CPP_NAMESPACE {
// ---------------------------------------------------------------------------
// Local, static data
//
// gStrictIANAEncoding
// A flag to control whether strict IANA encoding names checking should
// be done
//
// ---------------------------------------------------------------------------
static bool gStrictIANAEncoding = false;
RefHashTableOf<ENameMap>* XMLTransService::gMappings = 0;
RefVectorOf<ENameMap> * XMLTransService::gMappingsRecognizer = 0;
void XMLInitializer::initializeTransService()
{
XMLTransService::gMappings = new RefHashTableOf<ENameMap>(103);
XMLTransService::gMappingsRecognizer = new RefVectorOf<ENameMap>(
(XMLSize_t)XMLRecognizer::Encodings_Count);
}
void XMLInitializer::terminateTransService()
{
delete XMLTransService::gMappingsRecognizer;
XMLTransService::gMappingsRecognizer = 0;
delete XMLTransService::gMappings;
XMLTransService::gMappings = 0;
}
// ---------------------------------------------------------------------------
// XMLTransService: Constructors and destructor
// ---------------------------------------------------------------------------
XMLTransService::XMLTransService()
{
}
XMLTransService::~XMLTransService()
{
}
// ---------------------------------------------------------------------------
// Allow user specific encodings to be added to the mappings table.
// Should be called after platform init
// ---------------------------------------------------------------------------
void XMLTransService::addEncoding(const XMLCh* const encoding,
ENameMap* const ownMapping)
{
gMappings->put((void *) encoding, ownMapping);
}
// ---------------------------------------------------------------------------
// XMLTransService: Non-virtual API
// ---------------------------------------------------------------------------
XMLTranscoder*
XMLTransService::makeNewTranscoderFor( const char* const encodingName
, XMLTransService::Codes& resValue
, const XMLSize_t blockSize
, MemoryManager* const manager)
{
XMLCh* tmpName = XMLString::transcode(encodingName, manager);
ArrayJanitor<XMLCh> janName(tmpName, manager);
return makeNewTranscoderFor(tmpName, resValue, blockSize, manager);
}
XMLTranscoder*
XMLTransService::makeNewTranscoderFor( const XMLCh* const encodingName
, XMLTransService::Codes& resValue
, const XMLSize_t blockSize
, MemoryManager* const manager)
{
//
// If strict IANA encoding flag is set, validate encoding name
//
if (gStrictIANAEncoding)
{
if (!EncodingValidator::instance()->isValidEncoding(encodingName))
{
resValue = XMLTransService::UnsupportedEncoding;
return 0;
}
}
//
// First try to find it in our list of mappings to intrinsically
// supported encodings. We have to upper case the passed encoding
// name because we use a hash table and we stored all our mappings
// in all uppercase.
//
const XMLSize_t bufSize = 2048;
XMLCh upBuf[bufSize + 1];
if (!XMLString::copyNString(upBuf, encodingName, bufSize))
{
resValue = XMLTransService::InternalFailure;
return 0;
}
XMLString::upperCaseASCII(upBuf);
ENameMap* ourMapping = gMappings->get(upBuf);
// If we found it, then call the factory method for it
if (ourMapping)
{
XMLTranscoder* temp = ourMapping->makeNew(blockSize, manager);
resValue = temp ? XMLTransService::Ok : XMLTransService::InternalFailure;
return temp;
}
//
// It wasn't an intrinsic and it wasn't disallowed, so pass it on
// to the trans service to see if he can make anything of it.
//
XMLTranscoder* temp = makeNewXMLTranscoder(encodingName, resValue, blockSize, manager);
// if successful, set resValue to OK
// if failed, the makeNewXMLTranscoder has already set the proper failing resValue
if (temp) resValue = XMLTransService::Ok;
return temp;
}
XMLTranscoder*
XMLTransService::makeNewTranscoderFor( XMLRecognizer::Encodings encodingEnum
, XMLTransService::Codes& resValue
, const XMLSize_t blockSize
, MemoryManager* const manager)
{
//
// We can only make transcoder if the passed encodingEnum is under this range
//
if (encodingEnum < XMLRecognizer::Encodings_Min || encodingEnum > XMLRecognizer::Encodings_Max) {
resValue = XMLTransService::InternalFailure;
return 0;
}
ENameMap* ourMapping = gMappingsRecognizer->elementAt(encodingEnum);
// If we found it, then call the factory method for it
if (ourMapping) {
XMLTranscoder* temp = ourMapping->makeNew(blockSize, manager);
resValue = temp ? XMLTransService::Ok : XMLTransService::InternalFailure;
return temp;
}
else {
XMLTranscoder* temp = makeNewXMLTranscoder(XMLRecognizer::nameForEncoding(encodingEnum, manager), resValue, blockSize, manager);
// if successful, set resValue to OK
// if failed, the makeNewXMLTranscoder has already set the proper failing resValue
if (temp) resValue = XMLTransService::Ok;
return temp;
}
}
// ---------------------------------------------------------------------------
// XMLTransTransService: Hidden Init Method
//
// This is called by platform utils during startup.
// ---------------------------------------------------------------------------
void XMLTransService::initTransService()
{
//
// A stupid way to increment the fCurCount inside the RefVectorOf
//
for (XMLSize_t i = 0; i < (XMLSize_t)XMLRecognizer::Encodings_Count; i++)
gMappingsRecognizer->addElement(0);
//
// Add in the magical mapping for the native XMLCh transcoder. This
// is used for internal entities.
//
gMappingsRecognizer->setElementAt(new ENameMapFor<XMLChTranscoder>(XMLUni::fgXMLChEncodingString), XMLRecognizer::XERCES_XMLCH);
gMappings->put((void*)XMLUni::fgXMLChEncodingString, new ENameMapFor<XMLChTranscoder>(XMLUni::fgXMLChEncodingString));
//
// Add in our mappings for ASCII.
//
gMappingsRecognizer->setElementAt(new ENameMapFor<XMLASCIITranscoder>(XMLUni::fgUSASCIIEncodingString), XMLRecognizer::US_ASCII);
gMappings->put((void*)XMLUni::fgUSASCIIEncodingString, new ENameMapFor<XMLASCIITranscoder>(XMLUni::fgUSASCIIEncodingString));
gMappings->put((void*)XMLUni::fgUSASCIIEncodingString2, new ENameMapFor<XMLASCIITranscoder>(XMLUni::fgUSASCIIEncodingString2));
gMappings->put((void*)XMLUni::fgUSASCIIEncodingString3, new ENameMapFor<XMLASCIITranscoder>(XMLUni::fgUSASCIIEncodingString3));
gMappings->put((void*)XMLUni::fgUSASCIIEncodingString4, new ENameMapFor<XMLASCIITranscoder>(XMLUni::fgUSASCIIEncodingString4));
//
// Add in our mappings for UTF-8
//
gMappingsRecognizer->setElementAt(new ENameMapFor<XMLUTF8Transcoder>(XMLUni::fgUTF8EncodingString), XMLRecognizer::UTF_8);
gMappings->put((void*)XMLUni::fgUTF8EncodingString, new ENameMapFor<XMLUTF8Transcoder>(XMLUni::fgUTF8EncodingString));
gMappings->put((void*)XMLUni::fgUTF8EncodingString2, new ENameMapFor<XMLUTF8Transcoder>(XMLUni::fgUTF8EncodingString2));
//
// Add in our mappings for Latin1
//
gMappings->put((void*)XMLUni::fgISO88591EncodingString, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString));
gMappings->put((void*)XMLUni::fgISO88591EncodingString2, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString2));
gMappings->put((void*)XMLUni::fgISO88591EncodingString3, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString3));
gMappings->put((void*)XMLUni::fgISO88591EncodingString4, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString4));
gMappings->put((void*)XMLUni::fgISO88591EncodingString5, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString5));
gMappings->put((void*)XMLUni::fgISO88591EncodingString6, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString6));
gMappings->put((void*)XMLUni::fgISO88591EncodingString7, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString7));
gMappings->put((void*)XMLUni::fgISO88591EncodingString8, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString8));
gMappings->put((void*)XMLUni::fgISO88591EncodingString9, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString9));
gMappings->put((void*)XMLUni::fgISO88591EncodingString10, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString10));
gMappings->put((void*)XMLUni::fgISO88591EncodingString11, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString11));
gMappings->put((void*)XMLUni::fgISO88591EncodingString12, new ENameMapFor<XML88591Transcoder>(XMLUni::fgISO88591EncodingString12));
//
// Add in our mappings for UTF-16 and UCS-4, little endian
//
bool swapped = XMLPlatformUtils::fgXMLChBigEndian;
gMappingsRecognizer->setElementAt(new EEndianNameMapFor<XMLUTF16Transcoder>(XMLUni::fgUTF16LEncodingString, swapped), XMLRecognizer::UTF_16L);
gMappings->put
(
(void*)XMLUni::fgUTF16LEncodingString,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16LEncodingString
, swapped
)
);
gMappings->put
(
(void*)XMLUni::fgUTF16LEncodingString2,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16LEncodingString2
, swapped
)
);
gMappingsRecognizer->setElementAt(new EEndianNameMapFor<XMLUCS4Transcoder>(XMLUni::fgUCS4LEncodingString, swapped), XMLRecognizer::UCS_4L);
gMappings->put
(
(void*)XMLUni::fgUCS4LEncodingString,
new EEndianNameMapFor<XMLUCS4Transcoder>
(
XMLUni::fgUCS4LEncodingString
, swapped
)
);
gMappings->put
(
(void*)XMLUni::fgUCS4LEncodingString2,
new EEndianNameMapFor<XMLUCS4Transcoder>
(
XMLUni::fgUCS4LEncodingString2
, swapped
)
);
//
// Add in our mappings for UTF-16 and UCS-4, big endian
//
swapped = !XMLPlatformUtils::fgXMLChBigEndian;
gMappingsRecognizer->setElementAt(new EEndianNameMapFor<XMLUTF16Transcoder>(XMLUni::fgUTF16BEncodingString, swapped), XMLRecognizer::UTF_16B);
gMappings->put
(
(void*)XMLUni::fgUTF16BEncodingString,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16BEncodingString
, swapped
)
);
gMappings->put
(
(void*)XMLUni::fgUTF16BEncodingString2,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16BEncodingString2
, swapped
)
);
gMappingsRecognizer->setElementAt(new EEndianNameMapFor<XMLUCS4Transcoder>(XMLUni::fgUCS4BEncodingString, swapped), XMLRecognizer::UCS_4B);
gMappings->put
(
(void*)XMLUni::fgUCS4BEncodingString,
new EEndianNameMapFor<XMLUCS4Transcoder>
(
XMLUni::fgUCS4BEncodingString
, swapped
)
);
gMappings->put
(
(void*)XMLUni::fgUCS4BEncodingString2,
new EEndianNameMapFor<XMLUCS4Transcoder>
(
XMLUni::fgUCS4BEncodingString2
, swapped
)
);
//
// Add in our mappings for UTF-16 and UCS-4 which does not indicate endian
// assumes the same endian encoding as the OS
//
gMappings->put
(
(void*)XMLUni::fgUTF16EncodingString,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16EncodingString
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUTF16EncodingString2,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16EncodingString2
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUTF16EncodingString3,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16EncodingString3
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUTF16EncodingString4,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16EncodingString4
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUTF16EncodingString5,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16EncodingString5
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUTF16EncodingString6,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16EncodingString6
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUTF16EncodingString7,
new EEndianNameMapFor<XMLUTF16Transcoder>
(
XMLUni::fgUTF16EncodingString7
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUCS4EncodingString,
new EEndianNameMapFor<XMLUCS4Transcoder>
(
XMLUni::fgUCS4EncodingString
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUCS4EncodingString2,
new EEndianNameMapFor<XMLUCS4Transcoder>
(
XMLUni::fgUCS4EncodingString2
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUCS4EncodingString3,
new EEndianNameMapFor<XMLUCS4Transcoder>
(
XMLUni::fgUCS4EncodingString3
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUCS4EncodingString4,
new EEndianNameMapFor<XMLUCS4Transcoder>
(
XMLUni::fgUCS4EncodingString4
, false
)
);
gMappings->put
(
(void*)XMLUni::fgUCS4EncodingString5,
new EEndianNameMapFor<XMLUCS4Transcoder>
(
XMLUni::fgUCS4EncodingString5
, false
)
);
//
// Add in our mappings for IBM037, and the one alias we support for
// it, which is EBCDIC-CP-US.
//
gMappingsRecognizer->setElementAt(new ENameMapFor<XMLEBCDICTranscoder>(XMLUni::fgEBCDICEncodingString), XMLRecognizer::EBCDIC);
gMappings->put((void*)XMLUni::fgIBM037EncodingString, new ENameMapFor<XMLEBCDICTranscoder>(XMLUni::fgIBM037EncodingString));
gMappings->put((void*)XMLUni::fgIBM037EncodingString2, new ENameMapFor<XMLEBCDICTranscoder>(XMLUni::fgIBM037EncodingString2));
//hhe
gMappings->put((void*)XMLUni::fgIBM1047EncodingString, new ENameMapFor<XMLIBM1047Transcoder>(XMLUni::fgIBM1047EncodingString));
gMappings->put((void*)XMLUni::fgIBM1047EncodingString2, new ENameMapFor<XMLIBM1047Transcoder>(XMLUni::fgIBM1047EncodingString2));
//
// Add in our mappings for IBM037 with Euro update, i.e. IBM1140. It
// has alias IBM01140, the one suggested by IANA
//
gMappings->put((void*)XMLUni::fgIBM1140EncodingString, new ENameMapFor<XMLIBM1140Transcoder>(XMLUni::fgIBM1140EncodingString));
gMappings->put((void*)XMLUni::fgIBM1140EncodingString2, new ENameMapFor<XMLIBM1140Transcoder>(XMLUni::fgIBM1140EncodingString2));
gMappings->put((void*)XMLUni::fgIBM1140EncodingString3, new ENameMapFor<XMLIBM1140Transcoder>(XMLUni::fgIBM1140EncodingString3));
gMappings->put((void*)XMLUni::fgIBM1140EncodingString4, new ENameMapFor<XMLIBM1140Transcoder>(XMLUni::fgIBM1140EncodingString4));
//
// Add in our mappings for Windows-1252. We don't have any aliases for
// this one, so there is just one mapping.
//
gMappings->put((void*)XMLUni::fgWin1252EncodingString, new ENameMapFor<XMLWin1252Transcoder>(XMLUni::fgWin1252EncodingString));
}
// ---------------------------------------------------------------------------
// XMLTransService: IANA encoding setting
// ---------------------------------------------------------------------------
void XMLTransService::strictIANAEncoding(const bool newState)
{
gStrictIANAEncoding = newState;
}
bool XMLTransService::isStrictIANAEncoding()
{
return gStrictIANAEncoding;
}
// ---------------------------------------------------------------------------
// XMLTranscoder: Public Destructor
// ---------------------------------------------------------------------------
XMLTranscoder::~XMLTranscoder()
{
fMemoryManager->deallocate(fEncodingName);//delete [] fEncodingName;
}
// ---------------------------------------------------------------------------
// XMLTranscoder: Hidden Constructors
// ---------------------------------------------------------------------------
XMLTranscoder::XMLTranscoder(const XMLCh* const encodingName
, const XMLSize_t blockSize
, MemoryManager* const manager) :
fBlockSize(blockSize)
, fEncodingName(0)
, fMemoryManager(manager)
{
fEncodingName = XMLString::replicate(encodingName, fMemoryManager);
}
// ---------------------------------------------------------------------------
// XMLTranscoder: Protected helpers
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// XMLLCPTranscoder: Public Destructor
// ---------------------------------------------------------------------------
XMLLCPTranscoder::XMLLCPTranscoder()
{
}
// ---------------------------------------------------------------------------
// XMLLCPTranscoder: Hidden Constructors
// ---------------------------------------------------------------------------
XMLLCPTranscoder::~XMLLCPTranscoder()
{
}
// ---------------------------------------------------------------------------
// TranscodeToStr: Public constructors and destructor
// ---------------------------------------------------------------------------
TranscodeToStr::TranscodeToStr(const XMLCh *in, const char *encoding,
MemoryManager *manager)
: fString(0),
fBytesWritten(0),
fMemoryManager(manager)
{
XMLTransService::Codes failReason;
const XMLSize_t blockSize = 2048;
XMLTranscoder* trans = XMLPlatformUtils::fgTransService->makeNewTranscoderFor(encoding, failReason, blockSize, fMemoryManager);
if (!trans) {
ThrowXMLwithMemMgr1
(
TranscodingException
, XMLExcepts::Trans_CantCreateCvtrFor
, encoding
, fMemoryManager
);
}
Janitor<XMLTranscoder> janTrans(trans);
transcode(in, XMLString::stringLen(in), trans);
}
TranscodeToStr::TranscodeToStr(const XMLCh *in, XMLSize_t length, const char *encoding,
MemoryManager *manager)
: fString(0),
fBytesWritten(0),
fMemoryManager(manager)
{
XMLTransService::Codes failReason;
const XMLSize_t blockSize = 2048;
XMLTranscoder* trans = XMLPlatformUtils::fgTransService->makeNewTranscoderFor(encoding, failReason, blockSize, fMemoryManager);
if (!trans) {
ThrowXMLwithMemMgr1
(
TranscodingException
, XMLExcepts::Trans_CantCreateCvtrFor
, encoding
, fMemoryManager
);
}
Janitor<XMLTranscoder> janTrans(trans);
transcode(in, length, trans);
}
TranscodeToStr::TranscodeToStr(const XMLCh *in, XMLTranscoder* trans,
MemoryManager *manager)
: fString(0),
fBytesWritten(0),
fMemoryManager(manager)
{
transcode(in, XMLString::stringLen(in), trans);
}
TranscodeToStr::TranscodeToStr(const XMLCh *in, XMLSize_t length, XMLTranscoder* trans,
MemoryManager *manager)
: fString(0),
fBytesWritten(0),
fMemoryManager(manager)
{
transcode(in, length, trans);
}
TranscodeToStr::~TranscodeToStr()
{
}
// ---------------------------------------------------------------------------
// TranscodeToStr: Private helper methods
// ---------------------------------------------------------------------------
void TranscodeToStr::transcode(const XMLCh *in, XMLSize_t len, XMLTranscoder* trans)
{
if(!in) return;
XMLSize_t allocSize = (len * sizeof(XMLCh)) + 4;
fString.reset((XMLByte*)fMemoryManager->allocate(allocSize), fMemoryManager);
XMLSize_t charsDone = 0;
bool bufferExpanded = false;
while(charsDone < len) {
XMLSize_t charsRead = 0;
fBytesWritten += trans->transcodeTo(in + charsDone, len - charsDone,
fString.get() + fBytesWritten, allocSize - fBytesWritten,
charsRead, XMLTranscoder::UnRep_Throw);
if (charsRead == 0)
{
if (bufferExpanded)
{
ThrowXMLwithMemMgr(TranscodingException, XMLExcepts::Trans_BadSrcSeq, fMemoryManager);
}
// it may have not enough space, try expanding the buffer
allocSize *= 2;
XMLByte *newBuf = (XMLByte*)fMemoryManager->allocate(allocSize);
memcpy(newBuf, fString.get(), fBytesWritten);
fString.reset(newBuf, fMemoryManager);
bufferExpanded = true;
}
else
{
charsDone += charsRead;
bufferExpanded = false;
}
}
// null terminate
if((fBytesWritten + 4) > allocSize) {
allocSize = fBytesWritten + 4;
XMLByte *newBuf = (XMLByte*)fMemoryManager->allocate(allocSize);
memcpy(newBuf, fString.get(), fBytesWritten);
fString.reset(newBuf, fMemoryManager);
}
fString[fBytesWritten + 0] = 0;
fString[fBytesWritten + 1] = 0;
fString[fBytesWritten + 2] = 0;
fString[fBytesWritten + 3] = 0;
}
// ---------------------------------------------------------------------------
// TranscodeFromStr: Public constructors and destructor
// ---------------------------------------------------------------------------
TranscodeFromStr::TranscodeFromStr(const XMLByte *data, XMLSize_t length, const char *encoding,
MemoryManager *manager)
: fString(0),
fCharsWritten(0),
fMemoryManager(manager)
{
XMLTransService::Codes failReason;
const XMLSize_t blockSize = 2048;
XMLTranscoder* trans = XMLPlatformUtils::fgTransService->makeNewTranscoderFor(encoding, failReason, blockSize, fMemoryManager);
if (!trans) {
ThrowXMLwithMemMgr1
(
TranscodingException
, XMLExcepts::Trans_CantCreateCvtrFor
, encoding
, fMemoryManager
);
}
Janitor<XMLTranscoder> janTrans(trans);
transcode(data, length, trans);
}
TranscodeFromStr::TranscodeFromStr(const XMLByte *data, XMLSize_t length, XMLTranscoder *trans,
MemoryManager *manager)
: fString(0),
fCharsWritten(0),
fMemoryManager(manager)
{
transcode(data, length, trans);
}
TranscodeFromStr::~TranscodeFromStr()
{
}
// ---------------------------------------------------------------------------
// TranscodeFromStr: Private helper methods
// ---------------------------------------------------------------------------
void TranscodeFromStr::transcode(const XMLByte *in, XMLSize_t length, XMLTranscoder *trans)
{
if(!in) return;
XMLSize_t allocSize = length + 1;
fString.reset((XMLCh*)fMemoryManager->allocate(allocSize * sizeof(XMLCh)), fMemoryManager);
XMLSize_t csSize = allocSize;
ArrayJanitor<unsigned char> charSizes((unsigned char*)fMemoryManager->allocate(csSize * sizeof(unsigned char)),
fMemoryManager);
XMLSize_t bytesDone = 0;
while(bytesDone < length) {
if((allocSize - fCharsWritten) > csSize) {
csSize = allocSize - fCharsWritten;
charSizes.reset((unsigned char*)fMemoryManager->allocate(csSize * sizeof(unsigned char)), fMemoryManager);
}
XMLSize_t bytesRead = 0;
fCharsWritten += trans->transcodeFrom(in + bytesDone, length - bytesDone,
fString.get() + fCharsWritten, allocSize - fCharsWritten,
bytesRead, charSizes.get());
if(bytesRead == 0)
ThrowXMLwithMemMgr(TranscodingException, XMLExcepts::Trans_BadSrcSeq, fMemoryManager);
bytesDone += bytesRead;
if(((allocSize - fCharsWritten)*sizeof(XMLCh)) < (length - bytesDone))
{
allocSize *= 2;
XMLCh *newBuf = (XMLCh*)fMemoryManager->allocate(allocSize * sizeof(XMLCh));
memcpy(newBuf, fString.get(), fCharsWritten*sizeof(XMLCh));
fString.reset(newBuf, fMemoryManager);
}
}
// null terminate
if((fCharsWritten + 1) > allocSize) {
allocSize = fCharsWritten + 1;
XMLCh *newBuf = (XMLCh*)fMemoryManager->allocate(allocSize * sizeof(XMLCh));
memcpy(newBuf, fString.get(), fCharsWritten*sizeof(XMLCh));
fString.reset(newBuf, fMemoryManager);
}
fString[fCharsWritten] = 0;
}
}