source: icXML/icXML-devel/src/xercesc/dom/impl/DOMLSSerializerImpl.cpp @ 2722

Last change on this file since 2722 was 2722, checked in by cameron, 6 years ago

Original Xerces files with import mods for icxercesc

File size: 60.2 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: DOMLSSerializerImpl.cpp 768978 2009-04-27 13:45:52Z amassari $
20 */
21
22#include "DOMLSSerializerImpl.hpp"
23#include "DOMLSOutputImpl.hpp"
24#include "DOMErrorImpl.hpp"
25#include "DOMLocatorImpl.hpp"
26#include "DOMImplementationImpl.hpp"
27#include "DOMStringListImpl.hpp"
28
29#include <xercesc/framework/MemBufFormatTarget.hpp>
30#include <xercesc/framework/LocalFileFormatTarget.hpp>
31
32#include <icxercesc/util/TransService.hpp>
33#include <xercesc/util/TranscodingException.hpp>
34#include <xercesc/util/Janitor.hpp>
35#include <icxercesc/util/XMLString.hpp>
36#include <xercesc/util/XMLUniDefs.hpp>
37#include <xercesc/util/XMLMsgLoader.hpp>
38#include <xercesc/dom/StDOMNode.hpp>
39#include <xercesc/util/OutOfMemoryException.hpp>
40#include <xercesc/util/XMLChar.hpp>
41
42XERCES_CPP_NAMESPACE_BEGIN
43
44
45// ---------------------------------------------------------------------------
46//  Local const data
47//
48// ---------------------------------------------------------------------------
49
50static const int INVALID_FEATURE_ID               = -1;
51static const int CANONICAL_FORM_ID                = 0x0;
52static const int DISCARD_DEFAULT_CONTENT_ID       = 0x1;
53static const int ENTITIES_ID                      = 0x2;
54static const int FORMAT_PRETTY_PRINT_ID           = 0x3;
55static const int NORMALIZE_CHARACTERS_ID          = 0x4;
56static const int SPLIT_CDATA_SECTIONS_ID          = 0x5;
57static const int VALIDATION_ID                    = 0x6;
58static const int WHITESPACE_IN_ELEMENT_CONTENT_ID = 0x7;
59static const int BYTE_ORDER_MARK_ID               = 0x8;
60static const int XML_DECLARATION                  = 0x9;
61static const int FORMAT_PRETTY_PRINT_1ST_LEVEL_ID = 0xA;
62
63//    feature                      true                       false
64// ================================================================================
65//canonical-form                 [optional] Not Supported     [required] (default)
66//discard-default-content        [required] (default)         [required]
67//entity                         [required] (default)         [optional]
68//format-pretty-print            [optional] Partially Supported [required] (default)
69//normalize-characters           [optional] Not Supported     [required] (default)
70//split-cdata-sections           [required] (default)         [required]
71//validation                     [optional] Not Supported     [required] (default)
72//whitespace-in-element-content  [requierd] (default)         [optional] Not Supported
73//
74
75//
76// Each feature has 2 entries in this array,
77// the first for "true",
78// the second for "false".
79//
80static const bool  featuresSupported[] = {
81    false, true,  // canonical-form
82    true,  true,  // discard-default-content
83    true,  true,  // entity
84    true,  true,  // format-pretty-print
85    false, true,  // normalize-characters
86    true,  true,  // split-cdata-sections
87    false, true,  // validation
88    true,  false, // whitespace-in-element-content
89    true,  true,  // http://apache.org/xml/features/dom/byte-order-mark
90    true,  true,  // xml-declaration
91    true,  true   // http://apache.org/xml/features/pretty-print/space-first-level-elements
92};
93
94// default end-of-line sequence
95static const XMLCh  gEOLSeq[] =
96{
97    chLF, chNull
98};
99
100//UTF-8
101static const XMLCh  gUTF8[] =
102{
103    chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull
104};
105
106//</
107static const XMLCh  gEndElement[] =
108{
109    chOpenAngle, chForwardSlash, chNull
110};
111
112//?>
113static const XMLCh  gEndPI[] =
114{
115    chQuestion, chCloseAngle, chNull
116};
117
118//<?
119static const XMLCh  gStartPI[] =
120{
121    chOpenAngle, chQuestion, chNull
122};
123
124//<?xml version="
125static const XMLCh  gXMLDecl_VersionInfo[] =
126{
127    chOpenAngle, chQuestion, chLatin_x,     chLatin_m,  chLatin_l,  chSpace,
128    chLatin_v,   chLatin_e,  chLatin_r,     chLatin_s,  chLatin_i,  chLatin_o,
129    chLatin_n,   chEqual,    chDoubleQuote, chNull
130};
131
132static const XMLCh gXMLDecl_ver10[] =
133{
134    chDigit_1, chPeriod, chDigit_0, chNull
135};
136
137//encoding="
138static const XMLCh  gXMLDecl_EncodingDecl[] =
139{
140    chLatin_e,  chLatin_n,  chLatin_c,  chLatin_o,      chLatin_d, chLatin_i,
141    chLatin_n,  chLatin_g,  chEqual,    chDoubleQuote,  chNull
142};
143
144//" standalone="
145static const XMLCh  gXMLDecl_SDDecl[] =
146{
147    chLatin_s, chLatin_t, chLatin_a,   chLatin_n,    chLatin_d,   chLatin_a,
148    chLatin_l, chLatin_o, chLatin_n,   chLatin_e,    chEqual,     chDoubleQuote,
149    chNull
150};
151
152//"
153static const XMLCh  gXMLDecl_separator[] =
154{
155    chDoubleQuote, chSpace, chNull
156};
157
158//?>
159static const XMLCh  gXMLDecl_endtag[] =
160{
161    chQuestion, chCloseAngle,  chNull
162};
163
164//<![CDATA[
165static const XMLCh  gStartCDATA[] =
166{
167    chOpenAngle, chBang,    chOpenSquare, chLatin_C, chLatin_D,
168    chLatin_A,   chLatin_T, chLatin_A,    chOpenSquare, chNull
169};
170
171//]]>
172static const XMLCh  gEndCDATA[] =
173{
174//    chCloseSquare, chCloseAngle, chCloseAngle, chNull  // test only: ]>>
175      chCloseSquare, chCloseSquare, chCloseAngle, chNull
176};
177
178//<!--
179static const XMLCh  gStartComment[] =
180{
181    chOpenAngle, chBang, chDash, chDash, chNull
182};
183
184//-->
185static const XMLCh  gEndComment[] =
186{
187    chDash, chDash, chCloseAngle, chNull
188};
189
190//<!DOCTYPE
191static const XMLCh  gStartDoctype[] =
192{
193    chOpenAngle, chBang,    chLatin_D, chLatin_O, chLatin_C, chLatin_T,
194    chLatin_Y,   chLatin_P, chLatin_E, chSpace,   chNull
195};
196
197//PUBLIC "
198static const XMLCh  gPublic[] =
199{
200    chLatin_P, chLatin_U, chLatin_B,     chLatin_L, chLatin_I,
201    chLatin_C, chSpace,   chDoubleQuote, chNull
202};
203
204//SYSTEM "
205static const XMLCh  gSystem[] =
206{
207    chLatin_S, chLatin_Y, chLatin_S,     chLatin_T, chLatin_E,
208    chLatin_M, chSpace,   chDoubleQuote, chNull
209};
210
211//<!ENTITY
212static const XMLCh  gStartEntity[] =
213{
214    chOpenAngle, chBang,    chLatin_E, chLatin_N, chLatin_T, chLatin_I,
215    chLatin_T,   chLatin_Y, chSpace,   chNull
216};
217
218//NDATA "
219static const XMLCh  gNotation[] =
220{
221    chLatin_N, chLatin_D,     chLatin_A, chLatin_T, chLatin_A,
222    chSpace,   chDoubleQuote, chNull
223};
224
225static const XMLByte  BOM_utf8[]    = {(XMLByte)0xEF, (XMLByte)0xBB, (XMLByte)0xBF, (XMLByte) 0};
226static const XMLByte  BOM_utf16be[] = {(XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
227static const XMLByte  BOM_utf16le[] = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte) 0};
228static const XMLByte  BOM_ucs4be[]  = {(XMLByte)0x00, (XMLByte)0x00, (XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
229static const XMLByte  BOM_ucs4le[]  = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte)0x00, (XMLByte)0x00, (XMLByte) 0};
230
231//
232// Notification of the error though error handler
233//
234// The application may instruct the engine to abort serialization
235// by returning "false".
236//
237// REVISIT: update the locator ctor once the line#, col#, uri and offset
238// are available from DOM3 core
239//
240// REVISIT: use throwing exception to abort serialization is an interesting
241// thing here, since the serializer is a recusive function, we
242// can't use return, obviously. However we may have multiple try/catch
243// along its way going back to write(). So far we don't come up with a
244// "short-cut" to go "directly" back.
245//
246#define  TRY_CATCH_THROW(action)                                     \
247fFormatter->setUnRepFlags(XMLFormatter::UnRep_Fail);                 \
248try                                                                  \
249{                                                                    \
250    action;                                                          \
251}                                                                    \
252catch(TranscodingException const &e)                                 \
253{                                                                    \
254    reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, e.getMessage());  \
255    throw e;                                                         \
256}
257
258DOMLSSerializerImpl::~DOMLSSerializerImpl()
259{
260    fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
261    delete fNamespaceStack;
262    delete fSupportedParameters;
263    // we don't own/adopt error handler and filter
264}
265
266DOMLSSerializerImpl::DOMLSSerializerImpl(MemoryManager* const manager)
267:fFeatures(0)
268,fNewLine(0)
269,fErrorHandler(0)
270,fFilter(0)
271,fDocumentVersion(XMLUni::fgVersion1_0)
272,fSupportedParameters(0)
273,fEncodingUsed(0)
274,fNewLineUsed(0)
275,fFormatter(0)
276,fErrorCount(0)
277,fCurrentLine(0)
278,fLineFeedInTextNodePrinted(false)
279,fLastWhiteSpaceInTextNode(0)
280,fNamespaceStack(0)
281,fMemoryManager(manager)
282{
283    fNamespaceStack=new (fMemoryManager) RefVectorOf< RefHashTableOf<XMLCh> >(0,true, fMemoryManager);
284
285    //
286    // set features to default setting
287    //
288    setFeature(CANONICAL_FORM_ID,                false);
289    setFeature(DISCARD_DEFAULT_CONTENT_ID,       true );
290    setFeature(ENTITIES_ID,                      true );
291    setFeature(FORMAT_PRETTY_PRINT_ID,           false);
292    setFeature(NORMALIZE_CHARACTERS_ID,          false);
293    setFeature(SPLIT_CDATA_SECTIONS_ID,          true );
294    setFeature(VALIDATION_ID,                    false);
295    setFeature(WHITESPACE_IN_ELEMENT_CONTENT_ID, true );
296    setFeature(BYTE_ORDER_MARK_ID,               false);
297    setFeature(XML_DECLARATION,                  true );
298    setFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID, true );
299
300    fSupportedParameters=new (fMemoryManager) DOMStringListImpl(12, fMemoryManager);
301    fSupportedParameters->add(XMLUni::fgDOMErrorHandler);
302    fSupportedParameters->add(XMLUni::fgDOMWRTCanonicalForm);
303    fSupportedParameters->add(XMLUni::fgDOMWRTDiscardDefaultContent);
304    fSupportedParameters->add(XMLUni::fgDOMWRTEntities);
305    fSupportedParameters->add(XMLUni::fgDOMWRTFormatPrettyPrint);
306    fSupportedParameters->add(XMLUni::fgDOMWRTNormalizeCharacters);
307    fSupportedParameters->add(XMLUni::fgDOMWRTSplitCdataSections);
308    fSupportedParameters->add(XMLUni::fgDOMWRTValidation);
309    fSupportedParameters->add(XMLUni::fgDOMWRTWhitespaceInElementContent);
310    fSupportedParameters->add(XMLUni::fgDOMWRTBOM);
311    fSupportedParameters->add(XMLUni::fgDOMXMLDeclaration);
312    fSupportedParameters->add(XMLUni::fgDOMWRTXercesPrettyPrint);
313}
314
315bool DOMLSSerializerImpl::canSetParameter(const XMLCh* featName
316                                        , const void*  /*value*/) const
317{
318    if(XMLString::compareIStringASCII(featName, XMLUni::fgDOMErrorHandler)==0)
319        return true;
320    return false;
321}
322
323bool DOMLSSerializerImpl::canSetParameter(const XMLCh* featName
324                                        , bool         state) const
325{
326    int featureId = INVALID_FEATURE_ID;
327    return checkFeature(featName, false, featureId) ? canSetFeature(featureId, state) : false;
328}
329
330void DOMLSSerializerImpl::setParameter(const XMLCh* featName
331                                     , const void*  value)
332{
333    if(XMLString::compareIStringASCII(featName, XMLUni::fgDOMErrorHandler)==0)
334        fErrorHandler = (DOMErrorHandler*)value;
335    else
336        throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, fMemoryManager);
337}
338
339void DOMLSSerializerImpl::setParameter(const XMLCh* featName
340                                     , bool         state)
341{
342    int featureId = INVALID_FEATURE_ID;
343    checkFeature(featName, true, featureId);
344
345    if (!canSetFeature(featureId, state))
346        throw DOMException(DOMException::NOT_SUPPORTED_ERR, 0, fMemoryManager);
347
348    setFeature(featureId, state);
349
350    //
351    // setting "canonical-form" to true will set the parameters "format-pretty-print",
352    // "discard-default-content", and "xml-declaration", to false
353    //
354    if ((featureId == CANONICAL_FORM_ID) && state)
355    {
356        setFeature(FORMAT_PRETTY_PRINT_ID, false);
357        setFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID, false);
358        setFeature(DISCARD_DEFAULT_CONTENT_ID, false);
359        setFeature(XML_DECLARATION, false);
360    }
361    // Setting one of those parameters to true will set "canonical-form" to false.
362    if ((featureId == FORMAT_PRETTY_PRINT_ID || featureId == DISCARD_DEFAULT_CONTENT_ID || featureId == XML_DECLARATION) && state)
363        setFeature(CANONICAL_FORM_ID, false);
364}
365
366const void* DOMLSSerializerImpl::getParameter(const XMLCh* featName) const
367{
368    if(XMLString::compareIStringASCII(featName, XMLUni::fgDOMErrorHandler)==0)
369    {
370        return (void*)fErrorHandler;
371    }
372    else
373    {
374        int featureId = INVALID_FEATURE_ID;
375        checkFeature(featName, true, featureId);
376        return (void*)getFeature(featureId);
377    }
378}
379
380const DOMStringList* DOMLSSerializerImpl::getParameterNames() const
381{
382    return fSupportedParameters;
383}
384
385void DOMLSSerializerImpl::setNewLine(const XMLCh* const newLine)
386{
387    fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
388    fNewLine = XMLString::replicate(newLine, fMemoryManager);
389}
390
391const XMLCh* DOMLSSerializerImpl::getNewLine() const
392{
393    return fNewLine;
394}
395
396void DOMLSSerializerImpl::setFilter(DOMLSSerializerFilter *filter)
397{
398    fFilter = filter;
399}
400
401DOMLSSerializerFilter* DOMLSSerializerImpl::getFilter() const
402{
403    return fFilter;
404}
405
406//
407//
408//
409bool DOMLSSerializerImpl::write(const DOMNode* nodeToWrite,
410                                DOMLSOutput* const destination)
411{
412    XMLFormatTarget* pTarget=destination->getByteStream();
413    Janitor<XMLFormatTarget> janTarget(0);
414    if(!pTarget)
415    {
416        const XMLCh* szSystemId=destination->getSystemId();
417        if(!szSystemId)
418        {
419            //TODO: report error "missing target"
420            return false;
421        }
422        pTarget=new LocalFileFormatTarget(szSystemId, fMemoryManager);
423        janTarget.reset(pTarget);
424    }
425    /**
426     * When writing to a LSOutput, the encoding is found by looking at the encoding information
427     * that is reachable through the LSOutput and the item to be written (or its owner document) in this order:
428     *
429     *  1. LSOutput.encoding,
430     *  2. Document.inputEncoding,
431     *  3. Document.xmlEncoding.
432     *
433     * If no encoding is reachable through the above properties, a default encoding of "UTF-8" will be used.
434     * If the specified encoding is not supported an "unsupported-encoding" fatal error is raised.
435     */
436    fEncodingUsed = gUTF8;
437
438    const DOMDocument *docu = (nodeToWrite->getNodeType() == DOMNode::DOCUMENT_NODE)?
439                              (const DOMDocument*)nodeToWrite : nodeToWrite->getOwnerDocument();
440
441    const XMLCh* lsEncoding=destination->getEncoding();
442    if (lsEncoding && *lsEncoding)
443    {
444        fEncodingUsed = lsEncoding;
445    }
446    else if (docu)
447    {
448        const XMLCh* tmpEncoding = docu->getInputEncoding();
449
450        if ( tmpEncoding && *tmpEncoding)
451        {
452            fEncodingUsed = tmpEncoding;
453        }
454        else
455        {
456            tmpEncoding = docu->getXmlEncoding();
457
458            if ( tmpEncoding && *tmpEncoding)
459            {
460                fEncodingUsed = tmpEncoding;
461            }
462        }
463    }
464
465
466    /**
467     *  The end-of-line sequence of characters to be used in the XML being
468     *  written out. The only permitted values are these:
469     *     . null
470     *
471     *  Use a default end-of-line sequence. DOM implementations should choose
472     * the default to match the usual convention for text files in the
473     * environment being used. Implementations must choose a default
474     * sequence that matches one of those allowed by  2.11 "End-of-Line
475     * Handling".
476     *
477     *    CR    The carriage-return character (#xD)
478     *    CR-LF The carriage-return and line-feed characters (#xD #xA)
479     *    LF    The line-feed character (#xA)
480     *
481     *  The default value for this attribute is null
482     */
483    fNewLineUsed = (fNewLine && *fNewLine)? fNewLine : gEOLSeq;
484
485    /**
486     *  get Document Version
487     */
488    fDocumentVersion = (docu && docu->getXmlVersion() && *(docu->getXmlVersion()))?docu->getXmlVersion():XMLUni::fgVersion1_0;
489
490    fErrorCount = 0;
491
492    fLineFeedInTextNodePrinted = false;
493    fLastWhiteSpaceInTextNode = 0;
494
495    try
496    {
497        fFormatter = new (fMemoryManager) XMLFormatter( fEncodingUsed
498                                                       ,fDocumentVersion
499                                                       ,pTarget
500                                                       ,XMLFormatter::NoEscapes
501                                                       ,XMLFormatter::UnRep_CharRef
502                                                       ,fMemoryManager);
503    }
504    catch (const TranscodingException& e)
505    {
506        reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, e.getMessage());
507        return false;
508    }
509
510    try
511    {
512        Janitor<XMLFormatter> janName(fFormatter);
513        processNode(nodeToWrite);
514        pTarget->flush();
515    }
516
517    //
518    // The serialize engine (processNode) throws an exception to abort
519    // serialization if
520    //
521    //   . A fatal error occurs which renders the output ill-formed, or
522    //   . Instructed by the application's error handler
523    //
524    catch (const TranscodingException&)
525    {
526        pTarget->flush();
527        return false;
528    }
529
530    catch (const XMLDOMMsg::Codes)
531    {
532        pTarget->flush();
533        return false;
534    }
535    catch(const OutOfMemoryException&)
536    {
537        throw;
538    }
539    catch (...)
540    {
541        pTarget->flush();
542        throw;
543    }
544
545    //
546    // true if node was successfully serialized and
547    // false in case a failure occured and the
548    // failure wasn't canceled by the error handler.
549    //
550    return ((fErrorCount == 0)? true : false);
551}
552
553bool DOMLSSerializerImpl::writeToURI(const DOMNode* nodeToWrite, const XMLCh* uri)
554{
555    DOMLSOutputImpl output(fMemoryManager);
556    output.setSystemId(uri);
557    return write(nodeToWrite, &output);
558}
559
560//
561// We don't throw DOMSTRING_SIZE_ERR since we are no longer
562// using DOMString.
563//
564XMLCh* DOMLSSerializerImpl::writeToString(const DOMNode* nodeToWrite, MemoryManager* manager /*= NULL*/)
565{
566    if(manager==NULL)
567        manager = fMemoryManager;
568    MemBufFormatTarget  destination(1023, manager);
569    bool retVal;
570
571    bool bBOMFlag=getFeature(BYTE_ORDER_MARK_ID);
572    setFeature(BYTE_ORDER_MARK_ID, false);
573    try
574    {
575        DOMLSOutputImpl output(manager);
576        output.setByteStream(&destination);
577        output.setEncoding(XMLUni::fgUTF16EncodingString);
578        retVal = write(nodeToWrite, &output);
579    }
580    catch(const OutOfMemoryException&)
581    {
582        throw;
583    }
584    catch (...)
585    {
586        //
587        // there is a possibility that memory allocation
588        // exception thrown in XMLBuffer class
589        //
590        setFeature(BYTE_ORDER_MARK_ID, bBOMFlag);
591        return 0;
592    }
593
594    setFeature(BYTE_ORDER_MARK_ID, bBOMFlag);
595    return (retVal ? XMLString::replicate((XMLCh*) destination.getRawBuffer(), manager) : 0);
596}
597
598//
599// Characters not representable in output encoding,
600//
601// 1. CHARACTER DATA (outside of markup)                --- no error
602//    ordinary character  -> numeric character reference
603//    '<' and '&'         -> &lt; and &amp;
604//
605// 2. Within MARKUP, but outside of attributes
606//    reported as an error                                 --- ERROR
607//    markup:
608//           start tag                                  done
609//           end tag                                    done
610//           empty element tag                          done
611//           entity references                          done
612//           character references    // REVISIT
613//           comments                                   done
614//           CDATA section delimiters                   done, done
615//           document type declarartions                done
616//           processing instructions (PI)               done
617//
618// 3. With in ATTRIBUTE
619//    -> numeric character reference
620//    no quotes                        -> in quotes
621//    with quotes, no apostrophe       -> in apostrophe
622//    with quotes and apostrophe       -> in quotes and &quot;
623//
624// 4. CDATA sections
625//    "split_cdata_section"  true                      --- char ref
626//                           false                     ---      ERROR
627//
628// ---------------------------------------------------------------------------
629//  Stream out a DOM node, and, recursively, all of its children. This
630//  function is the heart of writing a DOM tree out as XML source. Give it
631//  a document node and it will do the whole thing.
632// ---------------------------------------------------------------------------
633
634void DOMLSSerializerImpl::processNode(const DOMNode* const nodeToWrite, int level)
635{
636
637    // Get the name and value out for convenience
638    const XMLCh*    nodeName = nodeToWrite->getNodeName();
639    const XMLCh*    nodeValue = nodeToWrite->getNodeValue();
640    XMLSize_t       lent = XMLString::stringLen(nodeValue);
641
642    switch (nodeToWrite->getNodeType())
643    {
644    case DOMNode::TEXT_NODE:
645        {
646            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
647                break;
648
649            if (getFeature(FORMAT_PRETTY_PRINT_ID))
650            {
651                fLineFeedInTextNodePrinted = false;
652                fLastWhiteSpaceInTextNode = 0;
653
654                if(XMLChar1_0::isAllSpaces(nodeValue, XMLString::stringLen(nodeValue)))
655                {
656                    // skips whitespace-only text nodes unless whitespace-in-element is set.
657                    if (!getFeature(WHITESPACE_IN_ELEMENT_CONTENT_ID))
658                    {
659                        break;
660                    }
661                    else
662                    {
663                        //
664                        // we need to trace if newline(s) have been printed out
665                        // to avoid generate extra newline for pretty printing,
666                        // as well as the number of whitespaces after the last
667                        // newline character to do indentation properly.
668                        //
669                        int pos = XMLString::lastIndexOf(nodeValue, chLF);
670                        if (-1 != pos)
671                        {
672                            fLineFeedInTextNodePrinted = true;
673                            fLastWhiteSpaceInTextNode = (unsigned int)(lent - pos);
674                        }
675                        else
676                        {
677                            // for those platforms using chCR alone as
678                            // a newline character
679                            pos = XMLString::lastIndexOf(nodeValue, chCR);
680                            if (-1 != pos)
681                            {
682                                fLineFeedInTextNodePrinted = true;
683                                fLastWhiteSpaceInTextNode = (unsigned int)(lent - pos);
684                            }
685                        }
686                    }
687                }
688            }
689
690            setURCharRef();      // character data
691            fFormatter->formatBuf(nodeValue, lent, XMLFormatter::CharEscapes);
692            break;
693        }
694
695    case DOMNode::PROCESSING_INSTRUCTION_NODE:
696        {
697            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
698                break;
699
700            if(level == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
701                printNewLine();
702
703            printNewLine();
704            printIndent(level);
705
706            TRY_CATCH_THROW
707            (
708                *fFormatter << XMLFormatter::NoEscapes << gStartPI << nodeName;
709                if (lent > 0)
710                {
711                    *fFormatter << chSpace << nodeValue;
712                }
713                *fFormatter << gEndPI;
714            )
715            break;
716        }
717
718    case DOMNode::DOCUMENT_NODE: // Not to be shown to Filter
719        {
720
721            // output BOM if needed
722            processBOM();
723
724            setURCharRef();
725            const DOMDocument *docu = (const DOMDocument*)nodeToWrite;
726
727            //[23] XMLDecl      ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
728            //[24] VersionInfo  ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
729            //[80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName
730            //[32] SDDecl       ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
731            //
732
733            if (getFeature(XML_DECLARATION)) {
734                // use the version and encoding resolved
735                *fFormatter << gXMLDecl_VersionInfo << fDocumentVersion << gXMLDecl_separator;
736                *fFormatter << gXMLDecl_EncodingDecl << fEncodingUsed << gXMLDecl_separator;
737
738                const XMLCh* st = (docu->getXmlStandalone())? XMLUni::fgYesString : XMLUni::fgNoString;
739                *fFormatter << gXMLDecl_SDDecl << st << gXMLDecl_separator;
740
741                *fFormatter << gXMLDecl_endtag;
742            }
743
744            DOMNodeSPtr child = nodeToWrite->getFirstChild();
745            while( child != 0)
746            {
747                processNode(child, level);
748                child = child->getNextSibling();
749            }
750            printNewLine();
751            break;
752        }
753
754    case DOMNode::DOCUMENT_FRAGMENT_NODE:
755        {
756
757            setURCharRef();
758
759            DOMNode *child = nodeToWrite->getFirstChild();
760            while( child != 0)
761            {
762                processNode(child, level);
763                child = child->getNextSibling();
764            }
765            printNewLine();
766            break;
767        }
768
769    case DOMNode::ELEMENT_NODE:
770        {
771            DOMNodeFilter::FilterAction filterAction = checkFilter(nodeToWrite);
772
773            if ( filterAction == DOMNodeFilter::FILTER_REJECT)
774                break;
775
776            if (!fLineFeedInTextNodePrinted)
777            {
778                if(level == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
779                    printNewLine();
780
781                printNewLine();
782            }
783            else
784            {
785                fLineFeedInTextNodePrinted = false;
786            }
787
788            printIndent(level);
789
790            //track the line number the current node begins on
791            int nodeLine = fCurrentLine;
792
793            // add an entry in the namespace stack
794            RefHashTableOf<XMLCh>* namespaceMap=NULL;
795
796            if ( filterAction == DOMNodeFilter::FILTER_ACCEPT)
797            {
798                //           this element    attributes   child elements
799                // accept        yes             yes           yes
800                // skip          no              no            yes
801                //
802                TRY_CATCH_THROW
803                (
804                // The name has to be representable without any escapes
805                    *fFormatter  << XMLFormatter::NoEscapes
806                                 << chOpenAngle << nodeName;
807                )
808
809                // Output any attributes on this element
810                setURCharRef();
811                DOMNamedNodeMap *attributes = nodeToWrite->getAttributes();
812                XMLSize_t attrCount = attributes->getLength();
813
814                // check if the namespace for the current node is already defined
815                const XMLCh* prefix = nodeToWrite->getPrefix();
816                const XMLCh* uri = nodeToWrite->getNamespaceURI();
817                if((uri && uri[0]) || ((prefix==0 || prefix[0]==0) && isDefaultNamespacePrefixDeclared()))
818                {
819                    if(prefix==0 || prefix[0]==0)
820                        prefix=XMLUni::fgZeroLenString;
821                    if(!isNamespaceBindingActive(prefix, uri))
822                    {
823                        if(namespaceMap==NULL)
824                        {
825                            namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
826                            fNamespaceStack->addElement(namespaceMap);
827                        }
828                        namespaceMap->put((void*)prefix,(XMLCh*)uri);
829                        *fFormatter  << XMLFormatter::NoEscapes
830                                     << chSpace << XMLUni::fgXMLNSString;
831                        if(!XMLString::equals(prefix,XMLUni::fgZeroLenString))
832                            *fFormatter  << chColon << prefix;
833                        *fFormatter  << chEqual << chDoubleQuote
834                                     << XMLFormatter::AttrEscapes
835                                     << uri
836                                     << XMLFormatter::NoEscapes
837                                     << chDoubleQuote;
838                    }
839                }
840
841                bool discard = getFeature(DISCARD_DEFAULT_CONTENT_ID);
842                for (XMLSize_t i = 0; i < attrCount; i++)
843                {
844                    DOMAttrSPtr  attribute = (DOMAttr*)attributes->item(i);
845
846                    // Not to be shown to Filter
847
848                    //
849                    //"discard-default-content"
850                    //    true
851                    //    [required] (default)
852                    //    Use whatever information available to the implementation
853                    //  (i.e. XML schema, DTD, the specified flag on Attr nodes,
854                    //  and so on) to decide what attributes and content should be
855                    //  discarded or not.
856                    //  Note that the specified flag on Attr nodes in itself is
857                    //  not always reliable, it is only reliable when it is set
858                    //  to false since the only case where it can be set to false
859                    //  is if the attribute was created by the implementation.
860                    //  The default content won't be removed if an implementation
861                    //  does not have any information available.
862                    //    false
863                    //    [required]
864                    //    Keep all attributes and all content.
865                    //
866                    if (discard && !((DOMAttr*)attribute )->getSpecified())
867                        continue;
868                    //
869                    //  Again the name has to be completely representable. But the
870                    //  attribute can have refs and requires the attribute style
871                    //  escaping.
872                    //
873
874                    // if this attribute is a namespace declaration, add it to the namespace map for the current level
875                    const XMLCh* ns = attribute->getNamespaceURI();
876                    if (ns != 0 )
877                    {
878                        if(XMLString::equals(ns, XMLUni::fgXMLNSURIName))
879                        {
880                            if(namespaceMap==NULL)
881                            {
882                                namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
883                                fNamespaceStack->addElement(namespaceMap);
884                            }
885                                        const XMLCh* nsPrefix = attribute->getLocalName();
886                            if(XMLString::equals(attribute->getNodeName(),XMLUni::fgXMLNSString))
887                                                                nsPrefix = XMLUni::fgZeroLenString;
888                                                        if(namespaceMap->containsKey((void*)nsPrefix))
889                                                                continue;
890                            namespaceMap->put((void*)attribute->getLocalName(),(XMLCh*)attribute->getNodeValue());
891                        }
892                        else if(!XMLString::equals(ns, XMLUni::fgXMLURIName))
893                        {
894                            // check if the namespace for the current node is already defined
895                            const XMLCh* prefix = attribute->getPrefix();
896                            if(prefix && prefix[0])
897                            {
898                                const XMLCh* uri = attribute->getNamespaceURI();
899                                if(!isNamespaceBindingActive(prefix, uri))
900                                {
901                                    if(namespaceMap==NULL)
902                                    {
903                                        namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
904                                        fNamespaceStack->addElement(namespaceMap);
905                                    }
906                                    namespaceMap->put((void*)prefix,(XMLCh*)uri);
907                                    *fFormatter  << XMLFormatter::NoEscapes
908                                                 << chSpace << XMLUni::fgXMLNSString << chColon << prefix
909                                                 << chEqual << chDoubleQuote
910                                                 << XMLFormatter::AttrEscapes
911                                                 << uri
912                                                 << XMLFormatter::NoEscapes
913                                                 << chDoubleQuote;
914                                }
915                            }
916                        }
917                    }
918                    if (XMLString::equals(ns, XMLUni::fgXMLNSURIName) || checkFilter(attribute) == DOMNodeFilter::FILTER_ACCEPT)
919                    {
920                        *fFormatter  << XMLFormatter::NoEscapes
921                                     << chSpace << attribute->getNodeName()
922                                     << chEqual << chDoubleQuote
923                                     << XMLFormatter::AttrEscapes;
924                        if (getFeature(ENTITIES_ID))
925                        {
926                            DOMNodeSPtr child = attribute->getFirstChild();
927                            while( child != 0)
928                            {
929                                if(child->getNodeType()==DOMNode::TEXT_NODE)
930                                    *fFormatter  << child->getNodeValue();
931                                else if(child->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE)
932                                    *fFormatter << XMLFormatter::NoEscapes
933                                                << chAmpersand << child->getNodeName() << chSemiColon
934                                                << XMLFormatter::AttrEscapes;
935                                child = child->getNextSibling();
936                            }
937                        }
938                        else
939                            *fFormatter  << attribute->getNodeValue();
940                        *fFormatter  << XMLFormatter::NoEscapes
941                                     << chDoubleQuote;
942                    }
943                } // end of for
944            } // end of FILTER_ACCEPT
945
946            level++;
947
948            // FILTER_SKIP may start from here
949
950            //
951            //  Test for the presence of children, which includes both
952            //  text content and nested elements.
953            //
954            DOMNodeSPtr child = nodeToWrite->getFirstChild();
955            if (child != 0)
956            {
957                // There are children. Close start-tag, and output children.
958                // No escapes are legal here
959                if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
960                    *fFormatter << XMLFormatter::NoEscapes << chCloseAngle;
961
962                while( child != 0)
963                {
964                    processNode(child, level);
965                    child = child->getNextSibling();
966                }
967
968                level--;
969
970                if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
971                {
972                    //if we are not on the same line as when we started
973                    //this node then print a new line and indent
974                    if(nodeLine != fCurrentLine)
975                    {
976                        if (!fLineFeedInTextNodePrinted)
977                        {
978                            printNewLine();
979                        }
980                        else
981                        {
982                            fLineFeedInTextNodePrinted = false;
983                        }
984
985                        if(nodeLine != fCurrentLine && level == 0 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
986                            printNewLine();
987
988                        printIndent(level);
989                    }
990                    TRY_CATCH_THROW
991                    (
992                         *fFormatter << XMLFormatter::NoEscapes << gEndElement
993                                     << nodeName << chCloseAngle;
994                    )
995
996                }
997            }
998            else
999            {
1000                level--;
1001
1002                //
1003                //  There were no children. Output the short form close of
1004                //  the element start tag, making it an empty-element tag.
1005                //
1006                if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
1007                {
1008                    TRY_CATCH_THROW
1009                    (
1010                        *fFormatter << XMLFormatter::NoEscapes << chForwardSlash << chCloseAngle;
1011                    )
1012                }
1013            }
1014
1015            // remove the namespace map at this level
1016            if(namespaceMap!=NULL)
1017                fNamespaceStack->removeLastElement();
1018
1019            break;
1020        }
1021    case DOMNode::ATTRIBUTE_NODE:
1022        {
1023            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
1024                break;
1025
1026            const XMLCh* localName = nodeToWrite->getLocalName();
1027
1028            // check if this is a DOM Level 1 Node
1029            if(localName == 0)
1030                *fFormatter  << XMLFormatter::NoEscapes
1031                             << nodeToWrite->getNodeName();
1032            else
1033                *fFormatter  << XMLFormatter::NoEscapes
1034                             << chOpenCurly << nodeToWrite->getNamespaceURI()
1035                             << chCloseCurly << localName;
1036            *fFormatter  << chEqual << chDoubleQuote
1037                         << XMLFormatter::AttrEscapes;
1038            if (getFeature(ENTITIES_ID))
1039            {
1040                DOMNodeSPtr child = nodeToWrite->getFirstChild();
1041                while( child != 0)
1042                {
1043                    if(child->getNodeType()==DOMNode::TEXT_NODE)
1044                        *fFormatter  << child->getNodeValue();
1045                    else if(child->getNodeType()==DOMNode::ENTITY_REFERENCE_NODE)
1046                        *fFormatter << XMLFormatter::NoEscapes
1047                                    << chAmpersand << child->getNodeName() << chSemiColon
1048                                    << XMLFormatter::AttrEscapes;
1049                    child = child->getNextSibling();
1050                }
1051            }
1052            else
1053                *fFormatter  << nodeValue;
1054            *fFormatter  << XMLFormatter::NoEscapes
1055                         << chDoubleQuote;
1056
1057            break;
1058        }
1059    case DOMNode::ENTITY_REFERENCE_NODE:
1060        {
1061            //"entities"
1062            //true
1063            //[required] (default)
1064            //Keep EntityReference and Entity nodes in the document.
1065
1066            //false
1067            //[optional]
1068            //Remove all EntityReference and Entity nodes from the document,
1069            //       putting the entity expansions directly in their place.
1070            //       Text nodes are into "normal" form.
1071            //Only EntityReference nodes to non-defined entities are kept in the document.
1072
1073            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
1074                break;
1075
1076            if (getFeature(ENTITIES_ID))
1077            {
1078                TRY_CATCH_THROW
1079                (
1080                    *fFormatter << XMLFormatter::NoEscapes << chAmpersand
1081                                << nodeName << chSemiColon;
1082                )
1083            }
1084            else
1085            {
1086                // check if the referenced entity is defined or not
1087                if (nodeToWrite->getOwnerDocument()->getDoctype()->getEntities()->getNamedItem(nodeName))
1088                {
1089                    DOMNodeSPtr child;
1090                    for (child = nodeToWrite->getFirstChild();
1091                    child != 0;
1092                    child = child->getNextSibling())
1093                    {
1094                        processNode(child, level);
1095                    }
1096                }
1097                else
1098                {
1099                    TRY_CATCH_THROW
1100                   (
1101                        *fFormatter<<XMLFormatter::NoEscapes<<chAmpersand<<nodeName<<chSemiColon;
1102                    )
1103                }
1104            }
1105            break;
1106        }
1107
1108        //
1109        //  feature:split_cdata_sections     occurence of ]]>   unrep-char
1110        //  ===============================================================
1111        //          true                        split            split
1112        //          false                       fails            fails
1113        //
1114    case DOMNode::CDATA_SECTION_NODE:
1115        {
1116            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
1117                break;
1118
1119            if (getFeature(SPLIT_CDATA_SECTIONS_ID))
1120            {
1121                // it is fairly complicated and we process this
1122                // in a separate function.
1123                procCdataSection(nodeValue, nodeToWrite);
1124            }
1125            else
1126            {
1127                // search for "]]>", the node value is not supposed to have this
1128                if (XMLString::patternMatch((XMLCh*) nodeValue, gEndCDATA) != -1)
1129                {
1130                    reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NestedCDATA);
1131                }
1132
1133                TRY_CATCH_THROW
1134                (
1135                    // transcoder throws exception for unrep chars
1136                    *fFormatter << XMLFormatter::NoEscapes << gStartCDATA << nodeValue << gEndCDATA;
1137                )
1138            }
1139
1140            break;
1141        }
1142
1143    case DOMNode::COMMENT_NODE:
1144        {
1145            if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
1146                break;
1147
1148            // Figure out if we want pretty-printing for this comment.
1149            // If this comment node does not have any element siblings
1150            // (i.e., it is a text node) then we don't want to add any
1151            // whitespaces since that might be significant to the
1152            // application. Otherwise we want pretty-printing.
1153            //
1154
1155            bool pretty = (level == 0); // Document-level comments.
1156
1157            if (!pretty)
1158            {
1159              // See if we have any element siblings.
1160              //
1161              const DOMNode* s = nodeToWrite->getNextSibling ();
1162
1163              while (s != 0 && s->getNodeType () != DOMNode::ELEMENT_NODE)
1164                s = s->getNextSibling ();
1165
1166              if (s != 0)
1167                pretty = true;
1168              else
1169              {
1170                s = nodeToWrite->getPreviousSibling ();
1171
1172                while (s != 0 && s->getNodeType () != DOMNode::ELEMENT_NODE)
1173                  s = s->getPreviousSibling ();
1174
1175                if (s != 0)
1176                  pretty = true;
1177              }
1178            }
1179
1180            if (pretty)
1181            {
1182              if(level == 1 && getFeature(FORMAT_PRETTY_PRINT_1ST_LEVEL_ID))
1183                printNewLine();
1184
1185              printNewLine();
1186              printIndent(level);
1187            }
1188
1189            TRY_CATCH_THROW
1190            (
1191                *fFormatter << XMLFormatter::NoEscapes << gStartComment
1192                << nodeValue << gEndComment;
1193            )
1194            break;
1195        }
1196
1197    case DOMNode::DOCUMENT_TYPE_NODE:  // Not to be shown to Filter
1198        {
1199            const DOMDocumentType *doctype = (const DOMDocumentType *)nodeToWrite;
1200
1201            fFormatter->setEscapeFlags(XMLFormatter::NoEscapes);
1202
1203            printNewLine();
1204            printIndent(level);
1205
1206            TRY_CATCH_THROW
1207            (
1208                *fFormatter << gStartDoctype << nodeName;
1209
1210                const XMLCh  *id = doctype->getPublicId();
1211                if (id && *id)
1212                {
1213                    *fFormatter << chSpace << gPublic << id << chDoubleQuote;
1214
1215                    id = doctype->getSystemId();
1216                    if (id && *id)
1217                    {
1218                        *fFormatter << chSpace << chDoubleQuote << id << chDoubleQuote;
1219                    }
1220                    else
1221                    {
1222                        //
1223                        // 4.2.2 External Entities
1224                        // [Definition: If the entity is not internal,
1225                        //           it is an external entity, declared as follows:]
1226                        // External Entity Declaration
1227                        // [75] ExternalID ::= 'SYSTEM' S SystemLiteral
1228                        //                   | 'PUBLIC' S PubidLiteral S SystemLiteral
1229                        //
1230                        reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NotRecognizedType);
1231                        // systemLiteral not found
1232                    }
1233                }
1234                else
1235                {
1236                    id = doctype->getSystemId();
1237                    if (id && *id)
1238                    {
1239                        *fFormatter << chSpace << gSystem << id << chDoubleQuote;
1240                    }
1241                }
1242
1243                id = doctype->getInternalSubset();
1244                if (id && *id)
1245                {
1246                    *fFormatter << chSpace << chOpenSquare << id << chCloseSquare;
1247                }
1248
1249                *fFormatter << chCloseAngle;
1250            ) // end of TRY_CATCH_THROW
1251
1252            break;
1253        }
1254
1255    case DOMNode::ENTITY_NODE:  // Not to be shown to Filter
1256        {
1257            //
1258            // REVISIT: how does the feature "entities" impact
1259            // entity node?
1260            //
1261            printNewLine();
1262            printIndent(level);
1263
1264            fFormatter->setEscapeFlags(XMLFormatter::NoEscapes);
1265            *fFormatter << gStartEntity    << nodeName;
1266
1267            const XMLCh * id = ((const DOMEntity*)nodeToWrite)->getPublicId();
1268            if (id)
1269                *fFormatter << gPublic << id << chDoubleQuote;
1270
1271            id = ((const DOMEntity*)nodeToWrite)->getSystemId();
1272            if (id)
1273                *fFormatter << gSystem << id << chDoubleQuote;
1274
1275            id = ((const DOMEntity*)nodeToWrite)->getNotationName();
1276            if (id)
1277                *fFormatter << gNotation << id << chDoubleQuote;
1278
1279            *fFormatter << chCloseAngle;
1280
1281            break;
1282        }
1283
1284    default:
1285        /***
1286            This is an implementation specific behaviour, we abort if a user derived class has not dealt with
1287            this node type.
1288         ***/
1289        {
1290            if(!customNodeSerialize(nodeToWrite, level)) {
1291                reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NotRecognizedType);
1292                // UnreognizedNodeType;
1293            }
1294        }
1295
1296        break;
1297    }
1298
1299}
1300
1301bool DOMLSSerializerImpl::customNodeSerialize(const DOMNode* const, int) {
1302    return false;
1303}
1304
1305//
1306//
1307DOMNodeFilter::FilterAction DOMLSSerializerImpl::checkFilter(const DOMNode* const node) const
1308{
1309    if (!fFilter ||
1310        ((fFilter->getWhatToShow() & (1 << (node->getNodeType() - 1))) == 0))
1311        return DOMNodeFilter::FILTER_ACCEPT;
1312
1313    //
1314    // if and only if there is a filter, and it is interested
1315    // in the node type, then we pass the node to the filter
1316    // for examination
1317    //
1318    return (DOMNodeFilter::FilterAction) fFilter->acceptNode(node);
1319}
1320
1321
1322bool DOMLSSerializerImpl::checkFeature(const XMLCh* const featName
1323                               , bool               toThrow
1324                               , int&               featureId) const
1325{
1326    // check for null and/or empty feature name
1327    if (!featName || !*featName)
1328    {
1329        if (toThrow)
1330            throw DOMException(DOMException::NOT_FOUND_ERR, 0, fMemoryManager);
1331
1332        return false;
1333    }
1334
1335    featureId = INVALID_FEATURE_ID;
1336
1337    if (XMLString::equals(featName, XMLUni::fgDOMWRTCanonicalForm))
1338        featureId = CANONICAL_FORM_ID;
1339    else if (XMLString::equals(featName, XMLUni::fgDOMWRTDiscardDefaultContent))
1340        featureId = DISCARD_DEFAULT_CONTENT_ID;
1341    else if (XMLString::equals(featName, XMLUni::fgDOMWRTEntities))
1342        featureId = ENTITIES_ID;
1343    else if (XMLString::equals(featName, XMLUni::fgDOMWRTFormatPrettyPrint))
1344        featureId = FORMAT_PRETTY_PRINT_ID;
1345    else if (XMLString::equals(featName, XMLUni::fgDOMWRTNormalizeCharacters))
1346        featureId = NORMALIZE_CHARACTERS_ID;
1347    else if (XMLString::equals(featName, XMLUni::fgDOMWRTSplitCdataSections))
1348        featureId = SPLIT_CDATA_SECTIONS_ID;
1349    else if (XMLString::equals(featName, XMLUni::fgDOMWRTValidation))
1350        featureId = VALIDATION_ID;
1351    else if (XMLString::equals(featName, XMLUni::fgDOMWRTWhitespaceInElementContent))
1352        featureId = WHITESPACE_IN_ELEMENT_CONTENT_ID;
1353    else if (XMLString::equals(featName, XMLUni::fgDOMWRTBOM))
1354        featureId = BYTE_ORDER_MARK_ID;
1355    else if (XMLString::equals(featName, XMLUni::fgDOMXMLDeclaration))
1356        featureId = XML_DECLARATION;
1357    else if (XMLString::equals(featName, XMLUni::fgDOMWRTXercesPrettyPrint))
1358        featureId = FORMAT_PRETTY_PRINT_1ST_LEVEL_ID;
1359
1360
1361    //feature name not resolvable
1362    if (featureId == INVALID_FEATURE_ID)
1363    {
1364        if (toThrow)
1365            throw DOMException(DOMException::NOT_FOUND_ERR, 0, fMemoryManager);
1366
1367        return false;
1368    }
1369
1370    return true;
1371}
1372
1373bool DOMLSSerializerImpl::reportError(const DOMNode* const    errorNode
1374                              , DOMError::ErrorSeverity errorType
1375                              , const XMLCh*   const    errorMsg)
1376{
1377    bool toContinueProcess = true;   // default value for no error handler
1378
1379    if (fErrorHandler)
1380    {
1381        DOMLocatorImpl  locator(0, 0, (DOMNode*) errorNode, 0);
1382        DOMErrorImpl    domError(errorType , errorMsg, &locator);
1383        try
1384        {
1385            toContinueProcess = fErrorHandler->handleError(domError);
1386        }
1387        catch(...)
1388        {
1389        }
1390    }
1391
1392    if (errorType != DOMError::DOM_SEVERITY_WARNING)
1393        fErrorCount++;
1394
1395    return toContinueProcess;
1396}
1397
1398bool DOMLSSerializerImpl::reportError(const DOMNode* const    errorNode
1399                              , DOMError::ErrorSeverity errorType
1400                              , XMLDOMMsg::Codes        toEmit)
1401{
1402    const XMLSize_t msgSize = 1023;
1403    XMLCh errText[msgSize + 1];
1404
1405    DOMImplementationImpl::getMsgLoader4DOM()->loadMsg(toEmit, errText, msgSize);
1406
1407    bool toContinueProcess = true;   // default value for no error handler
1408
1409    if (fErrorHandler)
1410    {
1411        DOMLocatorImpl  locator(0, 0, (DOMNode*) errorNode, 0);
1412        DOMErrorImpl    domError(errorType , errText, &locator);
1413        try
1414        {
1415            toContinueProcess = fErrorHandler->handleError(domError);
1416        }
1417        catch(...)
1418        {
1419        }
1420    }
1421
1422    if (errorType != DOMError::DOM_SEVERITY_WARNING)
1423        fErrorCount++;
1424
1425    if (errorType == DOMError::DOM_SEVERITY_FATAL_ERROR || !toContinueProcess)
1426        throw toEmit;
1427
1428    return toContinueProcess;
1429}
1430
1431//
1432//
1433//
1434void DOMLSSerializerImpl::procCdataSection(const XMLCh*   const nodeValue
1435                                   , const DOMNode* const nodeToWrite)
1436{
1437    static const XMLSize_t offset = XMLString::stringLen(gEndCDATA);
1438
1439    /***
1440     * Append a ']]>' at the end
1441     */
1442    XMLSize_t len = XMLString::stringLen(nodeValue);
1443    XMLCh* repNodeValue = (XMLCh*) fMemoryManager->allocate
1444    (
1445        (len + offset + 1) * sizeof(XMLCh)
1446    );//new XMLCh [len + offset + 1];
1447    XMLString::copyString(repNodeValue, nodeValue);
1448    XMLString::catString(repNodeValue, gEndCDATA);
1449    ArrayJanitor<XMLCh>  jName(repNodeValue, fMemoryManager);
1450
1451    XMLCh* curPtr  = (XMLCh*) repNodeValue;
1452    XMLCh* nextPtr = 0;
1453    int    endTagPos = -1;
1454
1455    bool   endTagFound = true;
1456
1457    while (endTagFound)
1458    {
1459        endTagPos = XMLString::patternMatch(curPtr, gEndCDATA);
1460        if (endTagPos != -1)
1461        {
1462            nextPtr = curPtr + endTagPos + offset;  // skip the ']]>'
1463            *(curPtr + endTagPos) = chNull;         //nullify the first ']'
1464            if (XMLSize_t(endTagPos) != len)
1465                reportError(nodeToWrite, DOMError::DOM_SEVERITY_WARNING, XMLDOMMsg::Writer_NestedCDATA);
1466            len = len - endTagPos - offset;
1467        }
1468        else
1469        {
1470            endTagFound = false;
1471        }
1472
1473        /***
1474            to check ]]>]]>
1475        ***/
1476        if (endTagPos == 0)
1477        {
1478            TRY_CATCH_THROW
1479            (
1480                *fFormatter << XMLFormatter::NoEscapes << gStartCDATA << gEndCDATA;
1481            )
1482        }
1483        else
1484        {
1485            procUnrepCharInCdataSection(curPtr, nodeToWrite);
1486        }
1487
1488        if (endTagFound)
1489        {
1490            *(nextPtr - offset) = chCloseSquare;   //restore the first ']'
1491            curPtr = nextPtr;
1492        }
1493    }
1494}
1495
1496//
1497//
1498//
1499void DOMLSSerializerImpl::procUnrepCharInCdataSection(const XMLCh*   const nodeValue
1500                                              , const DOMNode* const nodeToWrite)
1501{
1502    //
1503    //  We have to check each character and see if it could be represented.
1504    //  As long as it can, we just keep up with where we started and how
1505    //  many chars we've checked. When we hit an unrepresentable one, we
1506    //  stop, transcode everything we've collected, then start handling
1507    //  the unrepresentables via char refs. We repeat this until we get all
1508    //  the chars done.
1509    //
1510    const XMLCh*    srcPtr = nodeValue;
1511    const XMLCh*    endPtr = nodeValue +  XMLString::stringLen(nodeValue);
1512
1513    // Set up the common part of the buffer that we build char refs into
1514    XMLCh tmpBuf[32];
1515    tmpBuf[0] = chAmpersand;
1516    tmpBuf[1] = chPound;
1517    tmpBuf[2] = chLatin_x;
1518
1519    while (srcPtr < endPtr)
1520    {
1521        const XMLCh* tmpPtr = srcPtr;
1522        while (tmpPtr < endPtr)
1523        {
1524            if (fFormatter->getTranscoder()->canTranscodeTo(*tmpPtr))
1525                tmpPtr++;
1526            else
1527                break;
1528        }
1529
1530        if (tmpPtr > srcPtr)
1531        {
1532            TRY_CATCH_THROW
1533            (
1534                *fFormatter << XMLFormatter::NoEscapes << gStartCDATA;
1535            )
1536
1537            // We got at least some chars that can be done normally
1538            fFormatter->formatBuf
1539            (
1540                srcPtr
1541                , tmpPtr - srcPtr
1542                , XMLFormatter::NoEscapes
1543                , XMLFormatter::UnRep_Fail
1544            );
1545
1546            TRY_CATCH_THROW
1547            (
1548                *fFormatter << XMLFormatter::NoEscapes << gEndCDATA;
1549            )
1550
1551            // Update the source pointer to our new spot
1552            srcPtr = tmpPtr;
1553        }
1554        else
1555        {
1556            //
1557            //  We hit something unrepresentable. So continue forward doing
1558            //  char refs until we hit something representable again or the
1559            //  end of input.
1560            //
1561
1562            // one warning for consective unrep chars
1563            reportError(nodeToWrite, DOMError::DOM_SEVERITY_WARNING, XMLDOMMsg::Writer_NotRepresentChar);
1564
1565            while (srcPtr < endPtr)
1566            {
1567                // Build a char ref for the current char
1568                XMLString::binToText(*srcPtr, &tmpBuf[3], 8, 16, fMemoryManager);
1569                const XMLSize_t bufLen = XMLString::stringLen(tmpBuf);
1570                tmpBuf[bufLen] = chSemiColon;
1571                tmpBuf[bufLen+1] = chNull;
1572
1573                // And now call recursively back to our caller to format this
1574                fFormatter->formatBuf
1575                (
1576                    tmpBuf
1577                    , bufLen + 1
1578                    , XMLFormatter::NoEscapes
1579                    , XMLFormatter::UnRep_Fail
1580                );
1581
1582                // Move up the source pointer and break out if needed
1583                srcPtr++;
1584                if (fFormatter->getTranscoder()->canTranscodeTo(*srcPtr))
1585                    break;
1586            }
1587        }
1588    }
1589}
1590
1591void DOMLSSerializerImpl::processNode(const DOMNode* const nodeToWrite)
1592{
1593    processNode(nodeToWrite, 0);
1594}
1595
1596bool DOMLSSerializerImpl::canSetFeature(const int featureId
1597                                       , bool      val) const
1598{
1599    return featuresSupported[2*featureId + (val? 0: 1)];
1600}
1601
1602void DOMLSSerializerImpl::printNewLine()
1603{
1604    if (getFeature(FORMAT_PRETTY_PRINT_ID))
1605    {
1606        fCurrentLine++;
1607        *fFormatter << fNewLineUsed;
1608    }
1609}
1610
1611void DOMLSSerializerImpl::printIndent(unsigned int level)
1612{
1613    if (getFeature(FORMAT_PRETTY_PRINT_ID))
1614    {
1615        if (fLastWhiteSpaceInTextNode)
1616        {
1617            unsigned int indentLevel = fLastWhiteSpaceInTextNode/2; // two chSpaces equals one indent level
1618            fLastWhiteSpaceInTextNode = 0;
1619            // if fLastWhiteSpaceInTextNode/2 is greater than level, then
1620            // it means too many spaces have been written to the
1621            // output stream and we can no longer indent properly
1622            if(indentLevel < level)
1623                level -= indentLevel;
1624            else
1625                level = 0;
1626        }
1627
1628        for(unsigned int i = 0; i < level; i++)
1629            *fFormatter << chSpace << chSpace;
1630    }
1631}
1632
1633void DOMLSSerializerImpl::release()
1634{
1635    DOMLSSerializerImpl* writer = (DOMLSSerializerImpl*) this;
1636    delete writer;
1637}
1638
1639void DOMLSSerializerImpl::processBOM()
1640{
1641    // if the feature is not set, don't output bom
1642    if (!getFeature(BYTE_ORDER_MARK_ID))
1643        return;
1644
1645    if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF8EncodingString)  == 0) ||
1646        (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF8EncodingString2) == 0)  )
1647    {
1648        fFormatter->writeBOM(BOM_utf8, 3);
1649    }
1650    else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16LEncodingString)  == 0) ||
1651        (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16LEncodingString2) == 0)  )
1652    {
1653        fFormatter->writeBOM(BOM_utf16le, 2);
1654    }
1655    else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16BEncodingString)  == 0) ||
1656             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16BEncodingString2) == 0)  )
1657    {
1658        fFormatter->writeBOM(BOM_utf16be, 2);
1659    }
1660    else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString)  == 0) ||
1661             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString2) == 0) ||
1662             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString3) == 0) ||
1663             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString4) == 0) ||
1664             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString5) == 0) ||
1665             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString6) == 0) ||
1666             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUTF16EncodingString7) == 0)  )
1667    {
1668        if (XMLPlatformUtils::fgXMLChBigEndian)
1669            fFormatter->writeBOM(BOM_utf16be, 2);
1670        else
1671            fFormatter->writeBOM(BOM_utf16le, 2);
1672    }
1673    else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4LEncodingString)  == 0) ||
1674             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4LEncodingString2) == 0)  )
1675    {
1676        fFormatter->writeBOM(BOM_ucs4le, 4);
1677    }
1678    else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4BEncodingString)  == 0) ||
1679             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4BEncodingString2) == 0)  )
1680    {
1681        fFormatter->writeBOM(BOM_ucs4be, 4);
1682    }
1683    else if ((XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4EncodingString)  == 0) ||
1684             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4EncodingString2) == 0) ||
1685             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4EncodingString3) == 0) ||
1686             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4EncodingString4) == 0) ||
1687             (XMLString::compareIStringASCII(fEncodingUsed, XMLUni::fgUCS4EncodingString5) == 0)  )
1688    {
1689                if (XMLPlatformUtils::fgXMLChBigEndian)
1690                fFormatter->writeBOM(BOM_ucs4be, 4);
1691            else
1692                        fFormatter->writeBOM(BOM_ucs4le, 4);
1693    }
1694}
1695
1696bool DOMLSSerializerImpl::isDefaultNamespacePrefixDeclared() const
1697{
1698    for(XMLSize_t i=fNamespaceStack->size();i>0;i--)
1699    {
1700        RefHashTableOf<XMLCh>* curNamespaceMap=fNamespaceStack->elementAt(i-1);
1701        const XMLCh* thisUri=curNamespaceMap->get((void*)XMLUni::fgZeroLenString);
1702        if(thisUri)
1703            return true;
1704    }
1705    return false;
1706}
1707
1708bool DOMLSSerializerImpl::isNamespaceBindingActive(const XMLCh* prefix, const XMLCh* uri) const
1709{
1710    for(XMLSize_t i=fNamespaceStack->size();i>0;i--)
1711    {
1712        RefHashTableOf<XMLCh>* curNamespaceMap=fNamespaceStack->elementAt(i-1);
1713        const XMLCh* thisUri=curNamespaceMap->get((void*)prefix);
1714        // if the prefix has been declared, check if it binds to the correct namespace, otherwise, reports it isn't bound
1715        if(thisUri)
1716            return XMLString::equals(thisUri,uri);
1717    }
1718    return false;
1719}
1720
1721XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.