<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2002-2004 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact <EMAIL>.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their featName, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 * $Log$
 * Revision 1.53  2004/05/10 08:03:25  amassari
 * Performance: push a new map on the namespace stack only when an element has a xmlns attribute
 *
 * Revision 1.52  2004/04/01 22:05:32  peiyongz
 * invoke DOMException with Memory Manager
 *
 * Revision 1.51  2004/01/29 11:44:27  cargilld
 * Code cleanup changes to get rid of various compiler diagnostic messages.
 *
 * Revision 1.50  2004/01/20 23:23:57  peiyongz
 * patch to Bug#25751
 *
 * Revision 1.49  2004/01/13 20:47:42  knoaman
 * Remove unnecessary local static data
 *
 * Revision 1.48  2004/01/13 16:34:20  cargilld
 * Misc memory management changes.
 *
 * Revision 1.47  2003/12/17 00:18:33  cargilld
 * Update to memory management so that the static memory manager (one used to call Initialize) is only for static data.
 *
 * Revision 1.46  2003/11/24 19:52:22  neilg
 * fix a typo
 *
 * Revision 1.45  2003/11/24 12:27:57  gareth
 * added in support for xml-declaration feature.
 *
 * Revision 1.44  2003/11/24 11:10:58  gareth
 * Fix for bug 22917. Patch by <NAME> .
 *
 * Revision 1.43  2003/11/10 17:52:58  amassari
 * Fixed memory leak
 *
 * Revision 1.42  2003/10/01 16:32:37  neilg
 * improve handling of out of memory conditions, bug #23415.  Thanks to <NAME>.
 *
 * Revision 1.41  2003/08/14 16:31:13  gareth
 * Method added to allow serilization of custom nodes from derived classes.
 *
 * Revision 1.40  2003/08/12 12:46:57  gareth
 * Added serialization for attribute nodes. Patch by <NAME>.
 *
 * Revision 1.39  2003/05/18 14:02:03  knoaman
 * Memory manager implementation: pass per instance manager.
 *
 * Revision 1.38  2003/05/16 21:36:55  knoaman
 * Memory manager implementation: Modify constructors to pass in the memory manager.
 *
 * Revision 1.37  2003/05/15 18:25:54  knoaman
 * Partial implementation of the configurable memory manager.
 *
 * Revision 1.36  2003/05/14 16:20:13  gareth
 * Fix to problem with multiple default namespace attributes being serialized. Patch by <NAME>.
 *
 * Revision 1.35  2003/05/12 16:08:11  gareth
 * fix to #18832. Corrected serilization with regards to namespace nodes. Patch by <NAME>.
 *
 * Revision 1.34  2003/05/06 13:48:35  neilg
 * fix GCC compilation problem and incorrect #include
 *
 * Revision 1.33  2003/05/05 21:23:21  neilg
 * use of the new DOMNodeSPtr typedef and its friends to enable reference counting in
 * the DOMWriter implementation for applications that require it.
 *
 * Revision 1.32  2003/04/02 03:14:42  peiyongz
 * Bug#18594: DOMWriter does not recognize Document Fragment
 *
 * Revision 1.31  2003/03/16 05:42:04  peiyongz
 * Bug#17983 Formatter does not escape control characters
 *
 * Revision 1.30  2003/02/25 16:07:37  tng
 * [Bug 13493] Use const on static data in DOMWriterImpl.cpp.
 *
 * Revision 1.29  2003/01/28 18:31:47  peiyongz
 * Bug#13694: Allow Xerces to write the BOM to XML files
 *
 * Revision 1.28  2003/01/24 20:21:46  tng
 * DOMWriter: Call XMLFormatTarget::flush when done.
 *
 * Revision 1.27  2003/01/20 16:50:13  tng
 * DOMWriter fix:
 * 1. wrong wrong nested cdata message
 * 2. pretty format the cdata section
 * 3. do not increment error count if warning was issued
 *
 * Revision 1.26  2003/01/09 19:53:45  tng
 * [Bug 15372] DOMBuilder::parseFromURI ignores result of handleErrors.
 *
 * Revision 1.25  2002/12/10 21:01:32  tng
 * NLS: DOMWriter should use message loader to load message instead of using hardcoded static stirng
 *
 * Revision 1.24  2002/12/10 18:59:14  tng
 * pretty format print: consistent newline
 *
 * Revision 1.23  2002/12/10 13:34:07  tng
 * Pretty-format print: also indent PI/comment that appear inside the root element.
 *
 * Revision 1.22  2002/12/09 11:46:08  gareth
 * More pretty pretty print feature. Patch by <NAME>. Closes bug #13840.
 *
 * Revision 1.21  2002/12/02 23:08:09  peiyongz
 * fix to bug#14528: output n+1 cdatasection
 *
 * Revision 1.20  2002/11/13 21:51:22  peiyongz
 * fix to Bug#14528
 *
 * Revision 1.19  2002/11/04 15:07:35  tng
 * C++ Namespace Support.
 *
 * Revision 1.18  2002/10/03 18:13:38  peiyongz
 * Bug#12560 Use const in DOMWriter - patch from <NAME>
 *                                                              (<EMAIL> )
 *
 * Revision 1.17  2002/09/24 20:19:14  tng
 * Performance: use XMLString::equals instead of XMLString::compareString
 * and check for null string directly isntead of calling XMLString::stringLen
 *
 * Revision 1.16  2002/09/09 15:42:14  peiyongz
 * Patch to Bug#12369: invalid output from DOMWriter using MemBufFormatTarget
 *
 * Revision 1.15  2002/08/07 18:10:19  peiyongz
 * Fix to Bug#11534: Wrong CDATA Terminator in DOMWriterImpl
 *
 * Revision 1.14  2002/07/22 23:24:01  tng
 * DOM L3: writeToString should use the fFormatter to do the transcoding
 *
 * Revision 1.13  2002/07/16 15:19:42  peiyongz
 * check lenght of getEncoding()/getActualEncoding()
 *
 * Revision 1.12  2002/06/25 16:17:16  tng
 * DOM L3: add release()
 *
 * Revision 1.11  2002/06/21 19:33:12  peiyongz
 * support for feature split_cdata_section and entities revised.
 *
 * Revision 1.10  2002/06/18 15:35:25  peiyongz
 * Bug#9950: Compilation error on MSVC5, patch from <EMAIL> (<NAME>)
 *
 * Revision 1.9  2002/06/17 19:45:58  peiyongz
 * optimization on fFeatures and featureId introduced
 *
 * Revision 1.8  2002/06/11 19:45:45  peiyongz
 * Notify application of the XMLFormatter creation failure
 *
 * Revision 1.7  2002/06/10 16:02:21  peiyongz
 * format-pretty-print partially supported
 * resolve encoding from DOMDocument Interface
 *
 * Revision 1.6  2002/06/06 20:58:37  tng
 * [Bug 9639] enum_mem in DOMError clashes with constant.
 *
 * Revision 1.5  2002/06/05 16:03:03  peiyongz
 * delete[] used.
 *
 * Revision 1.4  2002/06/03 22:35:54  peiyongz
 * constants changed
 *
 * Revision 1.3  2002/05/31 21:01:06  peiyongz
 * move printing of XMLDecl into the processNode().
 *
 * Revision 1.2  2002/05/29 21:31:50  knoaman
 * DOM L3 LS: DOMInputSource, DOMEntityResolver, DOMImplementationLS and DOMBuilder
 *
 * Revision 1.1  2002/05/28 22:39:39  peiyongz
 * DOM3 Save Interface: DOMWriter/DOMWriterFilter
 *
 */

#include "DOMWriterImpl.hpp"
#include "DOMErrorImpl.hpp"
#include "DOMLocatorImpl.hpp"
#include "DOMImplementationImpl.hpp"

#include <xercesc/framework/MemBufFormatTarget.hpp>

#include <xercesc/util/TransService.hpp>
#include <xercesc/util/TranscodingException.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/dom/StDOMNode.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>

XERCES_CPP_NAMESPACE_BEGIN


// ---------------------------------------------------------------------------
//  Local const data
//
// ---------------------------------------------------------------------------

static const int INVALID_FEATURE_ID               = -1;
static const int CANONICAL_FORM_ID                = 0x0;
static const int DISCARD_DEFAULT_CONTENT_ID       = 0x1;
static const int ENTITIES_ID                      = 0x2;
static const int FORMAT_PRETTY_PRINT_ID           = 0x3;
static const int NORMALIZE_CHARACTERS_ID          = 0x4;
static const int SPLIT_CDATA_SECTIONS_ID          = 0x5;
static const int VALIDATION_ID                    = 0x6;
static const int WHITESPACE_IN_ELEMENT_CONTENT_ID = 0x7;
static const int BYTE_ORDER_MARK_ID               = 0x8;
static const int XML_DECLARATION                 = 0x9;

//    feature                      true                       false
// ================================================================================
//canonical-form                 [optional] Not Supported     [required] (default)
//discard-default-content        [required] (default)         [required]
//entity                         [required] (default)         [optional]
//format-pretty-print            [optional] Partially Supported [required] (default)
//normalize-characters           [optional] Not Supported     [required] (default)
//split-cdata-sections           [required] (default)         [required]
//validation                     [optional] Not Supported     [required] (default)
//whitespace-in-element-content  [requierd] (default)         [optional] Not Supported
//

//
// Each feature has 2 entries in this array,
// the first for "true",
// the second for "false".
//
static const bool  featuresSupported[] = {
    false, true,  // canonical-form
    true,  true,  // discard-default-content
    true,  true,  // entity
    true,  true,  // format-pretty-print
    false, true,  // normalize-characters
    true,  true,  // split-cdata-sections
    false, true,  // validation
    true,  false, // whitespace-in-element-content
    true,  true,   // byte-order-mark
    true,  true   // xml-declaration
};

// default end-of-line sequence
static const XMLCh  gEOLSeq[] =
{
    chLF, chNull
};

//UTF-8
static const XMLCh  gUTF8[] =
{
    chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull
};

//</
static const XMLCh  gEndElement[] =
{
    chOpenAngle, chForwardSlash, chNull
};

//?>
static const XMLCh  gEndPI[] =
{
    chQuestion, chCloseAngle, chNull
};

//<?
static const XMLCh  gStartPI[] =
{
    chOpenAngle, chQuestion, chNull
};

//<?xml version="
static const XMLCh  gXMLDecl_VersionInfo[] =
{
    chOpenAngle, chQuestion, chLatin_x,     chLatin_m,  chLatin_l,  chSpace,
    chLatin_v,   chLatin_e,  chLatin_r,     chLatin_s,  chLatin_i,  chLatin_o,
    chLatin_n,   chEqual,    chDoubleQuote, chNull
};

static const XMLCh gXMLDecl_ver10[] =
{
    chDigit_1, chPeriod, chDigit_0, chNull
};

//encoding="
static const XMLCh  gXMLDecl_EncodingDecl[] =
{
    chLatin_e,  chLatin_n,  chLatin_c,  chLatin_o,      chLatin_d, chLatin_i,
    chLatin_n,  chLatin_g,  chEqual,    chDoubleQuote,  chNull
};

//" standalone="
static const XMLCh  gXMLDecl_SDDecl[] =
{
    chLatin_s, chLatin_t, chLatin_a,   chLatin_n,    chLatin_d,   chLatin_a,
    chLatin_l, chLatin_o, chLatin_n,   chLatin_e,    chEqual,     chDoubleQuote,
    chNull
};

//"
static const XMLCh  gXMLDecl_separator[] =
{
    chDoubleQuote, chSpace, chNull
};

//?>
static const XMLCh  gXMLDecl_endtag[] =
{
    chQuestion, chCloseAngle,  chNull
};

//<![CDATA[
static const XMLCh  gStartCDATA[] =
{
    chOpenAngle, chBang,    chOpenSquare, chLatin_C, chLatin_D,
    chLatin_A,   chLatin_T, chLatin_A,    chOpenSquare, chNull
};

//]]>
static const XMLCh  gEndCDATA[] =
{
//    chCloseSquare, chCloseAngle, chCloseAngle, chNull  // test only: ]>>
      chCloseSquare, chCloseSquare, chCloseAngle, chNull
};

static const int offset = XMLString::stringLen(gEndCDATA);

//<!--
static const XMLCh  gStartComment[] =
{
    chOpenAngle, chBang, chDash, chDash, chNull
};

//-->
static const XMLCh  gEndComment[] =
{
    chDash, chDash, chCloseAngle, chNull
};

//<!DOCTYPE
static const XMLCh  gStartDoctype[] =
{
    chOpenAngle, chBang,    chLatin_D, chLatin_O, chLatin_C, chLatin_T,
    chLatin_Y,   chLatin_P, chLatin_E, chSpace,   chNull
};

//PUBLIC "
static const XMLCh  gPublic[] =
{
    chLatin_P, chLatin_U, chLatin_B,     chLatin_L, chLatin_I,
    chLatin_C, chSpace,   chDoubleQuote, chNull
};

//SYSTEM "
static const XMLCh  gSystem[] =
{
    chLatin_S, chLatin_Y, chLatin_S,     chLatin_T, chLatin_E,
    chLatin_M, chSpace,   chDoubleQuote, chNull
};

//<!ENTITY
static const XMLCh  gStartEntity[] =
{
    chOpenAngle, chBang,    chLatin_E, chLatin_N, chLatin_T, chLatin_I,
    chLatin_T,   chLatin_Y, chSpace,   chNull
};

//NDATA "
static const XMLCh  gNotation[] =
{
    chLatin_N, chLatin_D,     chLatin_A, chLatin_T, chLatin_A,
    chSpace,   chDoubleQuote, chNull
};

//Feature
static const XMLCh  gFeature[] =
{
    chLatin_F, chLatin_e, chLatin_a, chLatin_t, chLatin_u, chLatin_r,
    chLatin_e, chSpace,   chNull
};

// Can not be set to
static const XMLCh  gCantSet[] =
{
    chSpace,   chLatin_C, chLatin_a, chLatin_n, chSpace, chLatin_n, chLatin_o,
    chLatin_t, chSpace,   chLatin_b, chLatin_e, chSpace, chLatin_s,
    chLatin_e, chLatin_t, chSpace,   chLatin_t, chLatin_o, chSpace, chNull
};

static const XMLCh  gTrue[] =
{
    chSingleQuote, chLatin_t, chLatin_r, chLatin_u, chLatin_e,
    chSingleQuote, chLF,      chNull
};

static const XMLCh  gFalse[] =
{
    chSingleQuote, chLatin_f, chLatin_a, chLatin_l, chLatin_s,
    chLatin_e,     chSingleQuote, chLF, chNull
};

static const XMLByte  BOM_utf16be[] = {(XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
static const XMLByte  BOM_utf16le[] = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte) 0};
static const XMLByte  BOM_ucs4be[]  = {(XMLByte)0x00, (XMLByte)0x00, (XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
static const XMLByte  BOM_ucs4le[]  = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte)0x00, (XMLByte)0x00, (XMLByte) 0};

static bool lineFeedInTextNodePrinted = false;
static int  lastWhiteSpaceInTextNode = 0;

//
// Notification of the error though error handler
//
// The application may instruct the engine to abort serialization
// by returning "false".
//
// REVISIT: update the locator ctor once the line#, col#, uri and offset
// are available from DOM3 core
//
// REVISIT: use throwing exception to abort serialization is an interesting
// thing here, since the serializer is a recusive function, we
// can't use return, obviously. However we may have multiple try/catch
// along its way going back to writeNode(). So far we don't come up with a
// "short-cut" to go "directly" back.
//
#define  TRY_CATCH_THROW(action, forceToRethrow)                     \
fFormatter->setUnRepFlags(XMLFormatter::UnRep_Fail);                 \
try                                                                  \
{                                                                    \
    action;                                                          \
}                                                                    \
catch(TranscodingException const &e)                                 \
{                                                                    \
    if ( !reportError(nodeToWrite                                    \
                    , DOMError::DOM_SEVERITY_FATAL_ERROR             \
                    , e.getMessage())                       ||       \
          forceToRethrow)                                            \
        throw e;                                                       \
}

DOMWriterImpl::~DOMWriterImpl()
{
    fMemoryManager->deallocate(fEncoding);//delete [] fEncoding;
    fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
    delete fNamespaceStack;
    // we don't own/adopt error handler and filter
}

DOMWriterImpl::DOMWriterImpl(MemoryManager* const manager)
:fFeatures(0)
,fEncoding(0)
,fNewLine(0)
,fErrorHandler(0)
,fFilter(0)
,fDocumentVersion(XMLUni::fgVersion1_0)
,fEncodingUsed(0)
,fNewLineUsed(0)
,fFormatter(0)
,fErrorCount(0)
,fCurrentLine(0)
,fNamespaceStack(0)
,fMemoryManager(manager)
{
    fNamespaceStack=new (fMemoryManager) RefVectorOf< RefHashTableOf<XMLCh> >(0,true, fMemoryManager);

    //
    // set features to default setting
    //
    setFeature(CANONICAL_FORM_ID,                false);
    setFeature(DISCARD_DEFAULT_CONTENT_ID,       true );
    setFeature(ENTITIES_ID,                      true );
    setFeature(FORMAT_PRETTY_PRINT_ID,           false);
    setFeature(NORMALIZE_CHARACTERS_ID,          false);
    setFeature(SPLIT_CDATA_SECTIONS_ID,          true );
    setFeature(VALIDATION_ID,                    false);
    setFeature(WHITESPACE_IN_ELEMENT_CONTENT_ID, true );
    setFeature(BYTE_ORDER_MARK_ID,               false);
    setFeature(XML_DECLARATION,                 true );

}

bool DOMWriterImpl::canSetFeature(const XMLCh* const featName
                                  , bool               state) const
{
    int featureId = INVALID_FEATURE_ID;
    return checkFeature(featName, false, featureId) ? canSetFeature(featureId, state) : false;
}

void DOMWriterImpl::setFeature(const XMLCh* const featName
                             , bool               state)
{
    int featureId = INVALID_FEATURE_ID;
    checkFeature(featName, true, featureId);

    if (!canSetFeature(featureId, state))
    {
        XMLCh  tmpbuf[256];
        unsigned int strLen = XMLString::stringLen(gFeature) +
                              XMLString::stringLen(featName) +
                              XMLString::stringLen(gCantSet) +
                              XMLString::stringLen(gFalse);

        XMLString::copyString(tmpbuf, gFeature);
        if (strLen < 256)
        {
            XMLString::catString(tmpbuf, featName);
        }
        else
        {
            // truncate the featurename to fit into the 256 buffer
            XMLString::copyNString(tmpbuf+XMLString::stringLen(gFeature),
                                   featName, 200);
        }
        XMLString::catString(tmpbuf, gCantSet);
        XMLString::catString(tmpbuf, state? gTrue : gFalse);
        throw DOMException(DOMException::NOT_SUPPORTED_ERR, tmpbuf, fMemoryManager);
    }
    else
        setFeature(featureId, state);

    //
    // canonical-form and format-pretty-print can not be both set to true
    // meaning set canonical-form true will automatically set
    // format-pretty-print to false and vise versa.
    //
    if ((featureId == CANONICAL_FORM_ID) && state)
        setFeature(FORMAT_PRETTY_PRINT_ID, false);

    if ((featureId == FORMAT_PRETTY_PRINT_ID) && state)
        setFeature(CANONICAL_FORM_ID, false);

    return;
}

bool DOMWriterImpl::getFeature(const XMLCh* const featName) const
{
    int featureId = INVALID_FEATURE_ID;
    checkFeature(featName, true, featureId);
    return getFeature(featureId);
}

// we don't check the validity of the encoding set
void DOMWriterImpl::setEncoding(const XMLCh* const encoding)
{
    fMemoryManager->deallocate(fEncoding);//delete [] fEncoding;
    fEncoding = XMLString::replicate(encoding, fMemoryManager);
}

const XMLCh* DOMWriterImpl::getEncoding() const
{
    return fEncoding;
}

void DOMWriterImpl::setNewLine(const XMLCh* const newLine)
{
    fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
    fNewLine = XMLString::replicate(newLine, fMemoryManager);
}

const XMLCh* DOMWriterImpl::getNewLine() const
{
    return fNewLine;
}

void DOMWriterImpl::setErrorHandler(DOMErrorHandler *errorHandler)
{
    fErrorHandler = errorHandler;
}

DOMErrorHandler* DOMWriterImpl::getErrorHandler() const
{
    return fErrorHandler;
}

void DOMWriterImpl::setFilter(DOMWriterFilter *filter)
{
    fFilter = filter;
}

DOMWriterFilter* DOMWriterImpl::getFilter() const
{
    return fFilter;
}

//
//
//
bool DOMWriterImpl::writeNode(XMLFormatTarget* const destination
                            , const DOMNode         &nodeToWrite)
{
    //init session vars
    initSession(&nodeToWrite);

    try
    {
        fFormatter = new (fMemoryManager) XMLFormatter(fEncodingUsed
                                     ,fDocumentVersion
                                     ,destination
                                     ,XMLFormatter::NoEscapes
                                     ,XMLFormatter::UnRep_CharRef);
    }
    catch (const TranscodingException& e)
    {
        reportError(&nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, e.getMessage());<commit_msg>Fix for jira#1238: DOMWriter was creating an XMLFormatter without propagating the memory manager<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2002-2004 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact <EMAIL>.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their featName, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 * $Log$
 * Revision 1.54  2004/07/06 15:16:57  amassari
 * Fix for jira#1238: DOMWriter was creating an XMLFormatter without propagating the memory manager
 *
 * Revision 1.53  2004/05/10 08:03:25  amassari
 * Performance: push a new map on the namespace stack only when an element has a xmlns attribute
 *
 * Revision 1.52  2004/04/01 22:05:32  peiyongz
 * invoke DOMException with Memory Manager
 *
 * Revision 1.51  2004/01/29 11:44:27  cargilld
 * Code cleanup changes to get rid of various compiler diagnostic messages.
 *
 * Revision 1.50  2004/01/20 23:23:57  peiyongz
 * patch to Bug#25751
 *
 * Revision 1.49  2004/01/13 20:47:42  knoaman
 * Remove unnecessary local static data
 *
 * Revision 1.48  2004/01/13 16:34:20  cargilld
 * Misc memory management changes.
 *
 * Revision 1.47  2003/12/17 00:18:33  cargilld
 * Update to memory management so that the static memory manager (one used to call Initialize) is only for static data.
 *
 * Revision 1.46  2003/11/24 19:52:22  neilg
 * fix a typo
 *
 * Revision 1.45  2003/11/24 12:27:57  gareth
 * added in support for xml-declaration feature.
 *
 * Revision 1.44  2003/11/24 11:10:58  gareth
 * Fix for bug 22917. Patch by <NAME> .
 *
 * Revision 1.43  2003/11/10 17:52:58  amassari
 * Fixed memory leak
 *
 * Revision 1.42  2003/10/01 16:32:37  neilg
 * improve handling of out of memory conditions, bug #23415.  Thanks to <NAME>.
 *
 * Revision 1.41  2003/08/14 16:31:13  gareth
 * Method added to allow serilization of custom nodes from derived classes.
 *
 * Revision 1.40  2003/08/12 12:46:57  gareth
 * Added serialization for attribute nodes. Patch by <NAME>.
 *
 * Revision 1.39  2003/05/18 14:02:03  knoaman
 * Memory manager implementation: pass per instance manager.
 *
 * Revision 1.38  2003/05/16 21:36:55  knoaman
 * Memory manager implementation: Modify constructors to pass in the memory manager.
 *
 * Revision 1.37  2003/05/15 18:25:54  knoaman
 * Partial implementation of the configurable memory manager.
 *
 * Revision 1.36  2003/05/14 16:20:13  gareth
 * Fix to problem with multiple default namespace attributes being serialized. Patch by <NAME>.
 *
 * Revision 1.35  2003/05/12 16:08:11  gareth
 * fix to #18832. Corrected serilization with regards to namespace nodes. Patch by <NAME>.
 *
 * Revision 1.34  2003/05/06 13:48:35  neilg
 * fix GCC compilation problem and incorrect #include
 *
 * Revision 1.33  2003/05/05 21:23:21  neilg
 * use of the new DOMNodeSPtr typedef and its friends to enable reference counting in
 * the DOMWriter implementation for applications that require it.
 *
 * Revision 1.32  2003/04/02 03:14:42  peiyongz
 * Bug#18594: DOMWriter does not recognize Document Fragment
 *
 * Revision 1.31  2003/03/16 05:42:04  peiyongz
 * Bug#17983 Formatter does not escape control characters
 *
 * Revision 1.30  2003/02/25 16:07:37  tng
 * [Bug 13493] Use const on static data in DOMWriterImpl.cpp.
 *
 * Revision 1.29  2003/01/28 18:31:47  peiyongz
 * Bug#13694: Allow Xerces to write the BOM to XML files
 *
 * Revision 1.28  2003/01/24 20:21:46  tng
 * DOMWriter: Call XMLFormatTarget::flush when done.
 *
 * Revision 1.27  2003/01/20 16:50:13  tng
 * DOMWriter fix:
 * 1. wrong wrong nested cdata message
 * 2. pretty format the cdata section
 * 3. do not increment error count if warning was issued
 *
 * Revision 1.26  2003/01/09 19:53:45  tng
 * [Bug 15372] DOMBuilder::parseFromURI ignores result of handleErrors.
 *
 * Revision 1.25  2002/12/10 21:01:32  tng
 * NLS: DOMWriter should use message loader to load message instead of using hardcoded static stirng
 *
 * Revision 1.24  2002/12/10 18:59:14  tng
 * pretty format print: consistent newline
 *
 * Revision 1.23  2002/12/10 13:34:07  tng
 * Pretty-format print: also indent PI/comment that appear inside the root element.
 *
 * Revision 1.22  2002/12/09 11:46:08  gareth
 * More pretty pretty print feature. Patch by <NAME>. Closes bug #13840.
 *
 * Revision 1.21  2002/12/02 23:08:09  peiyongz
 * fix to bug#14528: output n+1 cdatasection
 *
 * Revision 1.20  2002/11/13 21:51:22  peiyongz
 * fix to Bug#14528
 *
 * Revision 1.19  2002/11/04 15:07:35  tng
 * C++ Namespace Support.
 *
 * Revision 1.18  2002/10/03 18:13:38  peiyongz
 * Bug#12560 Use const in DOMWriter - patch from Duncan Stodart
 *                                                              (<EMAIL> )
 *
 * Revision 1.17  2002/09/24 20:19:14  tng
 * Performance: use XMLString::equals instead of XMLString::compareString
 * and check for null string directly isntead of calling XMLString::stringLen
 *
 * Revision 1.16  2002/09/09 15:42:14  peiyongz
 * Patch to Bug#12369: invalid output from DOMWriter using MemBufFormatTarget
 *
 * Revision 1.15  2002/08/07 18:10:19  peiyongz
 * Fix to Bug#11534: Wrong CDATA Terminator in DOMWriterImpl
 *
 * Revision 1.14  2002/07/22 23:24:01  tng
 * DOM L3: writeToString should use the fFormatter to do the transcoding
 *
 * Revision 1.13  2002/07/16 15:19:42  peiyongz
 * check lenght of getEncoding()/getActualEncoding()
 *
 * Revision 1.12  2002/06/25 16:17:16  tng
 * DOM L3: add release()
 *
 * Revision 1.11  2002/06/21 19:33:12  peiyongz
 * support for feature split_cdata_section and entities revised.
 *
 * Revision 1.10  2002/06/18 15:35:25  peiyongz
 * Bug#9950: Compilation error on MSVC5, patch from <EMAIL> (<NAME>)
 *
 * Revision 1.9  2002/06/17 19:45:58  peiyongz
 * optimization on fFeatures and featureId introduced
 *
 * Revision 1.8  2002/06/11 19:45:45  peiyongz
 * Notify application of the XMLFormatter creation failure
 *
 * Revision 1.7  2002/06/10 16:02:21  peiyongz
 * format-pretty-print partially supported
 * resolve encoding from DOMDocument Interface
 *
 * Revision 1.6  2002/06/06 20:58:37  tng
 * [Bug 9639] enum_mem in DOMError clashes with constant.
 *
 * Revision 1.5  2002/06/05 16:03:03  peiyongz
 * delete[] used.
 *
 * Revision 1.4  2002/06/03 22:35:54  peiyongz
 * constants changed
 *
 * Revision 1.3  2002/05/31 21:01:06  peiyongz
 * move printing of XMLDecl into the processNode().
 *
 * Revision 1.2  2002/05/29 21:31:50  knoaman
 * DOM L3 LS: DOMInputSource, DOMEntityResolver, DOMImplementationLS and DOMBuilder
 *
 * Revision 1.1  2002/05/28 22:39:39  peiyongz
 * DOM3 Save Interface: DOMWriter/DOMWriterFilter
 *
 */

#include "DOMWriterImpl.hpp"
#include "DOMErrorImpl.hpp"
#include "DOMLocatorImpl.hpp"
#include "DOMImplementationImpl.hpp"

#include <xercesc/framework/MemBufFormatTarget.hpp>

#include <xercesc/util/TransService.hpp>
#include <xercesc/util/TranscodingException.hpp>
#include <xercesc/util/Janitor.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLUniDefs.hpp>
#include <xercesc/util/XMLMsgLoader.hpp>
#include <xercesc/dom/StDOMNode.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>

XERCES_CPP_NAMESPACE_BEGIN


// ---------------------------------------------------------------------------
//  Local const data
//
// ---------------------------------------------------------------------------

static const int INVALID_FEATURE_ID               = -1;
static const int CANONICAL_FORM_ID                = 0x0;
static const int DISCARD_DEFAULT_CONTENT_ID       = 0x1;
static const int ENTITIES_ID                      = 0x2;
static const int FORMAT_PRETTY_PRINT_ID           = 0x3;
static const int NORMALIZE_CHARACTERS_ID          = 0x4;
static const int SPLIT_CDATA_SECTIONS_ID          = 0x5;
static const int VALIDATION_ID                    = 0x6;
static const int WHITESPACE_IN_ELEMENT_CONTENT_ID = 0x7;
static const int BYTE_ORDER_MARK_ID               = 0x8;
static const int XML_DECLARATION                 = 0x9;

//    feature                      true                       false
// ================================================================================
//canonical-form                 [optional] Not Supported     [required] (default)
//discard-default-content        [required] (default)         [required]
//entity                         [required] (default)         [optional]
//format-pretty-print            [optional] Partially Supported [required] (default)
//normalize-characters           [optional] Not Supported     [required] (default)
//split-cdata-sections           [required] (default)         [required]
//validation                     [optional] Not Supported     [required] (default)
//whitespace-in-element-content  [requierd] (default)         [optional] Not Supported
//

//
// Each feature has 2 entries in this array,
// the first for "true",
// the second for "false".
//
static const bool  featuresSupported[] = {
    false, true,  // canonical-form
    true,  true,  // discard-default-content
    true,  true,  // entity
    true,  true,  // format-pretty-print
    false, true,  // normalize-characters
    true,  true,  // split-cdata-sections
    false, true,  // validation
    true,  false, // whitespace-in-element-content
    true,  true,   // byte-order-mark
    true,  true   // xml-declaration
};

// default end-of-line sequence
static const XMLCh  gEOLSeq[] =
{
    chLF, chNull
};

//UTF-8
static const XMLCh  gUTF8[] =
{
    chLatin_U, chLatin_T, chLatin_F, chDash, chDigit_8, chNull
};

//</
static const XMLCh  gEndElement[] =
{
    chOpenAngle, chForwardSlash, chNull
};

//?>
static const XMLCh  gEndPI[] =
{
    chQuestion, chCloseAngle, chNull
};

//<?
static const XMLCh  gStartPI[] =
{
    chOpenAngle, chQuestion, chNull
};

//<?xml version="
static const XMLCh  gXMLDecl_VersionInfo[] =
{
    chOpenAngle, chQuestion, chLatin_x,     chLatin_m,  chLatin_l,  chSpace,
    chLatin_v,   chLatin_e,  chLatin_r,     chLatin_s,  chLatin_i,  chLatin_o,
    chLatin_n,   chEqual,    chDoubleQuote, chNull
};

static const XMLCh gXMLDecl_ver10[] =
{
    chDigit_1, chPeriod, chDigit_0, chNull
};

//encoding="
static const XMLCh  gXMLDecl_EncodingDecl[] =
{
    chLatin_e,  chLatin_n,  chLatin_c,  chLatin_o,      chLatin_d, chLatin_i,
    chLatin_n,  chLatin_g,  chEqual,    chDoubleQuote,  chNull
};

//" standalone="
static const XMLCh  gXMLDecl_SDDecl[] =
{
    chLatin_s, chLatin_t, chLatin_a,   chLatin_n,    chLatin_d,   chLatin_a,
    chLatin_l, chLatin_o, chLatin_n,   chLatin_e,    chEqual,     chDoubleQuote,
    chNull
};

//"
static const XMLCh  gXMLDecl_separator[] =
{
    chDoubleQuote, chSpace, chNull
};

//?>
static const XMLCh  gXMLDecl_endtag[] =
{
    chQuestion, chCloseAngle,  chNull
};

//<![CDATA[
static const XMLCh  gStartCDATA[] =
{
    chOpenAngle, chBang,    chOpenSquare, chLatin_C, chLatin_D,
    chLatin_A,   chLatin_T, chLatin_A,    chOpenSquare, chNull
};

//]]>
static const XMLCh  gEndCDATA[] =
{
//    chCloseSquare, chCloseAngle, chCloseAngle, chNull  // test only: ]>>
      chCloseSquare, chCloseSquare, chCloseAngle, chNull
};

static const int offset = XMLString::stringLen(gEndCDATA);

//<!--
static const XMLCh  gStartComment[] =
{
    chOpenAngle, chBang, chDash, chDash, chNull
};

//-->
static const XMLCh  gEndComment[] =
{
    chDash, chDash, chCloseAngle, chNull
};

//<!DOCTYPE
static const XMLCh  gStartDoctype[] =
{
    chOpenAngle, chBang,    chLatin_D, chLatin_O, chLatin_C, chLatin_T,
    chLatin_Y,   chLatin_P, chLatin_E, chSpace,   chNull
};

//PUBLIC "
static const XMLCh  gPublic[] =
{
    chLatin_P, chLatin_U, chLatin_B,     chLatin_L, chLatin_I,
    chLatin_C, chSpace,   chDoubleQuote, chNull
};

//SYSTEM "
static const XMLCh  gSystem[] =
{
    chLatin_S, chLatin_Y, chLatin_S,     chLatin_T, chLatin_E,
    chLatin_M, chSpace,   chDoubleQuote, chNull
};

//<!ENTITY
static const XMLCh  gStartEntity[] =
{
    chOpenAngle, chBang,    chLatin_E, chLatin_N, chLatin_T, chLatin_I,
    chLatin_T,   chLatin_Y, chSpace,   chNull
};

//NDATA "
static const XMLCh  gNotation[] =
{
    chLatin_N, chLatin_D,     chLatin_A, chLatin_T, chLatin_A,
    chSpace,   chDoubleQuote, chNull
};

//Feature
static const XMLCh  gFeature[] =
{
    chLatin_F, chLatin_e, chLatin_a, chLatin_t, chLatin_u, chLatin_r,
    chLatin_e, chSpace,   chNull
};

// Can not be set to
static const XMLCh  gCantSet[] =
{
    chSpace,   chLatin_C, chLatin_a, chLatin_n, chSpace, chLatin_n, chLatin_o,
    chLatin_t, chSpace,   chLatin_b, chLatin_e, chSpace, chLatin_s,
    chLatin_e, chLatin_t, chSpace,   chLatin_t, chLatin_o, chSpace, chNull
};

static const XMLCh  gTrue[] =
{
    chSingleQuote, chLatin_t, chLatin_r, chLatin_u, chLatin_e,
    chSingleQuote, chLF,      chNull
};

static const XMLCh  gFalse[] =
{
    chSingleQuote, chLatin_f, chLatin_a, chLatin_l, chLatin_s,
    chLatin_e,     chSingleQuote, chLF, chNull
};

static const XMLByte  BOM_utf16be[] = {(XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
static const XMLByte  BOM_utf16le[] = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte) 0};
static const XMLByte  BOM_ucs4be[]  = {(XMLByte)0x00, (XMLByte)0x00, (XMLByte)0xFE, (XMLByte)0xFF, (XMLByte) 0};
static const XMLByte  BOM_ucs4le[]  = {(XMLByte)0xFF, (XMLByte)0xFE, (XMLByte)0x00, (XMLByte)0x00, (XMLByte) 0};

static bool lineFeedInTextNodePrinted = false;
static int  lastWhiteSpaceInTextNode = 0;

//
// Notification of the error though error handler
//
// The application may instruct the engine to abort serialization
// by returning "false".
//
// REVISIT: update the locator ctor once the line#, col#, uri and offset
// are available from DOM3 core
//
// REVISIT: use throwing exception to abort serialization is an interesting
// thing here, since the serializer is a recusive function, we
// can't use return, obviously. However we may have multiple try/catch
// along its way going back to writeNode(). So far we don't come up with a
// "short-cut" to go "directly" back.
//
#define  TRY_CATCH_THROW(action, forceToRethrow)                     \
fFormatter->setUnRepFlags(XMLFormatter::UnRep_Fail);                 \
try                                                                  \
{                                                                    \
    action;                                                          \
}                                                                    \
catch(TranscodingException const &e)                                 \
{                                                                    \
    if ( !reportError(nodeToWrite                                    \
                    , DOMError::DOM_SEVERITY_FATAL_ERROR             \
                    , e.getMessage())                       ||       \
          forceToRethrow)                                            \
        throw e;                                                       \
}

DOMWriterImpl::~DOMWriterImpl()
{
    fMemoryManager->deallocate(fEncoding);//delete [] fEncoding;
    fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
    delete fNamespaceStack;
    // we don't own/adopt error handler and filter
}

DOMWriterImpl::DOMWriterImpl(MemoryManager* const manager)
:fFeatures(0)
,fEncoding(0)
,fNewLine(0)
,fErrorHandler(0)
,fFilter(0)
,fDocumentVersion(XMLUni::fgVersion1_0)
,fEncodingUsed(0)
,fNewLineUsed(0)
,fFormatter(0)
,fErrorCount(0)
,fCurrentLine(0)
,fNamespaceStack(0)
,fMemoryManager(manager)
{
    fNamespaceStack=new (fMemoryManager) RefVectorOf< RefHashTableOf<XMLCh> >(0,true, fMemoryManager);

    //
    // set features to default setting
    //
    setFeature(CANONICAL_FORM_ID,                false);
    setFeature(DISCARD_DEFAULT_CONTENT_ID,       true );
    setFeature(ENTITIES_ID,                      true );
    setFeature(FORMAT_PRETTY_PRINT_ID,           false);
    setFeature(NORMALIZE_CHARACTERS_ID,          false);
    setFeature(SPLIT_CDATA_SECTIONS_ID,          true );
    setFeature(VALIDATION_ID,                    false);
    setFeature(WHITESPACE_IN_ELEMENT_CONTENT_ID, true );
    setFeature(BYTE_ORDER_MARK_ID,               false);
    setFeature(XML_DECLARATION,                 true );

}

bool DOMWriterImpl::canSetFeature(const XMLCh* const featName
                                  , bool               state) const
{
    int featureId = INVALID_FEATURE_ID;
    return checkFeature(featName, false, featureId) ? canSetFeature(featureId, state) : false;
}

void DOMWriterImpl::setFeature(const XMLCh* const featName
                             , bool               state)
{
    int featureId = INVALID_FEATURE_ID;
    checkFeature(featName, true, featureId);

    if (!canSetFeature(featureId, state))
    {
        XMLCh  tmpbuf[256];
        unsigned int strLen = XMLString::stringLen(gFeature) +
                              XMLString::stringLen(featName) +
                              XMLString::stringLen(gCantSet) +
                              XMLString::stringLen(gFalse);

        XMLString::copyString(tmpbuf, gFeature);
        if (strLen < 256)
        {
            XMLString::catString(tmpbuf, featName);
        }
        else
        {
            // truncate the featurename to fit into the 256 buffer
            XMLString::copyNString(tmpbuf+XMLString::stringLen(gFeature),
                                   featName, 200);
        }
        XMLString::catString(tmpbuf, gCantSet);
        XMLString::catString(tmpbuf, state? gTrue : gFalse);
        throw DOMException(DOMException::NOT_SUPPORTED_ERR, tmpbuf, fMemoryManager);
    }
    else
        setFeature(featureId, state);

    //
    // canonical-form and format-pretty-print can not be both set to true
    // meaning set canonical-form true will automatically set
    // format-pretty-print to false and vise versa.
    //
    if ((featureId == CANONICAL_FORM_ID) && state)
        setFeature(FORMAT_PRETTY_PRINT_ID, false);

    if ((featureId == FORMAT_PRETTY_PRINT_ID) && state)
        setFeature(CANONICAL_FORM_ID, false);

    return;
}

bool DOMWriterImpl::getFeature(const XMLCh* const featName) const
{
    int featureId = INVALID_FEATURE_ID;
    checkFeature(featName, true, featureId);
    return getFeature(featureId);
}

// we don't check the validity of the encoding set
void DOMWriterImpl::setEncoding(const XMLCh* const encoding)
{
    fMemoryManager->deallocate(fEncoding);//delete [] fEncoding;
    fEncoding = XMLString::replicate(encoding, fMemoryManager);
}

const XMLCh* DOMWriterImpl::getEncoding() const
{
    return fEncoding;
}

void DOMWriterImpl::setNewLine(const XMLCh* const newLine)
{
    fMemoryManager->deallocate(fNewLine);//delete [] fNewLine;
    fNewLine = XMLString::replicate(newLine, fMemoryManager);
}

const XMLCh* DOMWriterImpl::getNewLine() const
{
    return fNewLine;
}

void DOMWriterImpl::setErrorHandler(DOMErrorHandler *errorHandler)
{
    fErrorHandler = errorHandler;
}

DOMErrorHandler* DOMWriterImpl::getErrorHandler() const
{
    return fErrorHandler;
}

void DOMWriterImpl::setFilter(DOMWriterFilter *filter)
{
    fFilter = filter;
}

DOMWriterFilter* DOMWriterImpl::getFilter() const
{
    return fFilter;
}

//
//
//
bool DOMWriterImpl::writeNode(XMLFormatTarget* const destination
                            , const DOMNode         &nodeToWrite)
{
    //init session vars
    initSession(&nodeToWrite);

    try
    {
        fFormatter = new (fMemoryManager) XMLFormatter(fEncodingUsed
                                     ,fDocumentVersion
                                     ,destination
                                     ,XMLFormatter::NoEscapes
                                     ,XMLFormatter::UnRep_CharRef
                                     ,fMemoryManager);
    }
    catch (const TranscodingException& e)
    {
        reportError(&nodeToWrite, DOMError::DOM_SEVERITY_FATAL_ERROR, e.getMessage());
{'fraction_non_alphanumeric': 0.10658314299283114, 'fraction_numerical': 0.04986544245686243, 'mean_word_length': 2.7579671963967027, 'pattern_counts': {'":': 0, '<': 64, '<?xml version=': 2, '>': 70, 'https://': 0, 'lorem ipsum': 0, 'www.': 6, 'xml': 8}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 55, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3384812', 'n_tokens_mistral': 15692, 'n_tokens_neox': 13759, 'n_words': 3963}