blob: 1be70f8799efd8e707349fa4e91a2be0047ef566 [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed 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 "FormatterToXMLBase.hpp"
#include <xercesc/sax/SAXException.hpp>
#include <xalanc/PlatformSupport/DOMStringHelper.hpp>
#include <xalanc/PlatformSupport/XalanMessageLoader.hpp>
#include <xalanc/PlatformSupport/Writer.hpp>
#include <xalanc/PlatformSupport/XalanOutputStream.hpp>
XALAN_CPP_NAMESPACE_BEGIN
const XalanDOMChar FormatterToXMLBase::s_specialChars[kSpecialsSize] =
{
kNotSpecial, // 0
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kAttributeSpecial, // 0x9 -- horizontal tab. Write as a numeric character reference in attribute values.
kBothSpecial, // 0xA -- linefeed Normalize as requested, and write as a numeric character reference in attribute values.
kNotSpecial,
kNotSpecial,
kAttributeSpecial, // 0xD -- carriage return. Write as a numeric character reference in attribute values.
kNotSpecial,
kNotSpecial,
kNotSpecial, // 0x10
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial, // 0x20
kNotSpecial,
kAttributeSpecial, // 0x22 '"'
kNotSpecial,
kNotSpecial,
kNotSpecial,
kBothSpecial, // 0x26 -- '&'
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial, // 0x30
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kNotSpecial,
kBothSpecial, // 0x3C '<'
kNotSpecial,
kBothSpecial // 0x3E '>'
};
FormatterToXMLBase::FormatterToXMLBase(
Writer& writer,
const XalanDOMString& version,
const XalanDOMString& mediaType,
const XalanDOMString& doctypeSystem,
const XalanDOMString& doctypePublic,
bool xmlDecl,
const XalanDOMString& standalone) :
FormatterListener(OUTPUT_METHOD_XML),
m_writer(&writer),
m_nextIsRaw(false),
m_spaceBeforeClose(false),
m_doctypeSystem(doctypeSystem),
m_doctypePublic(doctypePublic),
m_version(version),
m_standalone(standalone),
m_mediaType(mediaType),
m_newlineString(0),
m_newlineStringLength(0),
m_needToOutputDoctypeDecl(false),
// We must write the XML declaration if standalone is specified
m_shouldWriteXMLHeader(xmlDecl == true ? true : standalone.length() != 0),
m_elemStack()
{
if(isEmpty(m_doctypePublic) == false)
{
if(startsWith(
m_doctypePublic,
s_xhtmlDocTypeString) == true)
{
m_spaceBeforeClose = true;
}
}
const XalanOutputStream* const theStream = writer.getStream();
if (theStream == 0)
{
m_newlineString = XalanOutputStream::defaultNewlineString();
}
else
{
m_newlineString = theStream->getNewlineString();
}
assert(m_newlineString != 0);
m_newlineStringLength = length(m_newlineString);
assert(m_newlineString != 0);
}
FormatterToXMLBase::~FormatterToXMLBase()
{
}
unsigned int
FormatterToXMLBase::decodeUTF16SurrogatePair(
XalanDOMChar theHighSurrogate,
XalanDOMChar theLowSurrogate)
{
assert(isUTF16HighSurrogate(theHighSurrogate) == true);
if (isUTF16LowSurrogate(theLowSurrogate) == false)
{
throwInvalidUTF16SurrogateException(theHighSurrogate, theLowSurrogate);
}
return ((theHighSurrogate - 0xD800u) << 10) + theLowSurrogate - 0xDC00u + 0x00010000u;
}
XALAN_USING_XERCES(SAXException)
void
FormatterToXMLBase::throwInvalidUTF16SurrogateException(XalanDOMChar ch)
{
const XalanDOMString theMessage = XalanMessageLoader::getMessage(XalanMessages::InvalidUFT16Surrogate_2Param, UnsignedLongToHexDOMString(ch));
throw SAXException(c_wstr(theMessage));
}
void
FormatterToXMLBase::throwInvalidUTF16SurrogateException(
XalanDOMChar ch,
XalanDOMChar next)
{
const XalanDOMString theMessage = XalanMessageLoader::getMessage(XalanMessages::InvalidUFT16Surrogate_2Param, UnsignedLongToHexDOMString(ch),UnsignedLongToHexDOMString(next));
throw SAXException(c_wstr(theMessage));
}
void
FormatterToXMLBase::throwInvalidCharacterException(unsigned int ch)
{
const XalanDOMString theMessage = XalanMessageLoader::getMessage(XalanMessages::InvalidCharDetected_1Param, UnsignedLongToHexDOMString(ch));
throw SAXException(c_wstr(theMessage));
}
void
FormatterToXMLBase::flushWriter()
{
m_writer->flush();
}
void
FormatterToXMLBase::setDocumentLocator(const LocatorType* const /* locator */)
{
}
void
FormatterToXMLBase::startDocument()
{
if (m_doctypeSystem.empty() == false)
{
m_needToOutputDoctypeDecl = true;
}
if(m_shouldWriteXMLHeader == true)
{
writeXMLHeader();
// Write a newline here, so the DOCTYPE comes out on a separate line
if (m_needToOutputDoctypeDecl == true)
{
outputNewline();
}
}
}
void
FormatterToXMLBase::endDocument()
{
m_needToOutputDoctypeDecl = false;
flushBuffer();
}
void
FormatterToXMLBase::characters(
const XMLCh* const chars,
const unsigned int length)
{
if(length != 0)
{
if(m_nextIsRaw)
{
m_nextIsRaw = false;
charactersRaw(chars, length);
}
else
{
writeCharacters(chars, length);
}
}
}
void
FormatterToXMLBase::cdata(
const XMLCh* const ch,
const unsigned int length)
{
if (length != 0)
{
if(m_nextIsRaw == true)
{
m_nextIsRaw = false;
charactersRaw(ch, length);
}
else
{
writeCDATA(ch, length);
}
}
}
void
FormatterToXMLBase::processingInstruction(
const XMLCh* const target,
const XMLCh* const data)
{
// Use a fairly nasty hack to tell if the next node is supposed to be
// unescaped text.
if(equals(target, length(target), s_piTarget, s_piTargetLength) == true &&
equals(data, length(data), s_piData, s_piDataLength) == true)
{
m_nextIsRaw = true;
}
else
{
writeProcessingInstruction(target, data);
}
}
void
FormatterToXMLBase::ignorableWhitespace(
const XMLCh* const chars,
const unsigned int length)
{
if (length > 0)
{
characters(chars, length);
}
}
Writer*
FormatterToXMLBase::getWriter() const
{
return m_writer;
}
const XalanDOMString&
FormatterToXMLBase::getDoctypeSystem() const
{
return m_doctypeSystem;
}
const XalanDOMString&
FormatterToXMLBase::getDoctypePublic() const
{
return m_doctypePublic;
}
const XalanDOMString&
FormatterToXMLBase::getMediaType() const
{
return m_mediaType;
}
void
FormatterToXMLBase::resetDocument()
{
// I don't do anything with this yet.
}
#define FXML_SIZE(str) ((sizeof(str) / sizeof(str[0]) - 1))
const XalanDOMChar FormatterToXMLBase::s_xhtmlDocTypeString[] =
{
XalanUnicode::charHyphenMinus,
XalanUnicode::charSolidus,
XalanUnicode::charSolidus,
XalanUnicode::charLetter_W,
XalanUnicode::charDigit_3,
XalanUnicode::charLetter_C,
XalanUnicode::charSolidus,
XalanUnicode::charSolidus,
XalanUnicode::charLetter_D,
XalanUnicode::charLetter_T,
XalanUnicode::charLetter_D,
XalanUnicode::charSpace,
XalanUnicode::charLetter_X,
XalanUnicode::charLetter_H,
XalanUnicode::charLetter_T,
XalanUnicode::charLetter_M,
XalanUnicode::charLetter_L,
XalanDOMChar(0)
};
const XalanDOMString::size_type FormatterToXMLBase::s_xhtmlDocTypeStringLength =
FXML_SIZE(s_xhtmlDocTypeString);
XALAN_CPP_NAMESPACE_END