src/xalanc/PlatformSupport/XalanOutputStream.cpp (535 lines of code) (raw):

/* * 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. */ // Class header file... #include "XalanOutputStream.hpp" #include <xercesc/util/TransService.hpp> #include "xalanc/Include/STLHelper.hpp" #include "XalanMessageLoader.hpp" #include "XalanTranscodingServices.hpp" namespace XALAN_CPP_NAMESPACE { const XalanDOMChar XalanOutputStream::s_nlString[] = { XalanUnicode::charLF, 0 }; const XalanDOMChar XalanOutputStream::s_nlCRString[] = { XalanUnicode::charCR, XalanUnicode::charLF, 0 }; const XalanDOMString::size_type XalanOutputStream::s_nlStringLength = sizeof(s_nlString) / sizeof(s_nlString[0]) - 1; const XalanDOMString::size_type XalanOutputStream::s_nlCRStringLength = sizeof(s_nlCRString) / sizeof(s_nlCRString[0]) - 1; XalanOutputStream::XalanOutputStream( MemoryManager& theManager, size_type theBufferSize, size_type theTranscoderBlockSize, bool fThrowTranscodeException) : m_transcoderBlockSize(theTranscoderBlockSize), m_transcoder(0), m_bufferSize(theBufferSize), m_buffer(theManager), m_encoding(theManager), m_writeAsUTF16(false), m_throwTranscodeException(fThrowTranscodeException), m_transcodingBuffer(theManager) { if (m_bufferSize == 0) { m_bufferSize = 1; } m_buffer.reserve(theBufferSize + 1); } XalanOutputStream::~XalanOutputStream() { XalanTranscodingServices::destroyTranscoder(m_transcoder); } void XalanOutputStream::write( const XalanDOMChar* theBuffer, size_type theBufferLength) { assert(theBuffer != 0); if (theBufferLength + m_buffer.size() > m_bufferSize) { flushBuffer(); } if (theBufferLength > m_bufferSize) { assert(m_buffer.empty() == true); doWrite(theBuffer, theBufferLength); } else { m_buffer.insert(m_buffer.end(), theBuffer, theBuffer + theBufferLength); } } void XalanOutputStream::transcode( const XalanDOMChar* theBuffer, size_type theBufferLength, TranscodeVectorType& theDestination) { if (m_transcoder == 0) { if (TranscodeToLocalCodePage( theBuffer, theBufferLength, theDestination) == false) { if (m_throwTranscodeException == true) { XalanDOMString theExceptionBuffer(theDestination.getMemoryManager()); throw TranscodingException( theExceptionBuffer, 0); } } } else { bool fDone = false; // Keep track of the total bytes we've added to the // destination vector, and the total bytes we've // eaten from theBuffer. size_type theTotalBytesFilled = 0; size_type theTotalBytesEaten = 0; // Keep track of the current position in the input buffer, // and amount remaining in the buffer, since we may not be // able to transcode it all at once. const XalanDOMChar* theBufferPosition = theBuffer; size_type theRemainingBufferLength = theBufferLength; // Keep track of the destination size, and the target size, which is // the size of the destination that has not yet been filled with // transcoded characters. Double the buffer size, in case we're // transcoding to a 16-bit encoding. // $$$ ToDo: We need to know the size of an encoding, so we can // do the right thing with the destination size. size_type theDestinationSize = theBufferLength * 2; size_type theTargetSize = theDestinationSize; do { // Resize the buffer... theDestination.resize(theDestinationSize + 1); size_type theSourceBytesEaten = 0; size_type theTargetBytesEaten = 0; XalanTranscodingServices::eCode theResult = m_transcoder->transcode( theBufferPosition, theRemainingBufferLength, reinterpret_cast<XMLByte*>(&theDestination[0]) + theTotalBytesFilled, theTargetSize, theSourceBytesEaten, theTargetBytesEaten); if(theResult != XalanTranscodingServices::OK) { if (m_throwTranscodeException == true) { XalanDOMString theExceptionBuffer(theDestination.getMemoryManager()); throw TranscodingException( theExceptionBuffer, 0); } } theTotalBytesFilled += theTargetBytesEaten; theTotalBytesEaten += theSourceBytesEaten; if (theTotalBytesEaten == theBufferLength) { fDone = true; } else { assert(theTotalBytesEaten < theBufferLength); // Update everything... theBufferPosition += theSourceBytesEaten; theRemainingBufferLength -= theSourceBytesEaten; // The new target size will always be the // current destination size, since we // grow by a factor of 2. This will // need to change if the factor is // every changed. theTargetSize = theDestinationSize; // Grow the destination by a factor of // two 2. See the previous comment if // you want to change this. theDestinationSize = theDestinationSize * 2; } } while(fDone == false); // Resize things, if there are any extra bytes... if (theDestination.size() != theTotalBytesFilled) { theDestination.resize(theTotalBytesFilled); } } } void XalanOutputStream::setOutputEncoding(const XalanDOMString& theEncoding) { // Flush, just in case. This should probably be an error... flushBuffer(); XalanTranscodingServices::destroyTranscoder(m_transcoder); m_transcoder = 0; XalanTranscodingServices::eCode theCode = XalanTranscodingServices::OK; if (XalanTranscodingServices::encodingIsUTF16(theEncoding) == true) { m_writeAsUTF16 = true; } else { m_transcoder = XalanTranscodingServices::makeNewTranscoder( getMemoryManager(), theEncoding, theCode, m_transcoderBlockSize); if (theCode == XalanTranscodingServices::UnsupportedEncoding || theCode == XalanTranscodingServices::SupportFilesNotFound) { XalanDOMString theBuffer(getMemoryManager()); throw UnsupportedEncodingException(theEncoding, theBuffer, 0); } else if (theCode != XalanTranscodingServices::OK) { XalanDOMString theBuffer(getMemoryManager()); throw TranscoderInternalFailureException(theEncoding, theBuffer, 0); } assert(m_transcoder != 0); } m_encoding = theEncoding; const XalanTranscodingServices::XalanXMLByte* theProlog = XalanTranscodingServices::getStreamProlog(theEncoding); assert(theProlog != 0); const size_type theLength = XalanTranscodingServices::length(theProlog); if (theLength > 0) { write(reinterpret_cast<const char*>(theProlog), theLength); } } bool XalanOutputStream::canTranscodeTo(XalanUnicodeChar theChar) const { if (m_transcoder != 0) { return m_transcoder->canTranscodeTo(theChar); } else { // We'll always return true here, since an exception will be // thrown when we try to transcode. We'ed like to enable the // commented out line, if we can ever figure out how to see // if a character can be encoded. return true; } } void XalanOutputStream::flushBuffer() { if (m_buffer.empty() == false) { CollectionClearGuard<BufferType> theGuard(m_buffer); assert(size_type(m_buffer.size()) == m_buffer.size()); doWrite(&*m_buffer.begin(), size_type(m_buffer.size())); } assert(m_buffer.empty() == true); } void XalanOutputStream::doWrite( const XalanDOMChar* theBuffer, size_type theBufferLength) { assert(theBuffer != 0); if (m_writeAsUTF16 == true) { // This is a hack to write UTF-16 through as if it // were just chars. Saves lots of time "transcoding." writeData(reinterpret_cast<const char*>(theBuffer), theBufferLength * 2); } else { transcode(theBuffer, theBufferLength, m_transcodingBuffer); assert(&m_transcodingBuffer[0] != 0); assert(size_type(m_transcodingBuffer.size()) == m_transcodingBuffer.size()); writeData( &m_transcodingBuffer[0], size_type(m_transcodingBuffer.size())); } } void XalanOutputStream::setBufferSize(size_type theBufferSize) { flushBuffer(); if (theBufferSize == 0) { m_bufferSize = 1; } else { m_bufferSize = theBufferSize; } if (m_buffer.size() < m_bufferSize) { // Enlarge the buffer... m_buffer.reserve(theBufferSize + 1); } else if (m_buffer.size() > m_bufferSize) { // Shrink the buffer. // Create a temp buffer and make it // the correct size. BufferType temp(getMemoryManager()); temp.reserve(theBufferSize + 1); // Swap temp with m_buffer so that // m_buffer is now the correct size. temp.swap(m_buffer); } } void XalanOutputStream::newline() { // We've had requests to make this a run-time switch, but for now, // it's compile time only... #if defined(XALAN_NEWLINE_IS_CRLF) write(s_nlCRString, s_nlCRStringLength); #else write(s_nlString, s_nlStringLength); #endif } const XalanDOMChar* XalanOutputStream::getNewlineString() const { // We've had requests to make this a run-time switch, but for now, // it's compile time only... #if defined(XALAN_NEWLINE_IS_CRLF) return s_nlCRString; #else return s_nlString; #endif } XalanOutputStream::XalanOutputStreamException::XalanOutputStreamException( const XalanDOMString& theMessage, MemoryManager& theManager, const Locator* theLocator) : XSLException( theMessage, theManager, theLocator) { } XalanOutputStream::XalanOutputStreamException::XalanOutputStreamException( const XalanDOMString& theMessage, MemoryManager& theManager) : XSLException( theMessage, theManager) { } XalanOutputStream::XalanOutputStreamException::XalanOutputStreamException(const XalanOutputStreamException& other): XSLException(other) { } XalanOutputStream::XalanOutputStreamException::~XalanOutputStreamException() { } const XalanDOMChar* XalanOutputStream::XalanOutputStreamException::getType() const { static const XalanDOMChar s_type[] = { XalanUnicode::charLetter_X, XalanUnicode::charLetter_a, XalanUnicode::charLetter_l, XalanUnicode::charLetter_a, XalanUnicode::charLetter_n, XalanUnicode::charLetter_F, XalanUnicode::charLetter_i, XalanUnicode::charLetter_l, XalanUnicode::charLetter_e, XalanUnicode::charLetter_O, XalanUnicode::charLetter_u, XalanUnicode::charLetter_t, XalanUnicode::charLetter_p, XalanUnicode::charLetter_u, XalanUnicode::charLetter_t, XalanUnicode::charLetter_S, XalanUnicode::charLetter_t, XalanUnicode::charLetter_r, XalanUnicode::charLetter_e, XalanUnicode::charLetter_a, XalanUnicode::charLetter_m, XalanUnicode::charLetter_E, XalanUnicode::charLetter_x, XalanUnicode::charLetter_c, XalanUnicode::charLetter_e, XalanUnicode::charLetter_p, XalanUnicode::charLetter_t, XalanUnicode::charLetter_i, XalanUnicode::charLetter_o, XalanUnicode::charLetter_n, 0 }; return s_type; } const XalanDOMChar* XalanOutputStream::UnsupportedEncodingException::getType() const { static const XalanDOMChar s_type[] = { XalanUnicode::charLetter_U, XalanUnicode::charLetter_n, XalanUnicode::charLetter_s, XalanUnicode::charLetter_u, XalanUnicode::charLetter_p, XalanUnicode::charLetter_p, XalanUnicode::charLetter_o, XalanUnicode::charLetter_r, XalanUnicode::charLetter_t, XalanUnicode::charLetter_e, XalanUnicode::charLetter_d, XalanUnicode::charLetter_E, XalanUnicode::charLetter_n, XalanUnicode::charLetter_c, XalanUnicode::charLetter_o, XalanUnicode::charLetter_d, XalanUnicode::charLetter_i, XalanUnicode::charLetter_n, XalanUnicode::charLetter_g, XalanUnicode::charLetter_E, XalanUnicode::charLetter_x, XalanUnicode::charLetter_c, XalanUnicode::charLetter_e, XalanUnicode::charLetter_p, XalanUnicode::charLetter_t, XalanUnicode::charLetter_i, XalanUnicode::charLetter_o, XalanUnicode::charLetter_n, 0 }; return s_type; } XalanOutputStream::UnsupportedEncodingException::UnsupportedEncodingException( const XalanDOMString& theEncoding, XalanDOMString& theBuffer, const Locator* theLocator) : XalanOutputStreamException( XalanMessageLoader::getMessage( theBuffer, XalanMessages::UnsupportedEncoding_1Param, theEncoding), theBuffer.getMemoryManager(), theLocator), m_encoding( theEncoding, theBuffer.getMemoryManager()) { } XalanOutputStream::UnsupportedEncodingException::UnsupportedEncodingException( const XalanDOMString& theEncoding, XalanDOMString& theBuffer) : XalanOutputStreamException( XalanMessageLoader::getMessage( theBuffer, XalanMessages::UnsupportedEncoding_1Param, theEncoding), theBuffer.getMemoryManager()), m_encoding( theEncoding, theBuffer.getMemoryManager()) { } XalanOutputStream::UnsupportedEncodingException::~UnsupportedEncodingException() { } XalanOutputStream::TranscoderInternalFailureException::TranscoderInternalFailureException( const XalanDOMString& theEncoding, XalanDOMString& theBuffer, const Locator* theLocator) : XalanOutputStreamException( XalanMessageLoader::getMessage( theBuffer, XalanMessages::UnknownErrorOccurredWhileTranscodingToEncoding_1Param, theEncoding), theBuffer.getMemoryManager(), theLocator), m_encoding( theEncoding, theBuffer.getMemoryManager()) { } XalanOutputStream::TranscoderInternalFailureException::TranscoderInternalFailureException(const TranscoderInternalFailureException& other) : XalanOutputStreamException(other), m_encoding( other.m_encoding, other.m_memoryManager) { } XalanOutputStream::TranscoderInternalFailureException::~TranscoderInternalFailureException() { } const XalanDOMChar* XalanOutputStream::TranscoderInternalFailureException::getType() const { static const XalanDOMChar s_type[] = { XalanUnicode::charLetter_T, XalanUnicode::charLetter_r, XalanUnicode::charLetter_a, XalanUnicode::charLetter_n, XalanUnicode::charLetter_s, XalanUnicode::charLetter_c, XalanUnicode::charLetter_o, XalanUnicode::charLetter_d, XalanUnicode::charLetter_e, XalanUnicode::charLetter_r, XalanUnicode::charLetter_I, XalanUnicode::charLetter_n, XalanUnicode::charLetter_t, XalanUnicode::charLetter_e, XalanUnicode::charLetter_r, XalanUnicode::charLetter_n, XalanUnicode::charLetter_a, XalanUnicode::charLetter_l, XalanUnicode::charLetter_F, XalanUnicode::charLetter_a, XalanUnicode::charLetter_i, XalanUnicode::charLetter_l, XalanUnicode::charLetter_u, XalanUnicode::charLetter_r, XalanUnicode::charLetter_e, XalanUnicode::charLetter_E, XalanUnicode::charLetter_x, XalanUnicode::charLetter_c, XalanUnicode::charLetter_e, XalanUnicode::charLetter_p, XalanUnicode::charLetter_t, XalanUnicode::charLetter_i, XalanUnicode::charLetter_o, XalanUnicode::charLetter_n, 0 }; return s_type; } XalanOutputStream::TranscodingException::TranscodingException( XalanDOMString& theBuffer, const Locator* theLocator) : XalanOutputStreamException( XalanMessageLoader::getMessage( theBuffer, XalanMessages::AnErrorOccurredWhileTranscoding), theBuffer.getMemoryManager(), theLocator) { } XalanOutputStream::TranscodingException::TranscodingException(const TranscodingException& other) : XalanOutputStreamException(other) { } XalanOutputStream::TranscodingException::~TranscodingException() { } const XalanDOMChar* XalanOutputStream::TranscodingException::getType() const { static const XalanDOMChar s_type[] = { XalanUnicode::charLetter_T, XalanUnicode::charLetter_r, XalanUnicode::charLetter_a, XalanUnicode::charLetter_n, XalanUnicode::charLetter_s, XalanUnicode::charLetter_c, XalanUnicode::charLetter_o, XalanUnicode::charLetter_d, XalanUnicode::charLetter_i, XalanUnicode::charLetter_n, XalanUnicode::charLetter_g, XalanUnicode::charLetter_E, XalanUnicode::charLetter_x, XalanUnicode::charLetter_c, XalanUnicode::charLetter_e, XalanUnicode::charLetter_p, XalanUnicode::charLetter_t, XalanUnicode::charLetter_i, XalanUnicode::charLetter_o, XalanUnicode::charLetter_n, 0 }; return s_type; } XalanDOMString& XalanOutputStream::formatMessage( const XalanDOMString& theMessage, int theErrorCode, XalanDOMString& theBuffer) { XalanDOMString strErrorCode(theBuffer.getMemoryManager()); XalanDOMString strErrorMsg(theBuffer.getMemoryManager()); NumberToDOMString(theErrorCode, strErrorCode); theBuffer.assign(theMessage); XalanMessageLoader::getMessage( strErrorMsg, XalanMessages::SystemErrorCode_1Param, strErrorCode); theBuffer.append(strErrorMsg); return theBuffer; } }