| /* |
| * 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. |
| */ |
| #if !defined(XALANUNICODESUBSETWRITER_HEADER_GUARD_1357924680) |
| #define XALANUNICODESUBSETWRITER_HEADER_GUARD_1357924680 |
| |
| |
| #include <xalanc/XMLSupport/XalanFormatterWriter.hpp> |
| |
| |
| |
| namespace XALAN_CPP_NAMESPACE { |
| |
| |
| |
| |
| template <class Predicate, |
| class ConstantsType> |
| class XalanOtherEncodingWriter : public XalanFormatterWriter |
| { |
| public: |
| |
| typedef XalanOtherEncodingWriter<Predicate, ConstantsType> ThisType; |
| |
| class WriteCharRef |
| { |
| public: |
| |
| WriteCharRef(ThisType& writer) : |
| m_writer(writer) |
| { |
| } |
| |
| void |
| operator()(XalanUnicodeChar value) const |
| { |
| m_writer.writeNumericCharacterReference(value); |
| } |
| |
| private: |
| |
| ThisType& m_writer; |
| }; |
| |
| class ThrowTranscodingException |
| { |
| public: |
| |
| ThrowTranscodingException(ThisType& writer) : |
| m_writer(writer) |
| { |
| } |
| |
| void |
| operator()(XalanUnicodeChar value) const |
| { |
| m_writer.throwUnrepresentableCharacterException( |
| value, |
| m_writer.getMemoryManager()); |
| } |
| |
| private: |
| |
| ThisType& m_writer; |
| }; |
| |
| friend class WriteCharRef; |
| friend class ThrowTranscodingException; |
| |
| typedef XalanDOMChar value_type; |
| |
| XalanOtherEncodingWriter( |
| Writer& writer, |
| MemoryManager& theMemoryManager) : |
| XalanFormatterWriter( |
| writer, |
| theMemoryManager), |
| m_buffer(), |
| m_bufferPosition(m_buffer), |
| m_bufferRemaining(kBufferSize), |
| m_predicate(writer.getStream()), |
| m_constants(), |
| m_charRefFunctor(*this), |
| m_exceptionFunctor(*this) |
| { |
| } |
| |
| virtual |
| ~XalanOtherEncodingWriter() |
| { |
| } |
| |
| /** |
| * Output a line break. |
| */ |
| void |
| outputNewline() |
| { |
| assert(m_newlineString != 0); |
| assert(length(m_newlineString) == m_newlineStringLength); |
| |
| write( |
| m_newlineString, |
| m_newlineStringLength); |
| } |
| |
| /** |
| * Writes CDATA chars , if not presentable, fixes it |
| * with addition CDATA sections |
| */ |
| size_type |
| writeCDATAChar( |
| const XalanDOMChar chars[], |
| size_type start, |
| size_type length, |
| bool& outsideCDATA) |
| { |
| assert(chars != 0 && length > 0 && start < length); |
| |
| const XalanDOMChar theChar = chars[start]; |
| |
| XalanUnicodeChar value = theChar; |
| |
| size_type result = start; |
| |
| if (isUTF16HighSurrogate(theChar) == true) |
| { |
| if (start + 1 >= length) |
| { |
| throwInvalidUTF16SurrogateException( |
| theChar, |
| 0, |
| getMemoryManager()); |
| } |
| else |
| { |
| value = decodeUTF16SurrogatePair(theChar, chars[start+1], getMemoryManager()); |
| |
| ++result; |
| } |
| } |
| |
| if(m_predicate(value)) |
| { |
| if (outsideCDATA == false) |
| { |
| // We have a representable char in the normal state, |
| // so just print it. |
| write(value); |
| } |
| else |
| { |
| // The previous character was a not representable. |
| // Open the CDATA section again, print the character, |
| // then change the flag. |
| write( |
| m_constants.s_cdataOpenString, |
| m_constants.s_cdataOpenStringLength); |
| |
| write(value); |
| |
| outsideCDATA = false; |
| } |
| } |
| else |
| { |
| if(outsideCDATA == false) |
| { |
| // we have a non-representable char in the normal state - |
| // close the CDATA section and print the value |
| write( |
| m_constants.s_cdataCloseString, |
| m_constants.s_cdataCloseStringLength); |
| |
| writeNumericCharacterReference(value); |
| |
| outsideCDATA = true; |
| } |
| else |
| { |
| writeNumericCharacterReference(value); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Writes name characters. If a character is not representable, |
| * an exception is thrown. |
| */ |
| void |
| writeNameChar( |
| const XalanDOMChar* data, |
| size_type theLength) |
| { |
| for( size_type i = 0; i < theLength; ++i) |
| { |
| i = write(data, i , theLength, m_exceptionFunctor); |
| } |
| } |
| |
| /** |
| * Writes PI characters. If a character is not representable, |
| * an exception is thrown. |
| */ |
| void |
| writePIChars( |
| const XalanDOMChar* data, |
| size_type theLength) |
| { |
| for( size_type i = 0; i < theLength; ) |
| { |
| i = write(data, i , theLength, m_exceptionFunctor); |
| } |
| } |
| |
| /** |
| * Writes comment characters. If a character is not representable, |
| * or must be written as a character reference for compatibility with |
| * XML 1.1, an exception is thrown. |
| */ |
| void |
| writeCommentChars( |
| const XalanDOMChar* data, |
| size_type theLength) |
| { |
| for( size_type i = 0; i < theLength; ) |
| { |
| i = write(data, i , theLength, m_exceptionFunctor); |
| } |
| } |
| |
| void |
| write( |
| const XalanDOMChar* theChars, |
| size_type theLength) |
| { |
| for(size_type i = 0; i < theLength; ++i) |
| { |
| write(theChars[i]); |
| } |
| } |
| |
| void |
| write(const XalanDOMString& theChars) |
| { |
| write(theChars.c_str(), theChars.length()); |
| } |
| |
| /** |
| * Writes writes a UTF-16 code unit that isn't |
| * part of the surrogate pair |
| */ |
| void |
| write(XalanDOMChar theChar) |
| { |
| assert( |
| isUTF16HighSurrogate(theChar) == false && |
| isUTF16LowSurrogate(theChar) == false); |
| |
| if (m_bufferRemaining == 0) |
| { |
| flushBuffer(); |
| } |
| |
| if(m_predicate(theChar)) |
| { |
| *m_bufferPosition = theChar; |
| |
| ++m_bufferPosition; |
| --m_bufferRemaining; |
| } |
| else |
| { |
| writeNumericCharacterReference(theChar); |
| } |
| } |
| |
| size_type |
| write( |
| const XalanDOMChar chars[], |
| size_type start, |
| size_type length) |
| { |
| |
| return write(chars, start, length, m_charRefFunctor); |
| } |
| |
| void |
| writeSafe( |
| const XalanDOMChar* theChars, |
| size_type theLength) |
| { |
| for(size_type i = 0; i < theLength; ++i) |
| { |
| const XalanDOMChar ch = theChars[i]; |
| |
| if (isUTF16HighSurrogate(ch) == true) |
| { |
| if (i + 1 >= theLength) |
| { |
| throwInvalidUTF16SurrogateException(ch, 0, getMemoryManager()); |
| } |
| else |
| { |
| XalanUnicodeChar value = decodeUTF16SurrogatePair(ch, theChars[i+1], getMemoryManager()); |
| |
| if (this->m_isPresentable(value)) |
| { |
| write(value); |
| } |
| else |
| { |
| this->writeNumberedEntityReference(value); |
| } |
| |
| ++i; |
| } |
| } |
| else |
| { |
| write(static_cast<XalanUnicodeChar>(ch)); |
| } |
| } |
| } |
| |
| void |
| write(const XalanDOMChar* theChars) |
| { |
| write(theChars, XalanDOMString::length(theChars)); |
| } |
| |
| void |
| flushWriter() |
| { |
| m_writer.flush(); |
| } |
| |
| void |
| flushBuffer() |
| { |
| m_writer.write(m_buffer, 0, m_bufferPosition - m_buffer); |
| |
| m_bufferPosition = m_buffer; |
| m_bufferRemaining = kBufferSize; |
| } |
| |
| private: |
| |
| /** |
| * Writes a representable code point |
| * |
| * @param chars Array of the characters for transcoding |
| * |
| * @param start Place int the array the transcoding should start |
| * |
| * @param length The length of the array |
| * |
| * @param failureHandler The functor handles the non-representable characters |
| * |
| * @return Place int the array of the next character |
| */ |
| |
| template <class TranscodingFailureFunctor> |
| size_type |
| write( |
| const XalanDOMChar chars[], |
| size_type start, |
| size_type length, |
| TranscodingFailureFunctor& failureHandler) |
| { |
| assert(chars != 0 && length > 0); |
| assert(start <= length); |
| |
| size_type result = start; |
| |
| const XalanDOMChar ch = chars[start]; |
| |
| XalanUnicodeChar value = ch; |
| |
| if (isUTF16HighSurrogate(ch) == true) |
| { |
| if (start + 1 >= length) |
| { |
| throwInvalidUTF16SurrogateException( |
| ch, |
| 0, |
| getMemoryManager()); |
| } |
| else |
| { |
| value = decodeUTF16SurrogatePair(ch, chars[start+1], getMemoryManager()); |
| |
| ++result; |
| } |
| } |
| |
| if(m_predicate(value)) |
| { |
| write(value); |
| } |
| else |
| { |
| failureHandler(value); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Writes a representable code point |
| * |
| * @param theChar UTF-32 code point . For passing it to the Xerces |
| * transcoder, we convert it back to UTF-16 |
| */ |
| void |
| write(XalanUnicodeChar theChar) |
| { |
| // encode back UTF-32 into UTF-16 |
| |
| if (theChar > 0xFFFF) |
| { |
| if (m_bufferRemaining < 2) |
| { |
| flushBuffer(); |
| } |
| |
| *m_bufferPosition = static_cast<XalanDOMChar>((theChar >> 10) + 0xD7C0); |
| |
| ++m_bufferPosition; |
| |
| *m_bufferPosition = static_cast<XalanDOMChar>((theChar & 0x03FF) + 0xDC00); |
| |
| ++m_bufferPosition; |
| |
| m_bufferRemaining = m_bufferRemaining - size_type(2); |
| } |
| else |
| { |
| if (m_bufferRemaining == 0) |
| { |
| flushBuffer(); |
| } |
| |
| *m_bufferPosition = XalanDOMChar(theChar); |
| |
| ++m_bufferPosition; |
| --m_bufferRemaining; |
| } |
| } |
| |
| void |
| writeNumericCharacterReference(XalanUnicodeChar theChar) |
| { |
| const XalanDOMString& theString = |
| formatNumericCharacterReference(theChar); |
| |
| const XalanDOMString::size_type theLength = |
| theString.length(); |
| |
| if (m_bufferRemaining < theLength) |
| { |
| flushBuffer(); |
| } |
| |
| using std::copy; |
| |
| assert(theString.size() <= m_bufferRemaining); |
| |
| m_bufferPosition = |
| copy( |
| theString.begin(), |
| theString.end(), |
| m_bufferPosition); |
| |
| m_bufferRemaining -= theLength; |
| } |
| |
| enum |
| { |
| // The size of the buffer. The minimum for this |
| // is the length of the longest numeric character |
| // reference that can be written. |
| kBufferSize = 512u |
| }; |
| |
| |
| // Data members... |
| XalanDOMChar m_buffer[kBufferSize]; |
| |
| XalanDOMChar* m_bufferPosition; |
| |
| size_type m_bufferRemaining; |
| |
| const Predicate m_predicate; |
| |
| const ConstantsType m_constants; |
| |
| const WriteCharRef m_charRefFunctor; |
| |
| const ThrowTranscodingException m_exceptionFunctor; |
| }; |
| |
| |
| |
| } |
| |
| |
| |
| #endif // XALANUNICODESUBSETWRITER_HEADER_GUARD_1357924680 |