DOMWriterImpl.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:60k
源码类别:

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 2002 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their featName, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: DOMWriterImpl.cpp,v 1.39 2003/05/18 14:02:03 knoaman Exp $
  58.  * $Log: DOMWriterImpl.cpp,v $
  59.  * Revision 1.39  2003/05/18 14:02:03  knoaman
  60.  * Memory manager implementation: pass per instance manager.
  61.  *
  62.  * Revision 1.38  2003/05/16 21:36:55  knoaman
  63.  * Memory manager implementation: Modify constructors to pass in the memory manager.
  64.  *
  65.  * Revision 1.37  2003/05/15 18:25:54  knoaman
  66.  * Partial implementation of the configurable memory manager.
  67.  *
  68.  * Revision 1.36  2003/05/14 16:20:13  gareth
  69.  * Fix to problem with multiple default namespace attributes being serialized. Patch by Alberto Massari.
  70.  *
  71.  * Revision 1.35  2003/05/12 16:08:11  gareth
  72.  * fix to #18832. Corrected serilization with regards to namespace nodes. Patch by Alby Massari.
  73.  *
  74.  * Revision 1.34  2003/05/06 13:48:35  neilg
  75.  * fix GCC compilation problem and incorrect #include
  76.  *
  77.  * Revision 1.33  2003/05/05 21:23:21  neilg
  78.  * use of the new DOMNodeSPtr typedef and its friends to enable reference counting in
  79.  * the DOMWriter implementation for applications that require it.
  80.  *
  81.  * Revision 1.32  2003/04/02 03:14:42  peiyongz
  82.  * Bug#18594: DOMWriter does not recognize Document Fragment
  83.  *
  84.  * Revision 1.31  2003/03/16 05:42:04  peiyongz
  85.  * Bug#17983 Formatter does not escape control characters
  86.  *
  87.  * Revision 1.30  2003/02/25 16:07:37  tng
  88.  * [Bug 13493] Use const on static data in DOMWriterImpl.cpp.
  89.  *
  90.  * Revision 1.29  2003/01/28 18:31:47  peiyongz
  91.  * Bug#13694: Allow Xerces to write the BOM to XML files
  92.  *
  93.  * Revision 1.28  2003/01/24 20:21:46  tng
  94.  * DOMWriter: Call XMLFormatTarget::flush when done.
  95.  *
  96.  * Revision 1.27  2003/01/20 16:50:13  tng
  97.  * DOMWriter fix:
  98.  * 1. wrong wrong nested cdata message
  99.  * 2. pretty format the cdata section
  100.  * 3. do not increment error count if warning was issued
  101.  *
  102.  * Revision 1.26  2003/01/09 19:53:45  tng
  103.  * [Bug 15372] DOMBuilder::parseFromURI ignores result of handleErrors.
  104.  *
  105.  * Revision 1.25  2002/12/10 21:01:32  tng
  106.  * NLS: DOMWriter should use message loader to load message instead of using hardcoded static stirng
  107.  *
  108.  * Revision 1.24  2002/12/10 18:59:14  tng
  109.  * pretty format print: consistent newline
  110.  *
  111.  * Revision 1.23  2002/12/10 13:34:07  tng
  112.  * Pretty-format print: also indent PI/comment that appear inside the root element.
  113.  *
  114.  * Revision 1.22  2002/12/09 11:46:08  gareth
  115.  * More pretty pretty print feature. Patch by Kevin King. Closes bug #13840.
  116.  *
  117.  * Revision 1.21  2002/12/02 23:08:09  peiyongz
  118.  * fix to bug#14528: output n+1 cdatasection
  119.  *
  120.  * Revision 1.20  2002/11/13 21:51:22  peiyongz
  121.  * fix to Bug#14528
  122.  *
  123.  * Revision 1.19  2002/11/04 15:07:35  tng
  124.  * C++ Namespace Support.
  125.  *
  126.  * Revision 1.18  2002/10/03 18:13:38  peiyongz
  127.  * Bug#12560 Use const in DOMWriter - patch from Duncan Stodart
  128.  *                                                              (Duncan_Stodart@insession.com )
  129.  *
  130.  * Revision 1.17  2002/09/24 20:19:14  tng
  131.  * Performance: use XMLString::equals instead of XMLString::compareString
  132.  * and check for null string directly isntead of calling XMLString::stringLen
  133.  *
  134.  * Revision 1.16  2002/09/09 15:42:14  peiyongz
  135.  * Patch to Bug#12369: invalid output from DOMWriter using MemBufFormatTarget
  136.  *
  137.  * Revision 1.15  2002/08/07 18:10:19  peiyongz
  138.  * Fix to Bug#11534: Wrong CDATA Terminator in DOMWriterImpl
  139.  *
  140.  * Revision 1.14  2002/07/22 23:24:01  tng
  141.  * DOM L3: writeToString should use the fFormatter to do the transcoding
  142.  *
  143.  * Revision 1.13  2002/07/16 15:19:42  peiyongz
  144.  * check lenght of getEncoding()/getActualEncoding()
  145.  *
  146.  * Revision 1.12  2002/06/25 16:17:16  tng
  147.  * DOM L3: add release()
  148.  *
  149.  * Revision 1.11  2002/06/21 19:33:12  peiyongz
  150.  * support for feature split_cdata_section and entities revised.
  151.  *
  152.  * Revision 1.10  2002/06/18 15:35:25  peiyongz
  153.  * Bug#9950: Compilation error on MSVC5, patch from PeterV@ti.com.od.ua (Peter A. Volchek)
  154.  *
  155.  * Revision 1.9  2002/06/17 19:45:58  peiyongz
  156.  * optimization on fFeatures and featureId introduced
  157.  *
  158.  * Revision 1.8  2002/06/11 19:45:45  peiyongz
  159.  * Notify application of the XMLFormatter creation failure
  160.  *
  161.  * Revision 1.7  2002/06/10 16:02:21  peiyongz
  162.  * format-pretty-print partially supported
  163.  * resolve encoding from DOMDocument Interface
  164.  *
  165.  * Revision 1.6  2002/06/06 20:58:37  tng
  166.  * [Bug 9639] enum_mem in DOMError clashes with constant.
  167.  *
  168.  * Revision 1.5  2002/06/05 16:03:03  peiyongz
  169.  * delete[] used.
  170.  *
  171.  * Revision 1.4  2002/06/03 22:35:54  peiyongz
  172.  * constants changed
  173.  *
  174.  * Revision 1.3  2002/05/31 21:01:06  peiyongz
  175.  * move printing of XMLDecl into the processNode().
  176.  *
  177.  * Revision 1.2  2002/05/29 21:31:50  knoaman
  178.  * DOM L3 LS: DOMInputSource, DOMEntityResolver, DOMImplementationLS and DOMBuilder
  179.  *
  180.  * Revision 1.1  2002/05/28 22:39:39  peiyongz
  181.  * DOM3 Save Interface: DOMWriter/DOMWriterFilter
  182.  *
  183.  */
  184. #include "DOMWriterImpl.hpp"
  185. #include "DOMErrorImpl.hpp"
  186. #include "DOMLocatorImpl.hpp"
  187. #include "DOMImplementationImpl.hpp"
  188. #include <xercesc/framework/MemBufFormatTarget.hpp>
  189. #include <xercesc/util/TransService.hpp>
  190. #include <xercesc/util/TranscodingException.hpp>
  191. #include <xercesc/util/Janitor.hpp>
  192. #include <xercesc/util/XMLString.hpp>
  193. #include <xercesc/util/XMLUniDefs.hpp>
  194. #include <xercesc/util/XMLMsgLoader.hpp>
  195. #include <xercesc/dom/StDOMNode.hpp>
  196. XERCES_CPP_NAMESPACE_BEGIN
  197. // ---------------------------------------------------------------------------
  198. //  Local const data
  199. //
  200. // ---------------------------------------------------------------------------
  201. static const int INVALID_FEATURE_ID               = -1;
  202. static const int CANONICAL_FORM_ID                = 0x0;
  203. static const int DISCARD_DEFAULT_CONTENT_ID       = 0x1;
  204. static const int ENTITIES_ID                      = 0x2;
  205. static const int FORMAT_PRETTY_PRINT_ID           = 0x3;
  206. static const int NORMALIZE_CHARACTERS_ID          = 0x4;
  207. static const int SPLIT_CDATA_SECTIONS_ID          = 0x5;
  208. static const int VALIDATION_ID                    = 0x6;
  209. static const int WHITESPACE_IN_ELEMENT_CONTENT_ID = 0x7;
  210. static const int BYTE_ORDER_MARK_ID               = 0x8;
  211. //    feature                      true                       false
  212. // ================================================================================
  213. //canonical-form                 [optional] Not Supported     [required] (default)
  214. //discard-default-content        [required] (default)         [required]
  215. //entity                         [required] (default)         [optional]
  216. //format-pretty-print            [optional] Partially Supported [required] (default)
  217. //normalize-characters           [optional] Not Supported     [required] (default)
  218. //split-cdata-sections           [required] (default)         [required]
  219. //validation                     [optional] Not Supported     [required] (default)
  220. //whitespace-in-element-content  [requierd] (default)         [optional] Not Supported
  221. //
  222. //
  223. // Each feature has 2 entries in this array,
  224. // the first for "true",
  225. // the second for "false".
  226. //
  227. static const bool  featuresSupported[] = {
  228.     false, true,  // canonical-form
  229.     true,  true,  // discard-default-content
  230.     true,  true,  // entity
  231.     true,  true,  // format-pretty-print
  232.     false, true,  // normalize-characters
  233.     true,  true,  // split-cdata-sections
  234.     false, true,  // validation
  235.     true,  false, // whitespace-in-element-content
  236.     true,  true   // byte-order-mark
  237. };
  238. // default end-of-line sequence
  239. static const XMLCh  gEOLSeq[] =
  240. {
  241.     chLF, chNull
  242. };
  243. //UTF-8
  244. static const XMLCh  gUTF8[] =
  245. {
  246.     chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull
  247. };
  248. //</
  249. static const XMLCh  gEndElement[] =
  250. {
  251.     chOpenAngle, chForwardSlash, chNull
  252. };
  253. //?>
  254. static const XMLCh  gEndPI[] =
  255. {
  256.     chQuestion, chCloseAngle, chNull
  257. };
  258. //<?
  259. static const XMLCh  gStartPI[] =
  260. {
  261.     chOpenAngle, chQuestion, chNull
  262. };
  263. //<?xml version="
  264. static const XMLCh  gXMLDecl_VersionInfo[] =
  265. {
  266.     chOpenAngle, chQuestion, chLatin_x,     chLatin_m,  chLatin_l,  chSpace,
  267.     chLatin_v,   chLatin_e,  chLatin_r,     chLatin_s,  chLatin_i,  chLatin_o,
  268.     chLatin_n,   chEqual,    chDoubleQuote, chNull
  269. };
  270. static const XMLCh gXMLDecl_ver10[] =
  271. {
  272.     chDigit_1, chPeriod, chDigit_0, chNull
  273. };
  274. //encoding="
  275. static const XMLCh  gXMLDecl_EncodingDecl[] =
  276. {
  277.     chLatin_e,  chLatin_n,  chLatin_c,  chLatin_o,      chLatin_d, chLatin_i,
  278.     chLatin_n,  chLatin_g,  chEqual,    chDoubleQuote,  chNull
  279. };
  280. //" standalone="
  281. static const XMLCh  gXMLDecl_SDDecl[] =
  282. {
  283.     chLatin_s, chLatin_t, chLatin_a,   chLatin_n,    chLatin_d,   chLatin_a,
  284.     chLatin_l, chLatin_o, chLatin_n,   chLatin_e,    chEqual,     chDoubleQuote,
  285.     chNull
  286. };
  287. //"
  288. static const XMLCh  gXMLDecl_separator[] =
  289. {
  290.     chDoubleQuote, chSpace, chNull
  291. };
  292. //?>
  293. static const XMLCh  gXMLDecl_endtag[] =
  294. {
  295.     chQuestion, chCloseAngle,  chNull
  296. };
  297. //<![CDATA[
  298. static const XMLCh  gStartCDATA[] =
  299. {
  300.     chOpenAngle, chBang,    chOpenSquare, chLatin_C, chLatin_D,
  301.     chLatin_A,   chLatin_T, chLatin_A,    chOpenSquare, chNull
  302. };
  303. //]]>
  304. static const XMLCh  gEndCDATA[] =
  305. {
  306. //    chCloseSquare, chCloseAngle, chCloseAngle, chNull  // test only: ]>>
  307.       chCloseSquare, chCloseSquare, chCloseAngle, chNull
  308. };
  309. static const int offset = XMLString::stringLen(gEndCDATA);
  310. //<!--
  311. static const XMLCh  gStartComment[] =
  312. {
  313.     chOpenAngle, chBang, chDash, chDash, chNull
  314. };
  315. //-->
  316. static const XMLCh  gEndComment[] =
  317. {
  318.     chDash, chDash, chCloseAngle, chNull
  319. };
  320. //<!DOCTYPE
  321. static const XMLCh  gStartDoctype[] =
  322. {
  323.     chOpenAngle, chBang,    chLatin_D, chLatin_O, chLatin_C, chLatin_T,
  324.     chLatin_Y,   chLatin_P, chLatin_E, chSpace,   chNull
  325. };
  326. //PUBLIC "
  327. static const XMLCh  gPublic[] =
  328. {
  329.     chLatin_P, chLatin_U, chLatin_B,     chLatin_L, chLatin_I,
  330.     chLatin_C, chSpace,   chDoubleQuote, chNull
  331. };
  332. //SYSTEM "
  333. static const XMLCh  gSystem[] =
  334. {
  335.     chLatin_S, chLatin_Y, chLatin_S,     chLatin_T, chLatin_E,
  336.     chLatin_M, chSpace,   chDoubleQuote, chNull
  337. };
  338. //<!ENTITY
  339. static const XMLCh  gStartEntity[] =
  340. {
  341.     chOpenAngle, chBang,    chLatin_E, chLatin_N, chLatin_T, chLatin_I,
  342.     chLatin_T,   chLatin_Y, chSpace,   chNull
  343. };
  344. //NDATA "
  345. static const XMLCh  gNotation[] =
  346. {
  347.     chLatin_N, chLatin_D,     chLatin_A, chLatin_T, chLatin_A,
  348.     chSpace,   chDoubleQuote, chNull
  349. };
  350. //Feature
  351. static const XMLCh  gFeature[] =
  352. {
  353.     chLatin_F, chLatin_e, chLatin_a, chLatin_t, chLatin_u, chLatin_r,
  354.     chLatin_e, chSpace,   chNull
  355. };
  356. // Can not be set to
  357. static const XMLCh  gCantSet[] =
  358. {
  359.     chSpace,   chLatin_C, chLatin_a, chLatin_n, chSpace, chLatin_n, chLatin_o,
  360.     chLatin_t, chSpace,   chLatin_b, chLatin_e, chSpace, chLatin_s,
  361.     chLatin_e, chLatin_t, chSpace,   chLatin_t, chLatin_o, chSpace, chNull
  362. };
  363. static const XMLCh  gTrue[] =
  364. {
  365.     chSingleQuote, chLatin_t, chLatin_r, chLatin_u, chLatin_e,
  366.     chSingleQuote, chLF,      chNull
  367. };
  368. static const XMLCh  gFalse[] =
  369. {
  370.     chSingleQuote, chLatin_f, chLatin_a, chLatin_l, chLatin_s,
  371.     chLatin_e,     chSingleQuote, chLF, chNull
  372. };
  373. static const XMLByte  BOM_utf16be[] = {(XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
  374. static const XMLByte  BOM_utf16le[] = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte) 0};
  375. static const XMLByte  BOM_ucs4be[]  = {(XMLByte)0x00, (XMLByte)0x00, (XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
  376. static const XMLByte  BOM_ucs4le[]  = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte)0x00, (XMLByte)0x00, (XMLByte) 0};
  377. static const XMLCh s_xmlnsURI[] = // "http://www.w3.org/2000/xmlns/"
  378.     {  chLatin_h, chLatin_t, chLatin_t, chLatin_p, chColon, chForwardSlash, chForwardSlash,
  379.        chLatin_w, chLatin_w, chLatin_w, chPeriod, chLatin_w, chDigit_3, chPeriod,
  380.        chLatin_o, chLatin_r, chLatin_g, chForwardSlash,
  381.        chDigit_2, chDigit_0, chDigit_0, chDigit_0, chForwardSlash,
  382.        chLatin_x, chLatin_m, chLatin_l, chLatin_n, chLatin_s, chForwardSlash, chNull};
  383. static const XMLCh s_xmlns[] = {chLatin_x, chLatin_m, chLatin_l, chLatin_n, chLatin_s, chNull};
  384. static const XMLCh s_xmlURI[] =    // "http://www.w3.org/XML/1998/namespace"
  385.     { chLatin_h, chLatin_t, chLatin_t, chLatin_p, chColon, chForwardSlash, chForwardSlash,
  386.       chLatin_w, chLatin_w, chLatin_w, chPeriod, chLatin_w, chDigit_3, chPeriod,
  387.       chLatin_o, chLatin_r, chLatin_g, chForwardSlash, chLatin_X, chLatin_M, chLatin_L, chForwardSlash,
  388.       chDigit_1, chDigit_9, chDigit_9, chDigit_8, chForwardSlash,
  389.       chLatin_n, chLatin_a, chLatin_m, chLatin_e, chLatin_s, chLatin_p, chLatin_a, chLatin_c, chLatin_e,
  390.       chNull};
  391. //
  392. // Notification of the error though error handler
  393. //
  394. // The application may instruct the engine to abort serialization
  395. // by returning "false".
  396. //
  397. // REVISIT: update the locator ctor once the line#, col#, uri and offset
  398. // are available from DOM3 core
  399. //
  400. // REVISIT: use throwing exception to abort serialization is an interesting
  401. // thing here, since the serializer is a recusive function, we
  402. // can't use return, obviously. However we may have multiple try/catch
  403. // along its way going back to writeNode(). So far we don't come up with a
  404. // "short-cut" to go "directly" back.
  405. //
  406. #define  TRY_CATCH_THROW(action, forceToRethrow)                     
  407. fFormatter->setUnRepFlags(XMLFormatter::UnRep_Fail);                 
  408. try                                                                  
  409. {                                                                    
  410.     action;                                                          
  411. }                                                                    
  412. catch(TranscodingException const &e)                                 
  413. {                                                                    
  414.     if ( !reportError(nodeToWrite                                    
  415.                     , DOMError::DOM_SEVERITY_FATAL_ERROR             
  416.                     , e.getMessage())                       ||       
  417.           forceToRethrow)                                            
  418.         throw e;                                                       
  419. }
  420. DOMWriterImpl::~DOMWriterImpl()
  421. {
  422.     fMemoryManager->deallocate(fEncoding);//delete [] fEncoding;
  423.     fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
  424.     delete fNamespaceStack;
  425.     // we don't own/adopt error handler and filter
  426. }
  427. DOMWriterImpl::DOMWriterImpl(MemoryManager* const manager)
  428. :fFeatures(0)
  429. ,fEncoding(0)
  430. ,fNewLine(0)
  431. ,fErrorHandler(0)
  432. ,fFilter(0)
  433. ,fDocumentVersion(XMLUni::fgVersion1_0)
  434. ,fEncodingUsed(0)
  435. ,fNewLineUsed(0)
  436. ,fFormatter(0)
  437. ,fErrorCount(0)
  438. ,fCurrentLine(0)
  439. ,fNamespaceStack(0)
  440. ,fMemoryManager(manager)
  441. {
  442.     fNamespaceStack=new (fMemoryManager) RefVectorOf< RefHashTableOf<XMLCh> >(0,true, fMemoryManager);
  443.     //
  444.     // set features to default setting
  445.     //
  446.     setFeature(CANONICAL_FORM_ID,                false);
  447.     setFeature(DISCARD_DEFAULT_CONTENT_ID,       true );
  448.     setFeature(ENTITIES_ID,                      true );
  449.     setFeature(FORMAT_PRETTY_PRINT_ID,           false);
  450.     setFeature(NORMALIZE_CHARACTERS_ID,          false);
  451.     setFeature(SPLIT_CDATA_SECTIONS_ID,          true );
  452.     setFeature(VALIDATION_ID,                    false);
  453.     setFeature(WHITESPACE_IN_ELEMENT_CONTENT_ID, true );
  454.     setFeature(BYTE_ORDER_MARK_ID,               false);
  455. }
  456. bool DOMWriterImpl::canSetFeature(const XMLCh* const featName
  457.                                   , bool               state) const
  458. {
  459.     int featureId = INVALID_FEATURE_ID;
  460.     return checkFeature(featName, false, featureId) ? canSetFeature(featureId, state) : false;
  461. }
  462. void DOMWriterImpl::setFeature(const XMLCh* const featName
  463.                              , bool               state)
  464. {
  465.     int featureId = INVALID_FEATURE_ID;
  466.     checkFeature(featName, true, featureId);
  467.     if (!canSetFeature(featureId, state))
  468.     {
  469.         XMLCh  tmpbuf[256];
  470.         XMLString::copyString(tmpbuf, gFeature);
  471.         XMLString::catString(tmpbuf, featName);
  472.         XMLString::catString(tmpbuf, gCantSet);
  473.         XMLString::catString(tmpbuf, state? gTrue : gFalse);
  474.         throw DOMException(DOMException::NOT_SUPPORTED_ERR, tmpbuf);
  475.     }
  476.     else
  477.         setFeature(featureId, state);
  478.     //
  479.     // canonical-form and format-pretty-print can not be both set to true
  480.     // meaning set canonical-form true will automatically set
  481.     // format-pretty-print to false and vise versa.
  482.     //
  483.     if ((featureId == CANONICAL_FORM_ID) && state)
  484.         setFeature(FORMAT_PRETTY_PRINT_ID, false);
  485.     if ((featureId == FORMAT_PRETTY_PRINT_ID) && state)
  486.         setFeature(CANONICAL_FORM_ID, false);
  487.     return;
  488. }
  489. bool DOMWriterImpl::getFeature(const XMLCh* const featName) const
  490. {
  491.     int featureId = INVALID_FEATURE_ID;
  492.     checkFeature(featName, true, featureId);
  493.     return getFeature(featureId);
  494. }
  495. // we don't check the validity of the encoding set
  496. void DOMWriterImpl::setEncoding(const XMLCh* const encoding)
  497. {
  498.     fMemoryManager->deallocate(fEncoding);//delete [] fEncoding;
  499.     fEncoding = XMLString::replicate(encoding, fMemoryManager);
  500. }
  501. const XMLCh* DOMWriterImpl::getEncoding() const
  502. {
  503.     return fEncoding;
  504. }
  505. void DOMWriterImpl::setNewLine(const XMLCh* const newLine)
  506. {
  507.     fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
  508.     fNewLine = XMLString::replicate(newLine, fMemoryManager);
  509. }
  510. const XMLCh* DOMWriterImpl::getNewLine() const
  511. {
  512.     return fNewLine;
  513. }
  514. void DOMWriterImpl::setErrorHandler(DOMErrorHandler *errorHandler)
  515. {
  516.     fErrorHandler = errorHandler;
  517. }
  518. DOMErrorHandler* DOMWriterImpl::getErrorHandler() const
  519. {
  520.     return fErrorHandler;
  521. }
  522. void DOMWriterImpl::setFilter(DOMWriterFilter *filter)
  523. {
  524.     fFilter = filter;
  525. }
  526. DOMWriterFilter* DOMWriterImpl::getFilter() const
  527. {
  528.     return fFilter;
  529. }
  530. //
  531. //
  532. //
  533. bool DOMWriterImpl::writeNode(XMLFormatTarget* const destination
  534.                             , const DOMNode         &nodeToWrite)
  535. {
  536.     //init session vars
  537.     initSession(&nodeToWrite);
  538.     try
  539.     {
  540.         fFormatter = new (fMemoryManager) XMLFormatter(fEncodingUsed
  541.                                      ,fDocumentVersion
  542.                                      ,destination
  543.                                      ,XMLFormatter::NoEscapes
  544.                                      ,XMLFormatter::UnRep_CharRef);
  545.     }
  546.     catch (const TranscodingException& e)
  547.     {
  548.         reportError(&nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, e.getMessage());
  549.         return false;
  550.     }
  551.     try
  552.     {
  553.         Janitor<XMLFormatter> janName(fFormatter);
  554.         processNode(&nodeToWrite);
  555.         destination->flush();
  556.     }
  557.     //
  558.     // The serialize engine (processNode) throws an exception to abort
  559.     // serialization if
  560.     //
  561.     //   . A fatal error occurs which renters the output ill-formed, or
  562.     //   . Instructed by the application's error handler
  563.     //
  564.     catch (const TranscodingException&)
  565.     {
  566.         destination->flush();
  567.         return false;
  568.     }
  569.     catch (const XMLDOMMsg::Codes)
  570.     {
  571.         destination->flush();
  572.         return false;
  573.     }
  574.     //
  575.     // DOMSystemException
  576.     // This exception will be raised in response to any sort of IO or system
  577.     // error that occurs while writing to the destination. It may wrap an
  578.     // underlying system exception.
  579.     //
  580.     //catch (RuntimeException const &)
  581.     catch (...)
  582.     {
  583.         // REVISIT generate a DOMSystemException wrapping the underlying
  584.         //         exception.
  585.         destination->flush();
  586.         throw;
  587.     }
  588.     //
  589.     // true if node was successfully serialized and
  590.     // false in case a failure occured and the
  591.     // failure wasn't canceled by the error handler.
  592.     //
  593.     return ((fErrorCount == 0)? true : false);
  594. }
  595. //
  596. // We don't throw DOMSTRING_SIZE_ERR since we are no longer
  597. // using DOMString.
  598. //
  599. XMLCh* DOMWriterImpl::writeToString(const DOMNode &nodeToWrite)
  600. {
  601.     MemBufFormatTarget  destination(1023, fMemoryManager);
  602.     bool retVal;
  603.     // XMLCh is unicode, assume fEncoding as UTF-16
  604.     XMLCh* tempEncoding = fEncoding;
  605.     fEncoding = (XMLCh*) XMLUni::fgUTF16EncodingString;
  606.     try
  607.     {
  608.         retVal = writeNode(&destination, nodeToWrite);
  609.     }
  610.     catch (...)
  611.     {
  612.         //
  613.         // there is a possibility that memeory allocation
  614.         // exception thrown in XMLBuffer class
  615.         //
  616.         fEncoding = tempEncoding;
  617.         return 0;
  618.     }
  619.     fEncoding = tempEncoding;
  620.     return (retVal ? XMLString::replicate((XMLCh*) destination.getRawBuffer()) : 0);
  621. }
  622. void DOMWriterImpl::initSession(const DOMNode* const nodeToWrite)
  623. {
  624. /**
  625.  * The encoding to use when writing is determined as follows:
  626.  *     If the encoding attribute has been set, that value will be used.
  627.  *     If the encoding attribute is null or empty,
  628.  *            but the item to be written, or
  629.  *            the owner document specified encoding (ie. the "actualEncoding"
  630.  *            from the document) that value will be used.
  631.  *     If neither of the above provides an encoding name, a default encoding of
  632.  *            "UTF-8" will be used.
  633.  */
  634.     fEncodingUsed = gUTF8;
  635.     if (fEncoding && *fEncoding)
  636.     {
  637.         fEncodingUsed = fEncoding;
  638.     }
  639.     else
  640.     {
  641.         const DOMDocument *docu = (nodeToWrite->getNodeType() == DOMNode::DOCUMENT_NODE)?
  642.                             (const DOMDocument*)nodeToWrite : nodeToWrite->getOwnerDocument();
  643.         if (docu)
  644.         {
  645.             const XMLCh* tmpEncoding = docu->getEncoding();
  646.             if ( tmpEncoding && *tmpEncoding)
  647.             {
  648.                 fEncodingUsed = tmpEncoding;
  649.             }
  650.             else
  651.             {
  652.                 tmpEncoding = docu->getActualEncoding();
  653.                 if ( tmpEncoding && *tmpEncoding)
  654.                 {
  655.                     fEncodingUsed = tmpEncoding;
  656.                 }
  657.             }
  658.         }
  659.     }
  660.     /**
  661.      *  The end-of-line sequence of characters to be used in the XML being
  662.      *  written out. The only permitted values are these:
  663.      *     . null
  664.      *
  665.      *  Use a default end-of-line sequence. DOM implementations should choose
  666.      * the default to match the usual convention for text files in the
  667.      * environment being used. Implementations must choose a default
  668.      * sequence that matches one of those allowed by  2.11 "End-of-Line
  669.      * Handling".
  670.      *
  671.      *    CR    The carriage-return character (#xD)
  672.      *    CR-LF The carriage-return and line-feed characters (#xD #xA)
  673.      *    LF    The line-feed character (#xA)
  674.      *
  675.      *  The default value for this attribute is null
  676.      */
  677.     fNewLineUsed = (fNewLine && *fNewLine)? fNewLine : gEOLSeq;
  678.     /**
  679.      *  get Document Version
  680.      */
  681.     const DOMDocument *docu = (nodeToWrite->getNodeType() == DOMNode::DOCUMENT_NODE)?
  682.                               (const DOMDocument*)nodeToWrite : nodeToWrite->getOwnerDocument();
  683.     if (docu)
  684.     {
  685.         fDocumentVersion = docu->getVersion();
  686.     }
  687.     fErrorCount = 0;
  688. }
  689. //
  690. // Characters not representable in output encoding,
  691. //
  692. // 1. CHARACTER DATA (outside of markup)                --- no error
  693. //    ordinary character  -> numeric character reference
  694. //    '<' and '&'         -> &lt; and &amp;
  695. //
  696. // 2. Within MARKUP, but outside of attributes
  697. //    reported as an error                                 --- ERROR
  698. //    markup:
  699. //           start tag                                  done
  700. //           end tag                                    done
  701. //           empty element tag                          done
  702. //           entity references                          done
  703. //           character references    // REVISIT
  704. //           comments                                   done
  705. //           CDATA section delimiters                   done, done
  706. //           document type declarartions                done
  707. //           processing instructions (PI)               done
  708. //
  709. // 3. With in ATTRIBUTE
  710. //    -> numeric character reference
  711. //    no quotes                        -> in quotes
  712. //    with quotes, no apostrophe       -> in apostrophe
  713. //    with quotes and apostrophe       -> in quotes and &quot;
  714. //
  715. // 4. CDATA sections
  716. //    "split_cdata_section"  true                      --- char ref
  717. //                           false                     ---      ERROR
  718. //
  719. // ---------------------------------------------------------------------------
  720. //  Stream out a DOM node, and, recursively, all of its children. This
  721. //  function is the heart of writing a DOM tree out as XML source. Give it
  722. //  a document node and it will do the whole thing.
  723. // ---------------------------------------------------------------------------
  724. void DOMWriterImpl::processNode(const DOMNode* const nodeToWrite, int level)
  725. {
  726.     // Get the name and value out for convenience
  727.     const XMLCh*    nodeName = nodeToWrite->getNodeName();
  728.     const XMLCh*    nodeValue = nodeToWrite->getNodeValue();
  729.     unsigned long   lent = XMLString::stringLen(nodeValue);
  730.     switch (nodeToWrite->getNodeType())
  731.     {
  732.     case DOMNode::TEXT_NODE:
  733.         {
  734.             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
  735.                 break;
  736.             //skip ws if pretty print
  737.             if (getFeature(FORMAT_PRETTY_PRINT_ID))
  738.             {
  739.                 if(XMLString::isAllWhiteSpace(nodeValue))
  740.                     break;
  741.             }
  742.             setURCharRef();      // character data
  743.             fFormatter->formatBuf(nodeValue, lent, XMLFormatter::CharEscapes);
  744.             break;
  745.         }
  746.     case DOMNode::PROCESSING_INSTRUCTION_NODE:
  747.         {
  748.             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
  749.                 break;
  750.             if(level == 1)
  751.                 printNewLine();
  752.             printNewLine();
  753.             printIndent(level);
  754.             TRY_CATCH_THROW
  755.             (
  756.                 *fFormatter << XMLFormatter::NoEscapes << gStartPI << nodeName;
  757.                 if (lent > 0)
  758.                 {
  759.                     *fFormatter << chSpace << nodeValue;
  760.                 }
  761.                 *fFormatter << gEndPI;
  762.                 ,true
  763.             )
  764.             break;
  765.         }
  766.     case DOMNode::DOCUMENT_NODE: // Not to be shown to Filter
  767.         {
  768.             // output BOM if needed
  769.             processBOM();          
  770.             
  771.             setURCharRef();
  772.             const DOMDocument *docu = (const DOMDocument*)nodeToWrite;
  773.         
  774.             //[23] XMLDecl      ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
  775.             //[24] VersionInfo  ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
  776.             //[80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName
  777.             //[32] SDDecl       ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"'))
  778.             //
  779.             // We always print out the xmldecl no matter whether it is
  780.             // present in the original XML instance document or not.
  781.             //
  782.             const XMLCh* versionNo = (docu->getVersion()) ? docu->getVersion() : gXMLDecl_ver10;
  783.             *fFormatter << gXMLDecl_VersionInfo << versionNo << gXMLDecl_separator;
  784.             // use the encoding resolved in initSession()
  785.             *fFormatter << gXMLDecl_EncodingDecl << fEncodingUsed << gXMLDecl_separator;
  786.             const XMLCh* st = (docu->getStandalone())? XMLUni::fgYesString : XMLUni::fgNoString;
  787.             *fFormatter << gXMLDecl_SDDecl << st << gXMLDecl_separator;
  788.             *fFormatter << gXMLDecl_endtag;
  789.             DOMNodeSPtr child = nodeToWrite->getFirstChild();
  790.             while( child != 0)
  791.             {
  792.                 processNode(child, level);
  793.                 child = child->getNextSibling();
  794.             }
  795.             printNewLine();
  796.             break;
  797.         }
  798.     case DOMNode::DOCUMENT_FRAGMENT_NODE:
  799.         {
  800.            
  801.             setURCharRef();
  802.             DOMNode *child = nodeToWrite->getFirstChild();
  803.             while( child != 0)
  804.             {
  805.                 processNode(child, level);
  806.                 child = child->getNextSibling();
  807.             }
  808.             printNewLine();
  809.             break;
  810.         }
  811.     case DOMNode::ELEMENT_NODE:
  812.         {
  813.             DOMNodeFilter::FilterAction filterAction = checkFilter(nodeToWrite);
  814.             if ( filterAction == DOMNodeFilter::FILTER_REJECT)
  815.                 break;
  816.             if(level == 1)
  817.                 printNewLine();
  818.             printNewLine();
  819.             printIndent(level);
  820.             //track the line number the current node begins on
  821.             int nodeLine = fCurrentLine;
  822.             // add an entry in the namespace stack
  823.             RefHashTableOf<XMLCh>* namespaceMap=new (fMemoryManager) RefHashTableOf<XMLCh>(12, false, fMemoryManager);
  824.             fNamespaceStack->addElement(namespaceMap);
  825.             if ( filterAction == DOMNodeFilter::FILTER_ACCEPT)
  826.             {
  827.                 //           this element    attributes   child elements
  828.                 // accept        yes             yes           yes
  829.                 // skip          no              no            yes
  830.                 //
  831.                 TRY_CATCH_THROW
  832.                 (
  833.                 // The name has to be representable without any escapes
  834.                     *fFormatter  << XMLFormatter::NoEscapes
  835.                                  << chOpenAngle << nodeName;
  836.                     ,true
  837.                 )
  838.                 // Output any attributes on this element
  839.                 setURCharRef();
  840.                 DOMNamedNodeMap *attributes = nodeToWrite->getAttributes();
  841.                 int attrCount = attributes->getLength();
  842.                 // check if the namespace for the current node is already defined
  843.                 const XMLCh* prefix = nodeToWrite->getPrefix();
  844.                 const XMLCh* uri = nodeToWrite->getNamespaceURI();
  845.                 if(uri && uri[0])
  846.                 {
  847.                     if(prefix==0 || prefix[0]==0)
  848.                         prefix=XMLUni::fgZeroLenString;
  849.                     bool bPrefixDeclared=false;
  850.                     for(int i=fNamespaceStack->size()-1;i>=0;i--)
  851.                     {
  852.                         RefHashTableOf<XMLCh>* curNamespaceMap=fNamespaceStack->elementAt(i);
  853.                         const XMLCh* thisUri=curNamespaceMap->get((void*)prefix);
  854.                         if(thisUri && XMLString::equals(thisUri,nodeToWrite->getNamespaceURI()))
  855.                         {
  856.                             bPrefixDeclared=true;
  857.                             break;
  858.                         }
  859.                     }
  860.                     if(!bPrefixDeclared)
  861.                     {
  862.                         namespaceMap->put((void*)prefix,(XMLCh*)nodeToWrite->getNamespaceURI());
  863.                         *fFormatter  << XMLFormatter::NoEscapes
  864.                                      << chSpace << s_xmlns;
  865.                         if(!XMLString::equals(prefix,XMLUni::fgZeroLenString))
  866.                             *fFormatter  << chColon << prefix;
  867.                         *fFormatter  << chEqual << chDoubleQuote
  868.                                      << XMLFormatter::AttrEscapes
  869.                                      << nodeToWrite->getNamespaceURI()
  870.                                      << XMLFormatter::NoEscapes
  871.                                      << chDoubleQuote;
  872.                     }
  873.                 }
  874.                 bool discard = getFeature(DISCARD_DEFAULT_CONTENT_ID);
  875.                 for (int i = 0; i < attrCount; i++)
  876.                 {
  877.                     DOMAttrSPtr  attribute = (DOMAttr*)attributes->item(i);
  878.                     // Not to be shown to Filter
  879.                     //
  880.                     //"discard-default-content"
  881.                     //    true
  882.                     //    [required] (default)
  883.                     //    Use whatever information available to the implementation
  884.                     //  (i.e. XML schema, DTD, the specified flag on Attr nodes,
  885.                     //  and so on) to decide what attributes and content should be
  886.                     //  discarded or not.
  887.                     //  Note that the specified flag on Attr nodes in itself is
  888.                     //  not always reliable, it is only reliable when it is set
  889.                     //  to false since the only case where it can be set to false
  890.                     //  is if the attribute was created by the implementation.
  891.                     //  The default content won't be removed if an implementation
  892.                     //  does not have any information available.
  893.                     //    false
  894.                     //    [required]
  895.                     //    Keep all attributes and all content.
  896.                     //
  897.                     if (discard && !((DOMAttr*)attribute )->getSpecified())
  898.                         continue;
  899.                     //
  900.                     //  Again the name has to be completely representable. But the
  901.                     //  attribute can have refs and requires the attribute style
  902.                     //  escaping.
  903.                     //
  904.                     // if this attribute is a namespace declaration, add it to the namespace map for the current level
  905.                     const XMLCh* ns = attribute->getNamespaceURI();
  906.                     if (ns != 0 )
  907.                     {
  908.                         if(XMLString::equals(ns, s_xmlnsURI)) 
  909.                         {
  910.                 const XMLCh* nsPrefix = attribute->getLocalName();
  911.                             if(XMLString::equals(attribute->getNodeName(),s_xmlns))
  912. nsPrefix = XMLUni::fgZeroLenString;
  913. if(namespaceMap->containsKey((void*)nsPrefix))
  914. continue;
  915.                             namespaceMap->put((void*)attribute->getLocalName(),(XMLCh*)attribute->getNodeValue());
  916.                         }
  917.                         else if(!XMLString::equals(ns, s_xmlURI)) 
  918.                         {
  919.                             // check if the namespace for the current node is already defined
  920.                             const XMLCh* prefix = attribute->getPrefix();
  921.                             if(prefix && prefix[0])
  922.                             {
  923.                                 bool bPrefixDeclared=false;
  924.                                 for(int i=fNamespaceStack->size()-1;i>=0;i--)
  925.                                 {
  926.                                     RefHashTableOf<XMLCh>* curNamespaceMap=fNamespaceStack->elementAt(i);
  927.                                     const XMLCh* thisUri=curNamespaceMap->get((void*)prefix);
  928.                                     if(thisUri && XMLString::equals(thisUri,attribute->getNamespaceURI()))
  929.                                     {
  930.                                         bPrefixDeclared=true;
  931.                                         break;
  932.                                     }
  933.                                 }
  934.                                 if(!bPrefixDeclared)
  935.                                 {
  936.                                     namespaceMap->put((void*)prefix,(XMLCh*)attribute->getNamespaceURI());
  937.                                     *fFormatter  << XMLFormatter::NoEscapes
  938.                                                  << chSpace << s_xmlns << chColon << prefix
  939.                                                  << chEqual << chDoubleQuote
  940.                                                  << XMLFormatter::AttrEscapes
  941.                                                  << attribute->getNamespaceURI()
  942.                                                  << XMLFormatter::NoEscapes
  943.                                                  << chDoubleQuote;
  944.                                 }
  945.                             }
  946.                         }
  947.                     }
  948.                     *fFormatter  << XMLFormatter::NoEscapes
  949.                                  << chSpace << attribute->getNodeName()
  950.                                  << chEqual << chDoubleQuote
  951.                                  << XMLFormatter::AttrEscapes
  952.                                  << attribute->getNodeValue()
  953.                                  << XMLFormatter::NoEscapes
  954.                                  << chDoubleQuote;
  955.                 } // end of for
  956.             } // end of FILTER_ACCEPT
  957.             level++;
  958.             // FILTER_SKIP may start from here
  959.             //
  960.             //  Test for the presence of children, which includes both
  961.             //  text content and nested elements.
  962.             //
  963.             DOMNodeSPtr child = nodeToWrite->getFirstChild();
  964.             if (child != 0)
  965.             {
  966.                 // There are children. Close start-tag, and output children.
  967.                 // No escapes are legal here
  968.                 if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
  969.                     *fFormatter << XMLFormatter::NoEscapes << chCloseAngle;
  970.                 while( child != 0)
  971.                 {
  972.                     processNode(child, level);
  973.                     child = child->getNextSibling();
  974.                 }
  975.                 level--;
  976.                 if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
  977.                 {
  978.                     //if we are not on the same line as when we started
  979.                     //this node then print a new line and indent
  980.                     if(nodeLine != fCurrentLine)
  981.                     {
  982.                         printNewLine();
  983.                         if(nodeLine != fCurrentLine && level == 0)
  984.                             printNewLine();
  985.                         printIndent(level);
  986.                     }
  987.                     TRY_CATCH_THROW
  988.                     (
  989.                          *fFormatter << XMLFormatter::NoEscapes << gEndElement
  990.                                      << nodeName << chCloseAngle;
  991.                         ,true
  992.                     )
  993.                 }
  994.             }
  995.             else
  996.             {
  997.                 level--;
  998.                 //
  999.                 //  There were no children. Output the short form close of
  1000.                 //  the element start tag, making it an empty-element tag.
  1001.                 //
  1002.                 if (filterAction == DOMNodeFilter::FILTER_ACCEPT)
  1003.                 {
  1004.                     TRY_CATCH_THROW
  1005.                     (
  1006.                         *fFormatter << XMLFormatter::NoEscapes << chForwardSlash << chCloseAngle;
  1007.                        , true
  1008.                     )
  1009.                 }
  1010.             }
  1011.             // remove the namespace map at this level
  1012.             fNamespaceStack->removeLastElement();
  1013.             break;
  1014.         }
  1015.     case DOMNode::ENTITY_REFERENCE_NODE:
  1016.         {
  1017.             //"entities"
  1018.             //true
  1019.             //[required] (default)
  1020.             //Keep EntityReference and Entity nodes in the document.
  1021.             //false
  1022.             //[optional]
  1023.             //Remove all EntityReference and Entity nodes from the document,
  1024.             //       putting the entity expansions directly in their place.
  1025.             //       Text nodes are into "normal" form.
  1026.             //Only EntityReference nodes to non-defined entities are kept in the document.
  1027.             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
  1028.                 break;
  1029.             if (getFeature(ENTITIES_ID))
  1030.             {
  1031.                 TRY_CATCH_THROW
  1032.                 (
  1033.                     *fFormatter << XMLFormatter::NoEscapes << chAmpersand
  1034.                                 << nodeName << chSemiColon;
  1035.                     , true
  1036.                 )
  1037.             }
  1038.             else
  1039.             {
  1040.                 // check if the referenced entity is defined or not
  1041.                 if (nodeToWrite->getOwnerDocument()->getDoctype()->getEntities()->getNamedItem(nodeName))
  1042.                 {
  1043.                     DOMNodeSPtr child;
  1044.                     for (child = nodeToWrite->getFirstChild();
  1045.                     child != 0;
  1046.                     child = child->getNextSibling())
  1047.                     {
  1048.                         processNode(child, level);
  1049.                     }
  1050.                 }
  1051.                 else
  1052.                 {
  1053.                     TRY_CATCH_THROW
  1054.                    (
  1055.                         *fFormatter<<XMLFormatter::NoEscapes<<chAmpersand<<nodeName<<chSemiColon;
  1056.                         , true
  1057.                     )
  1058.                 }
  1059.             }
  1060.             break;
  1061.         }
  1062.         //
  1063.         //  feature:split_cdata_sections     occurence of ]]>   unrep-char
  1064.         //  ===============================================================
  1065.         //          true                        split            split
  1066.         //          false                       fails            fails
  1067.         //
  1068.     case DOMNode::CDATA_SECTION_NODE:
  1069.         {
  1070.             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
  1071.                 break;
  1072.             if(level == 1)
  1073.                 printNewLine();
  1074.             printNewLine();
  1075.             printIndent(level);
  1076.             if (getFeature(SPLIT_CDATA_SECTIONS_ID))
  1077.             {
  1078.                 // it is fairly complicated and we process this
  1079.                 // in a separate function.
  1080.                 procCdataSection(nodeValue, nodeToWrite, level);
  1081.             }
  1082.             else
  1083.             {
  1084.                 // search for "]]>", the node value is not supposed to have this
  1085.                 if (XMLString::patternMatch((XMLCh* const) nodeValue, gEndCDATA) != -1)
  1086.                 {
  1087.                     reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NestedCDATA);
  1088.                 }
  1089.                 TRY_CATCH_THROW
  1090.                 (
  1091.                     // transcoder throws exception for unrep chars
  1092.                     *fFormatter << XMLFormatter::NoEscapes << gStartCDATA << nodeValue << gEndCDATA;
  1093.                    , true
  1094.                 )
  1095.             }
  1096.             break;
  1097.         }
  1098.     case DOMNode::COMMENT_NODE:
  1099.         {
  1100.             if (checkFilter(nodeToWrite) != DOMNodeFilter::FILTER_ACCEPT)
  1101.                 break;
  1102.             if(level == 1)
  1103.                 printNewLine();
  1104.             printNewLine();
  1105.             printIndent(level);
  1106.             TRY_CATCH_THROW
  1107.             (
  1108.                 *fFormatter << XMLFormatter::NoEscapes << gStartComment
  1109.                 << nodeValue << gEndComment;
  1110.                 , true
  1111.             )
  1112.             break;
  1113.         }
  1114.     case DOMNode::DOCUMENT_TYPE_NODE:  // Not to be shown to Filter
  1115.         {
  1116.             const DOMDocumentType *doctype = (const DOMDocumentType *)nodeToWrite;;
  1117.             fFormatter->setEscapeFlags(XMLFormatter::NoEscapes);
  1118.             printNewLine();
  1119.             printIndent(level);
  1120.             TRY_CATCH_THROW
  1121.             (
  1122.                 *fFormatter << gStartDoctype << nodeName;
  1123.                 const XMLCh  *id = doctype->getPublicId();
  1124.                 if (id && *id)
  1125.                 {
  1126.                     *fFormatter << chSpace << gPublic << id << chDoubleQuote;
  1127.                     id = doctype->getSystemId();
  1128.                     if (id && *id)
  1129.                     {
  1130.                         *fFormatter << chSpace << chDoubleQuote << id << chDoubleQuote;
  1131.                     }
  1132.                     else
  1133.                     {
  1134.                         //
  1135.                         // 4.2.2 External Entities
  1136.                         // [Definition: If the entity is not internal,
  1137.                         //           it is an external entity, declared as follows:]
  1138.                         // External Entity Declaration
  1139.                         // [75] ExternalID ::= 'SYSTEM' S SystemLiteral
  1140.                         //                   | 'PUBLIC' S PubidLiteral S SystemLiteral
  1141.                         //
  1142.                         reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NotRecognizedType);
  1143.                         // systemLiteral not found
  1144.                     }
  1145.                 }
  1146.                 else
  1147.                 {
  1148.                     id = doctype->getSystemId();
  1149.                     if (id && *id)
  1150.                     {
  1151.                         *fFormatter << chSpace << gSystem << id << chDoubleQuote;
  1152.                     }
  1153.                 }
  1154.                 id = doctype->getInternalSubset();
  1155.                 if (id && *id)
  1156.                 {
  1157.                     *fFormatter << chSpace << chOpenSquare << id << chCloseSquare;
  1158.                 }
  1159.                 *fFormatter << chCloseAngle;
  1160.                 , true
  1161.             ) // end of TRY_CATCH_THROW
  1162.             break;
  1163.         }
  1164.     case DOMNode::ENTITY_NODE:  // Not to be shown to Filter
  1165.         {
  1166.             //
  1167.             // REVISIT: how does the feature "entities" impact
  1168.             // entity node?
  1169.             //
  1170.             printNewLine();
  1171.             printIndent(level);
  1172.             fFormatter->setEscapeFlags(XMLFormatter::NoEscapes);
  1173.             *fFormatter << gStartEntity    << nodeName;
  1174.             const XMLCh * id = ((const DOMEntity*)nodeToWrite)->getPublicId();
  1175.             if (id)
  1176.                 *fFormatter << gPublic << id << chDoubleQuote;
  1177.             id = ((const DOMEntity*)nodeToWrite)->getSystemId();
  1178.             if (id)
  1179.                 *fFormatter << gSystem << id << chDoubleQuote;
  1180.             id = ((const DOMEntity*)nodeToWrite)->getNotationName();
  1181.             if (id)
  1182.                 *fFormatter << gNotation << id << chDoubleQuote;
  1183.             *fFormatter << chCloseAngle;
  1184.             break;
  1185.         }
  1186.     default:
  1187.         /***
  1188.             This is an implementation specific behaviour, we abort serialization
  1189.             once unrecognized node type encountered.
  1190.          ***/
  1191.         {
  1192.             reportError(nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, XMLDOMMsg::Writer_NotRecognizedType);
  1193.             // UnreognizedNodeType;
  1194.         }
  1195.         break;
  1196.     }
  1197. }
  1198. //
  1199. //
  1200. DOMNodeFilter::FilterAction DOMWriterImpl::checkFilter(const DOMNode* const node) const
  1201. {
  1202.     if (!fFilter ||
  1203.         ((fFilter->getWhatToShow() & (1 << (node->getNodeType() - 1))) == 0))
  1204.         return DOMNodeFilter::FILTER_ACCEPT;
  1205.     //
  1206.     // if and only if there is a filter, and it is interested
  1207.     // in the node type, then we pass the node to the filter
  1208.     // for examination
  1209.     //
  1210.     return (DOMNodeFilter::FilterAction) fFilter->acceptNode(node);
  1211. }
  1212. bool DOMWriterImpl::checkFeature(const XMLCh* const featName
  1213.                                , bool               toThrow
  1214.                                , int&               featureId) const
  1215. {
  1216.     // check for null and/or empty feature name
  1217.     if (!featName || !*featName)
  1218.     {
  1219.         if (toThrow)
  1220.             throw DOMException(DOMException::NOT_FOUND_ERR, 0);
  1221.         return false;
  1222.     }
  1223.     featureId = INVALID_FEATURE_ID;
  1224.     if (XMLString::equals(featName, XMLUni::fgDOMWRTCanonicalForm))
  1225.         featureId = CANONICAL_FORM_ID;
  1226.     else if (XMLString::equals(featName, XMLUni::fgDOMWRTDiscardDefaultContent))
  1227.         featureId = DISCARD_DEFAULT_CONTENT_ID;
  1228.     else if (XMLString::equals(featName, XMLUni::fgDOMWRTEntities))
  1229.         featureId = ENTITIES_ID;
  1230.     else if (XMLString::equals(featName, XMLUni::fgDOMWRTFormatPrettyPrint))
  1231.         featureId = FORMAT_PRETTY_PRINT_ID;
  1232.     else if (XMLString::equals(featName, XMLUni::fgDOMWRTNormalizeCharacters))
  1233.         featureId = NORMALIZE_CHARACTERS_ID;
  1234.     else if (XMLString::equals(featName, XMLUni::fgDOMWRTSplitCdataSections))
  1235.         featureId = SPLIT_CDATA_SECTIONS_ID;
  1236.     else if (XMLString::equals(featName, XMLUni::fgDOMWRTValidation))
  1237.         featureId = VALIDATION_ID;
  1238.     else if (XMLString::equals(featName, XMLUni::fgDOMWRTWhitespaceInElementContent))
  1239.         featureId = WHITESPACE_IN_ELEMENT_CONTENT_ID;
  1240.     else if (XMLString::equals(featName, XMLUni::fgDOMWRTBOM))
  1241.         featureId = BYTE_ORDER_MARK_ID;
  1242.     //feature name not resolvable
  1243.     if (featureId == INVALID_FEATURE_ID)
  1244.     {
  1245.         if (toThrow)
  1246.             throw DOMException(DOMException::NOT_FOUND_ERR, featName);
  1247.         return false;
  1248.     }
  1249.     return true;
  1250. }
  1251. bool DOMWriterImpl::reportError(const DOMNode* const    errorNode
  1252.                               , DOMError::ErrorSeverity errorType
  1253.                               , const XMLCh*   const    errorMsg)
  1254. {
  1255.     bool toContinueProcess = true;   // default value for no error handler
  1256.     if (fErrorHandler)
  1257.     {
  1258.         DOMLocatorImpl  locator(0, 0, (DOMNode* const) errorNode, 0, 0);
  1259.         DOMErrorImpl    domError(errorType , errorMsg, &locator);
  1260.         toContinueProcess = fErrorHandler->handleError(domError);
  1261.     }
  1262.     if (errorType != DOMError::DOM_SEVERITY_WARNING)
  1263.         fErrorCount++;
  1264.     return toContinueProcess;
  1265. }
  1266. bool DOMWriterImpl::reportError(const DOMNode* const    errorNode
  1267.                               , DOMError::ErrorSeverity errorType
  1268.                               , XMLDOMMsg::Codes        toEmit)
  1269. {
  1270.     const unsigned int msgSize = 1023;
  1271.     XMLCh errText[msgSize + 1];
  1272.     DOMImplementationImpl::getMsgLoader4DOM()->loadMsg(toEmit, errText, msgSize);
  1273.     bool toContinueProcess = true;   // default value for no error handler
  1274.     if (fErrorHandler)
  1275.     {
  1276.         DOMLocatorImpl  locator(0, 0, (DOMNode* const) errorNode, 0, 0);
  1277.         DOMErrorImpl    domError(errorType , errText, &locator);
  1278.         toContinueProcess = fErrorHandler->handleError(domError);
  1279.     }
  1280.     if (errorType != DOMError::DOM_SEVERITY_WARNING)
  1281.         fErrorCount++;
  1282.     if (errorType == DOMError::DOM_SEVERITY_FATAL_ERROR || !toContinueProcess)
  1283.         throw toEmit;
  1284.     return toContinueProcess;
  1285. }
  1286. //
  1287. //
  1288. //
  1289. void DOMWriterImpl::procCdataSection(const XMLCh*   const nodeValue
  1290.                                    , const DOMNode* const nodeToWrite
  1291.                                    , int level)
  1292. {
  1293.     /***
  1294.      * Append a ']]>' at the end
  1295.      */
  1296.     int len = XMLString::stringLen(nodeValue);
  1297.     XMLCh* repNodeValue = (XMLCh*) fMemoryManager->allocate
  1298.     (
  1299.         (len + offset + 1) * sizeof(XMLCh)
  1300.     );//new XMLCh [len + offset + 1];
  1301.     XMLString::copyString(repNodeValue, nodeValue);
  1302.     XMLString::catString(repNodeValue, gEndCDATA);
  1303.     ArrayJanitor<XMLCh>  jName(repNodeValue, fMemoryManager);
  1304.     XMLCh* curPtr  = (XMLCh*) repNodeValue;
  1305.     XMLCh* nextPtr = 0;
  1306.     int    endTagPos = -1;
  1307.     bool   endTagFound = true;
  1308.     while (endTagFound)
  1309.     {
  1310.         endTagPos = XMLString::patternMatch(curPtr, gEndCDATA);
  1311.         if (endTagPos != -1)
  1312.         {
  1313.             nextPtr = curPtr + endTagPos + offset;  // skip the ']]>'
  1314.             *(curPtr + endTagPos) = chNull;         //nullify the first ']'
  1315.             if (endTagPos != len)
  1316.                 reportError(nodeToWrite, DOMError::DOM_SEVERITY_WARNING, XMLDOMMsg::Writer_NestedCDATA);
  1317.             len = len - endTagPos - offset;
  1318.         }
  1319.         else
  1320.         {
  1321.             endTagFound = false;
  1322.         }
  1323.         /***
  1324.             to check ]]>]]>
  1325.         ***/
  1326.         if (endTagPos == 0)
  1327.         {
  1328.             printNewLine();
  1329.             printIndent(level);
  1330.             TRY_CATCH_THROW
  1331.             (
  1332.                 *fFormatter << XMLFormatter::NoEscapes << gStartCDATA << gEndCDATA;
  1333.                 , true
  1334.             )
  1335.         }
  1336.         else
  1337.         {
  1338.             procUnrepCharInCdataSection(curPtr, nodeToWrite, level);
  1339.         }
  1340.         if (endTagFound)
  1341.         {
  1342.             *(nextPtr - offset) = chCloseSquare;   //restore the first ']'
  1343.             curPtr = nextPtr;
  1344.         }
  1345.     }
  1346.     return;
  1347. }
  1348. //
  1349. //
  1350. //
  1351. void DOMWriterImpl::procUnrepCharInCdataSection(const XMLCh*   const nodeValue
  1352.                                               , const DOMNode* const nodeToWrite
  1353.                                               , int level)
  1354. {
  1355.     //
  1356.     //  We have to check each character and see if it could be represented.
  1357.     //  As long as it can, we just keep up with where we started and how
  1358.     //  many chars we've checked. When we hit an unrepresentable one, we
  1359.     //  stop, transcode everything we've collected, then start handling
  1360.     //  the unrepresentables via char refs. We repeat this until we get all
  1361.     //  the chars done.
  1362.     //
  1363.     const XMLCh*    srcPtr = nodeValue;
  1364.     const XMLCh*    endPtr = nodeValue +  XMLString::stringLen(nodeValue);;
  1365.     // Set up the common part of the buffer that we build char refs into
  1366.     XMLCh tmpBuf[32];
  1367.     tmpBuf[0] = chAmpersand;
  1368.     tmpBuf[1] = chPound;
  1369.     tmpBuf[2] = chLatin_x;
  1370.     while (srcPtr < endPtr)
  1371.     {
  1372.         const XMLCh* tmpPtr = srcPtr;
  1373.         while (tmpPtr < endPtr)
  1374.         {
  1375.             if (fFormatter->getTranscoder()->canTranscodeTo(*tmpPtr))
  1376.                 tmpPtr++;
  1377.             else
  1378.                 break;
  1379.         }
  1380.         if (tmpPtr > srcPtr)
  1381.         {
  1382.             printNewLine();
  1383.             printIndent(level);
  1384.             TRY_CATCH_THROW
  1385.            (
  1386.                 *fFormatter << XMLFormatter::NoEscapes << gStartCDATA;
  1387.                 , true
  1388.             )
  1389.             // We got at least some chars that can be done normally
  1390.             fFormatter->formatBuf
  1391.             (
  1392.                 srcPtr
  1393.                 , tmpPtr - srcPtr
  1394.                 , XMLFormatter::NoEscapes
  1395.                 , XMLFormatter::UnRep_Fail
  1396.             );
  1397.             TRY_CATCH_THROW
  1398.             (
  1399.                 *fFormatter << XMLFormatter::NoEscapes << gEndCDATA;
  1400.                 , true
  1401.             )
  1402.             // Update the source pointer to our new spot
  1403.             srcPtr = tmpPtr;
  1404.         }
  1405.         else
  1406.         {
  1407.             //
  1408.             //  We hit something unrepresentable. So continue forward doing
  1409.             //  char refs until we hit something representable again or the
  1410.             //  end of input.
  1411.             //
  1412.             // one warning for consective unrep chars
  1413.             reportError(nodeToWrite, DOMError::DOM_SEVERITY_WARNING, XMLDOMMsg::Writer_NotRepresentChar);
  1414.             while (srcPtr < endPtr)
  1415.             {
  1416.                 // Build a char ref for the current char
  1417.                 XMLString::binToText(*srcPtr, &tmpBuf[3], 8, 16);
  1418.                 const unsigned int bufLen = XMLString::stringLen(tmpBuf);
  1419.                 tmpBuf[bufLen] = chSemiColon;
  1420.                 tmpBuf[bufLen+1] = chNull;
  1421.                 // And now call recursively back to our caller to format this
  1422.                 fFormatter->formatBuf
  1423.                 (
  1424.                     tmpBuf
  1425.                     , bufLen + 1
  1426.                     , XMLFormatter::NoEscapes
  1427.                     , XMLFormatter::UnRep_Fail
  1428.                 );
  1429.                 // Move up the source pointer and break out if needed
  1430.                 srcPtr++;
  1431.                 if (fFormatter->getTranscoder()->canTranscodeTo(*srcPtr))
  1432.                     break;
  1433.             }
  1434.         }
  1435.     }
  1436. }
  1437. void DOMWriterImpl::processNode(const DOMNode* const nodeToWrite)
  1438. {
  1439.     processNode(nodeToWrite, 0);
  1440. }
  1441. bool DOMWriterImpl::canSetFeature(const int featureId
  1442.                                        , bool      val) const
  1443. {
  1444.     return featuresSupported[2*featureId + (val? 0: 1)];
  1445. }
  1446. void DOMWriterImpl::printNewLine()
  1447. {
  1448.     if (getFeature(FORMAT_PRETTY_PRINT_ID))
  1449.     {
  1450.         fCurrentLine++;
  1451.         *fFormatter << fNewLineUsed;
  1452.     }
  1453. }
  1454. void DOMWriterImpl::printIndent(int level) const
  1455. {
  1456.     if (getFeature(FORMAT_PRETTY_PRINT_ID))
  1457.     {
  1458.         for(int i = 0; i < level; i++)
  1459.             *fFormatter << chSpace << chSpace;
  1460.     }
  1461. }
  1462. void DOMWriterImpl::release()
  1463. {
  1464.     DOMWriterImpl* writer = (DOMWriterImpl*) this;
  1465.     delete writer;
  1466. }
  1467. void DOMWriterImpl::processBOM()
  1468. {
  1469.     // if the feature is not set, don't output bom
  1470.     if (!getFeature(BYTE_ORDER_MARK_ID))
  1471.         return;
  1472.     if ((XMLString::compareIString(fEncoding, XMLUni::fgUTF16LEncodingString)  == 0) ||
  1473.         (XMLString::compareIString(fEncoding, XMLUni::fgUTF16LEncodingString2) == 0)  )
  1474.     {
  1475.         fFormatter->writeBOM(BOM_utf16le, 2);
  1476.     }
  1477.     else if ((XMLString::compareIString(fEncoding, XMLUni::fgUTF16BEncodingString)  == 0) ||
  1478.              (XMLString::compareIString(fEncoding, XMLUni::fgUTF16BEncodingString2) == 0)  )
  1479.     {
  1480.         fFormatter->writeBOM(BOM_utf16be, 2);
  1481.     }
  1482.     else if ((XMLString::compareIString(fEncoding, XMLUni::fgUTF16EncodingString)  == 0) ||
  1483.              (XMLString::compareIString(fEncoding, XMLUni::fgUTF16EncodingString2) == 0) ||
  1484.              (XMLString::compareIString(fEncoding, XMLUni::fgUTF16EncodingString3) == 0) ||
  1485.              (XMLString::compareIString(fEncoding, XMLUni::fgUTF16EncodingString4) == 0) ||
  1486.              (XMLString::compareIString(fEncoding, XMLUni::fgUTF16EncodingString5) == 0)  ) 
  1487.     {
  1488. #if defined(ENDIANMODE_LITTLE)
  1489.             fFormatter->writeBOM(BOM_utf16le, 2);
  1490. #elif defined(ENDIANMODE_BIG)
  1491.             fFormatter->writeBOM(BOM_utf16be, 2);
  1492. #endif
  1493.     }
  1494.     else if ((XMLString::compareIString(fEncoding, XMLUni::fgUCS4LEncodingString)  == 0) ||
  1495.              (XMLString::compareIString(fEncoding, XMLUni::fgUCS4LEncodingString2) == 0)  )
  1496.     {
  1497.         fFormatter->writeBOM(BOM_ucs4le, 4);
  1498.     }
  1499.     else if ((XMLString::compareIString(fEncoding, XMLUni::fgUCS4BEncodingString)  == 0) ||
  1500.              (XMLString::compareIString(fEncoding, XMLUni::fgUCS4BEncodingString2) == 0)  )
  1501.     {
  1502.         fFormatter->writeBOM(BOM_ucs4be, 4);
  1503.     }
  1504.     else if ((XMLString::compareIString(fEncoding, XMLUni::fgUCS4EncodingString)  == 0) ||
  1505.              (XMLString::compareIString(fEncoding, XMLUni::fgUCS4EncodingString2) == 0) ||
  1506.              (XMLString::compareIString(fEncoding, XMLUni::fgUCS4EncodingString3) == 0)  )
  1507.     {
  1508. #if defined(ENDIANMODE_LITTLE)
  1509.         fFormatter->writeBOM(BOM_ucs4le, 4);
  1510. #elif defined(ENDIANMODE_BIG)
  1511.         fFormatter->writeBOM(BOM_ucs4be, 4);
  1512. #endif
  1513.     }
  1514.     return;
  1515. }
  1516. XERCES_CPP_NAMESPACE_END