VirtualBox

Changeset 7309 in vbox


Ignore:
Timestamp:
Mar 5, 2008 5:47:51 PM (17 years ago)
Author:
vboxsync
Message:

Main/Settings: Added XSLT-based auto-conversion functionality to the XmlTree backend.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/settings.h

    r6310 r7309  
    125125            if (level > 5)
    126126            {
    127                 // if so, create a "Bar" key if it doesn't exist yet 
     127                // if so, create a "Bar" key if it doesn't exist yet
    128128                Key bar = (*it).createKey ("Bar");
    129129                // set the "date" attribute
     
    265265//////////////////////////////////////////////////////////////////////////////
    266266
    267 /** 
     267/**
    268268 * Temporary holder for the formatted string.
    269269 *
     
    276276public:
    277277
    278     /** 
     278    /**
    279279     * Creates a formatted string using the format string and a set of
    280280     * printf-like arguments.
     
    309309public:
    310310
    311     Error (const char *aMsg = NULL) 
     311    Error (const char *aMsg = NULL)
    312312        : m (aMsg ? Str::New (aMsg) : NULL) {}
    313313
     
    440440                                         int aBits, uint64_t aMin, uint64_t aMax);
    441441
    442 /** 
     442/**
    443443 * Generic template function to perform a conversion of an UTF-8 string to an
    444444 * arbitrary value of type @a T.
     
    458458 *
    459459 * @param aValue Value to convert.
    460  * 
     460 *
    461461 * @return Result of conversion.
    462462 */
     
    492492template<> DECLEXPORT (RTTIMESPEC) FromString <RTTIMESPEC> (const char *aValue);
    493493
    494 /** 
     494/**
    495495 * Converts a string of hex digits to memory bytes.
    496  * 
     496 *
    497497 * @param aValue String to convert.
    498498 * @param aLen   Where to store the length of the returned memory
    499499 *               block (may be NULL).
    500  * 
     500 *
    501501 * @return Result of conversion (a block of @a aLen bytes).
    502502 */
     
    513513                 bool aSigned, int aBits);
    514514
    515 /** 
     515/**
    516516 * Generic template function to perform a conversion of an arbitrary value to
    517517 * an UTF-8 string.
     
    569569ToString <RTTIMESPEC> (const RTTIMESPEC &aValue, unsigned int aExtra);
    570570
    571 /** 
     571/**
    572572 * Converts memory bytes to a null-terminated string of hex values.
    573  * 
     573 *
    574574 * @param aData Pointer to the memory block.
    575575 * @param aLen  Length of the memory block.
    576  * 
     576 *
    577577 * @return Result of conversion.
    578578 */
     
    582582//////////////////////////////////////////////////////////////////////////////
    583583
    584 /** 
     584/**
    585585 * The Key class represents a settings key.
    586586 *
     
    647647    };
    648648
    649     /** 
     649    /**
    650650     * Creates a new key object. If @a aBackend is @c NULL then a null key is
    651651     * created.
     
    653653     * Regular API users should never need to call this method with something
    654654     * other than NULL argument (which is the default).
    655      * 
     655     *
    656656     * @param aBackend      Key backend to use.
    657657     */
    658658    Key (Backend *aBackend = NULL) : m (aBackend) {}
    659659
    660     /** 
     660    /**
    661661     * Returns @c true if this key is null.
    662662     */
    663663    bool isNull() const { return m.is_null(); }
    664664
    665     /** 
     665    /**
    666666     * Makes this object a null key.
    667667     *
     
    671671    void setNull() { m = NULL; }
    672672
    673     /** 
     673    /**
    674674     * Returns the name of this key.
    675675     * Returns NULL if this object a null (uninitialized) key.
     
    677677    const char *name() const { return m.is_null() ? NULL : m->name(); }
    678678
    679     /** 
     679    /**
    680680     * Sets the name of this key.
    681      * 
     681     *
    682682     * @param aName New key name.
    683683     */
    684684    void setName (const char *aName) { if (!m.is_null()) m->setName (aName); }
    685685
    686     /** 
     686    /**
    687687     * Returns the value of the attribute with the given name as an UTF-8
    688688     * string. Returns @c NULL if there is no attribute with the given name.
     
    696696    }
    697697
    698     /** 
     698    /**
    699699     * Sets the value of the attribute with the given name from an UTF-8
    700700     * string. This method will do a copy of the supplied @a aValue string.
    701      * 
     701     *
    702702     * @param aName     Name of the attribute. NULL may be used to
    703703     *                  set the key value.
     
    710710    }
    711711
    712     /** 
     712    /**
    713713     * Returns the value of the attribute with the given name as an object of
    714714     * type @a T. Throws ENoValue if there is no attribute with the given
     
    718718     * the attribute and then calls the FromString() template to convert this
    719719     * string to a value of the given type.
    720      * 
     720     *
    721721     * @param aName     Name of the attribute. NULL may be used to
    722722     *                  get the key value.
     
    735735    }
    736736
    737     /** 
     737    /**
    738738     * Returns the value of the attribute with the given name as an object of
    739739     * type @a T. Returns the given default value if there is no attribute
     
    743743     * the attribute and then calls the FromString() template to convert this
    744744     * string to a value of the given type.
    745      * 
     745     *
    746746     * @param aName     Name of the attribute. NULL may be used to
    747747     *                  get the key value.
     
    761761    }
    762762
    763     /** 
     763    /**
    764764     * Sets the value of the attribute with the given name from an object of
    765765     * type @a T. This method will do a copy of data represented by @a aValue
     
    768768     * This function converts the given value to a string using the ToString()
    769769     * template and then calls #setStringValue().
    770      * 
     770     *
    771771     * @param aName     Name of the attribute. NULL may be used to
    772772     *                  set the key value.
     
    790790    }
    791791
    792     /** 
     792    /**
    793793     * Sets the value of the attribute with the given name from an object of
    794794     * type @a T. If the value of the @a aValue object equals to the value of
     
    798798     * This function converts the given value to a string using the ToString()
    799799     * template and then calls #setStringValue().
    800      * 
     800     *
    801801     * @param aName     Name of the attribute. NULL may be used to
    802802     *                  set the key value.
     
    817817    }
    818818
    819     /** 
     819    /**
    820820     * Deletes the value of the attribute with the given name.
    821821     * Shortcut to <tt>setStringValue(aName, NULL)</tt>.
     
    823823    void zapValue (const char *aName) { setStringValue (aName, NULL); }
    824824
    825     /** 
     825    /**
    826826     * Returns the key value.
    827827     * Shortcut to <tt>stringValue (NULL)</tt>.
     
    829829    const char *keyStringValue() const { return stringValue (NULL); }
    830830
    831     /** 
     831    /**
    832832     * Sets the key value.
    833833     * Shortcut to <tt>setStringValue (NULL, aValue)</tt>.
     
    835835    void setKeyStringValue (const char *aValue) { setStringValue (NULL, aValue); }
    836836
    837     /** 
     837    /**
    838838     * Returns the key value.
    839839     * Shortcut to <tt>value (NULL)</tt>.
     
    842842    T keyValue() const { return value <T> (NULL); }
    843843
    844     /** 
     844    /**
    845845     * Returns the key value or the given default if the key value is NULL.
    846846     * Shortcut to <tt>value (NULL)</tt>.
     
    849849    T keyValueOr (const T &aDefault) const { return valueOr <T> (NULL, aDefault); }
    850850
    851     /** 
     851    /**
    852852     * Sets the key value.
    853853     * Shortcut to <tt>setValue (NULL, aValue, aExtra)</tt>.
     
    859859    }
    860860
    861     /** 
     861    /**
    862862     * Sets the key value.
    863863     * Shortcut to <tt>setValueOr (NULL, aValue, aDefault)</tt>.
     
    870870    }
    871871
    872     /** 
     872    /**
    873873     * Deletes the key value.
    874874     * Shortcut to <tt>zapValue (NULL)</tt>.
     
    876876    void zapKeyValue () { zapValue (NULL); }
    877877
    878     /** 
     878    /**
    879879     * Returns a list of all child keys named @a aName.
    880880     *
    881881     * If @a aname is @c NULL, returns a list of all child keys.
    882      * 
     882     *
    883883     * @param aName     Child key name to list.
    884884     */
    885885    List keys (const char *aName = NULL) const
    886886    {
    887         return m.is_null() ? List() : m->keys (aName); 
     887        return m.is_null() ? List() : m->keys (aName);
    888888    };
    889889
    890     /** 
     890    /**
    891891     * Returns the first child key with the given name.
    892892     *
    893893     * Throws ENoKey if no child key with the given name exists.
    894      * 
     894     *
    895895     * @param aName     Child key name.
    896896     */
     
    903903    }
    904904
    905     /** 
     905    /**
    906906     * Returns the first child key with the given name.
    907907     *
    908908     * As opposed to #key(), this method will not throw an exception if no
    909909     * child key with the given name exists, but return a null key instead.
    910      * 
     910     *
    911911     * @param aName     Child key name.
    912912     */
    913913    Key findKey (const char *aName) const
    914914    {
    915         return m.is_null() ? Key() : m->findKey (aName); 
    916     }
    917 
    918     /** 
     915        return m.is_null() ? Key() : m->findKey (aName);
     916    }
     917
     918    /**
    919919     * Creates a key with the given name as a child of this key and returns it
    920920     * to the caller.
     
    922922     * If one or more child keys with the given name already exist, no new key
    923923     * is created but the first matching child key is returned.
    924      * 
     924     *
    925925     * @param aName Name of the child key to create.
    926926     */
     
    933933    }
    934934
    935     /** 
     935    /**
    936936     * Appends a key with the given name to the list of child keys of this key
    937937     * and returns the appended key to the caller.
    938      * 
     938     *
    939939     * @param aName Name of the child key to create.
    940940     */
    941941    Key appendKey (const char *aName)
    942942    {
    943         return m.is_null() ? Key() : m->appendKey (aName); 
    944     }
    945 
    946     /** 
     943        return m.is_null() ? Key() : m->appendKey (aName);
     944    }
     945
     946    /**
    947947     * Deletes this key.
    948948     *
     
    973973    }
    974974
    975     /** 
     975    /**
    976976     * Counterpart to operator==().
    977977     */
     
    985985};
    986986
    987 /** 
     987/**
    988988 * The Stream class is a base class for I/O streams.
    989989 */
     
    10161016};
    10171017
    1018 /** 
     1018/**
    10191019 * The Input class represents an input stream.
    10201020 *
     
    10291029    /**
    10301030     * Reads from the stream to the supplied buffer.
    1031      * 
     1031     *
    10321032     * @param aBuf Buffer to store read data to.
    10331033     * @param aLen Buffer length.
    1034      * 
     1034     *
    10351035     * @return Number of bytes read.
    10361036     */
     
    10471047    /**
    10481048     * Writes to the stream from the supplied buffer.
    1049      * 
     1049     *
    10501050     * @param aBuf Buffer to write data from.
    10511051     * @param aLen Buffer length.
    1052      * 
     1052     *
    10531053     * @return Number of bytes written.
    10541054     */
    10551055    virtual int write (const char *aBuf, int aLen) = 0;
    10561056
    1057     /** 
     1057    /**
    10581058     * Truncates the stream from the current position and upto the end.
    10591059     * The new file size will become exactly #pos() bytes.
     
    10781078public:
    10791079
    1080     /** 
     1080    /**
    10811081     * Reads and parses the given input stream.
    10821082     *
     
    10941094     * given stream before reading. After the stream has been successfully
    10951095     * parsed, the position will be set back to the beginning.
    1096      * 
     1096     *
    10971097     * @param aInput        Input stream.
    10981098     * @param aSchema       Schema URI to use for input stream validation.
     
    11061106    }
    11071107
    1108     /** 
     1108    /**
    11091109     * Reads and parses the given input stream in a raw fashion.
    11101110     *
    1111      * Currently, the only difference from #read() is that this method doesn't
    1112      * set the stream position to the beginnign before and after reading but
    1113      * instead leaves it as is in both cases which can give unexpected
    1114      * results.
     1111     * This method doesn't set the stream position to the beginnign before and
     1112     * after reading but instead leaves it as is in both cases. It's the
     1113     * caller's responsibility to maintain the correct position.
    11151114     *
    11161115     * @see read()
     
    11191118                          int aFlags = 0) = 0;
    11201119
    1121     /** 
     1120    /**
    11221121     * Writes the current settings tree to the given output stream.
    1123      * 
     1122     *
    11241123     * This method will set the read/write position to the beginning of the
    11251124     * given stream before writing. After the settings have been successfully
     
    11271126     * following the last byte written by this method anc ghd position will be
    11281127     * set back to the beginning.
    1129      * 
     1128     *
    11301129     * @param aOutput       Output stream.
    11311130     */
     
    11381137    }
    11391138
    1140     /** 
     1139    /**
    11411140     * Writes the current settings tree to the given output stream in a raw
    11421141     * fashion.
    11431142     *
    1144      * Currently, the only difference from #write() is that this method
    1145      * doesn't set the stream position to the beginning before and after
    1146      * reading and doesn't thruncate the stream, but instead leaves it as is
    1147      * in both cases which can give unexpected results.
     1143     * This method doesn't set the stream position to the beginnign before and
     1144     * after reading and doesn't truncate the stream, but instead leaves it as
     1145     * is in both cases. It's the caller's responsibility to maintain the
     1146     * correct position and perform truncation.
    11481147     *
    11491148     * @see write()
     
    11511150    virtual void rawWrite (Output &aOutput) = 0;
    11521151
    1153     /** 
     1152    /**
    11541153     * Deletes the current settings tree.
    11551154     */
    11561155    virtual void reset() = 0;
    11571156
    1158     /** 
     1157    /**
    11591158     * Returns the root settings key.
    11601159     */
     
    11871186     * or ReadWrite, the file must exist. If @a aMode is Write, the file must
    11881187     * not exist. Otherwise, an EIPRTFailure excetion will be thrown.
    1189      * 
     1188     *
    11901189     * @param aMode     File mode.
    11911190     * @param aFileName File name.
     
    12231222    void setPos (uint64_t aPos);
    12241223
    1225     /** 
     1224    /**
    12261225     * See Input::read(). If this method is called in wrong file mode,
    12271226     * LogicError will be thrown.
     
    12291228    int read (char *aBuf, int aLen);
    12301229
    1231     /** 
     1230    /**
    12321231     * See Output::write(). If this method is called in wrong file mode,
    12331232     * LogicError will be thrown.
     
    12351234    int write (const char *aBuf, int aLen);
    12361235
    1237     /** 
     1236    /**
    12381237     * See Output::truncate(). If this method is called in wrong file mode,
    12391238     * LogicError will be thrown.
     
    12511250};
    12521251
    1253 /** 
     1252/**
    12541253 * The MemoryBuf class represents a stream implementation that reads from the
    12551254 * memory buffer.
     
    12911290    enum
    12921291    {
    1293         /** 
     1292        /**
    12941293         * Sbstitute default values for missing attributes that have defaults
    12951294         * in the XML schema. Otherwise, stringValue() will return NULL for
     
    12991298    };
    13001299
    1301     /** 
     1300    /**
    13021301     * The InputResolver class represents an input resolver, the service used to
    13031302     * provide input streams for external entities given an URL and entity ID.
     
    13101309         * Returns a newly allocated input stream for the given arguments. The
    13111310         * caller will delete the returned object when no more necessary.
    1312          * 
     1311         *
    13131312         * @param aURI  URI of the external entity.
    13141313         * @param aID   ID of the external entity (may be NULL).
    1315          * 
     1314         *
    13161315         * @return      Input stream created using @c new or NULL to indicate
    13171316         *              a wrong URI/ID pair.
     
    13241323
    13251324
    1326     /** 
     1325    /**
    13271326     * The Error class represents errors that may happen when parsing or
    13281327     * validating the XML document representing the settings tree.
     
    13381337    ~XmlTreeBackend();
    13391338
    1340     /** 
     1339    /**
    13411340     * Sets an external entity resolver used to provide input streams for
    13421341     * entities referred to by the XML document being parsed.
     
    13451344     * until a different resolver is set using setInputResolver() or reset
    13461345     * using resetInputResolver().
    1347      * 
     1346     *
    13481347     * @param aResolver Resolver to use.
    13491348     */
    13501349    void setInputResolver (InputResolver &aResolver);
    13511350
    1352     /** 
     1351    /**
    13531352     * Resets the entity resolver to the default resolver. The default
    13541353     * resolver provides support for 'file:' and 'http:' protocols.
    13551354     */
    13561355    void resetInputResolver();
     1356
     1357    /**
     1358     * Sets up automatic settings tree conversion.
     1359     *
     1360     * Automatic settings tree conversion is useful for upgrading old settings
     1361     * files to the new version transparently during execution of the #read()
     1362     * method.
     1363     *
     1364     * Automatic conversion is performed after reading the document from the
     1365     * stream but before validating it using the given XSLT template if the
     1366     * version check fails. The version check consists of comparing the given
     1367     * version string with the value of the given attribute of the root key. The
     1368     * conversion is performed only when the version strings are not equal.
     1369     *
     1370     * Note that in order to make the conversion permanent, the resulting tree
     1371     * needs to be exlicitly written back to the stream.
     1372     *
     1373     * The method will make copies of the supplied strings.
     1374     *
     1375     * Specifying a NULL value for all of the arguments will completely disable
     1376     * automatic conversion. Specifying an invalid root key name or a
     1377     * non-existent attribute name will disable automatic conversion too. By
     1378     * default automatic conversion it is disabled.
     1379     *
     1380     * Specifying a NULL value only for some of the arguments will throw an
     1381     * EInvalidArg exception.
     1382     *
     1383     * @param aRoot     Name of the root key containing the version attribute.
     1384     * @param aAttr     Name of the attribute containing the version string.
     1385     * @param aVersion  Version string to compare with the attribute value.
     1386     * @param aTemplate URI of the XSLT template that performs conversion.
     1387     */
     1388    void setAutoConversion (const char *aRoot, const char *aAttr,
     1389                            const char *aVersion, const char *aTemplate);
     1390
     1391    /**
     1392     * Disables automatic settings conversion previously enabled by
     1393     * setAutoConversion(). By default automatic conversion it is disabled.
     1394     */
     1395    void resetAutoConversion()
     1396    {
     1397        setAutoConversion (NULL, NULL, NULL, NULL);
     1398    }
    13571399
    13581400    void rawRead (Input &aInput, const char *aSchema = NULL, int aFlags = 0);
  • trunk/src/VBox/Main/Makefile.kmk

    r6988 r7309  
    407407VBoxSettings_TEMPLATE   = VBOXMAINDLL
    408408VBoxSettings_NAME       = $(basename $(notdir $(LIB_SETTINGS)))
    409 VBoxSettings_SDKS       = VBOX_LIBXML2 VBOX_ZLIB
     409VBoxSettings_SDKS       = VBOX_LIBXSLT VBOX_LIBXML2 VBOX_ZLIB
    410410VBoxSettings_DEFS       = IN_VBOXSETTINGS_R3
    411411VBoxSettings_INCS       = \
  • trunk/src/VBox/Main/xml/Settings.cpp

    r7027 r7309  
    3030
    3131#include <libxml/xmlschemas.h>
     32
     33#include <libxslt/xsltInternals.h>
     34#include <libxslt/transform.h>
     35#include <libxslt/xsltutils.h>
    3236
    3337#include <string.h>
     
    804808    std::auto_ptr <stdx::exception_trap_base> trappedErr;
    805809
     810    struct AutoConv
     811    {
     812        AutoConv() : root (NULL), attr (NULL), version (NULL), xslt (NULL) {}
     813        ~AutoConv() { uninit(); }
     814
     815        void uninit()
     816        {
     817            RTStrFree (xslt); xslt = NULL;
     818            RTStrFree (version); version = NULL;
     819            RTStrFree (attr); attr = NULL;
     820            RTStrFree (root); root = NULL;
     821        }
     822
     823        bool isNull() { return xslt == NULL; }
     824
     825        char *root;
     826        char *attr;
     827        char *version;
     828        char *xslt;
     829    }
     830    autoConv;
     831
    806832    /**
    807833     * This is to avoid throwing exceptions while in libxml2 code and
     
    870896}
    871897
     898void XmlTreeBackend::setAutoConversion (const char *aRoot, const char *aAttr,
     899                                        const char *aVersion, const char *aTemplate)
     900{
     901    if (aRoot == NULL && aAttr == NULL && aVersion == NULL && aTemplate == NULL)
     902    {
     903        m->autoConv.uninit();
     904        return;
     905    }
     906
     907    if (aRoot == NULL || aAttr == NULL || aVersion == NULL || aTemplate == NULL)
     908        throw EInvalidArg (RT_SRC_POS);
     909
     910    m->autoConv.root = RTStrDup (aRoot);
     911    m->autoConv.attr = RTStrDup (aAttr);
     912    m->autoConv.version = RTStrDup (aVersion);
     913    m->autoConv.xslt = RTStrDup (aTemplate);
     914}
     915
    872916void XmlTreeBackend::rawRead (Input &aInput, const char *aSchema /* = NULL */,
    873917                              int aFlags /* = 0 */)
     
    876920     * libxml2 code. */
    877921    m->trappedErr.reset();
    878 
    879     /* Set up an input stream for parsing the document. This will be deleted
    880      * when the stream is closed by the libxml2 API (e.g. when calling
    881      * xmlFreeParserCtxt()). */
    882     Data::InputCtxt *inputCtxt =
    883         new Data::InputCtxt (&aInput, m->trappedErr);
    884922
    885923    /* Set up the external entity resolver. Note that we do it in a
     
    899937
    900938    /* parse the stream */
     939    /* NOTE: new InputCtxt instance will be deleted when the stream is closed by
     940     * the libxml2 API (e.g. when calling xmlFreeParserCtxt()) */
    901941    xmlDocPtr doc = xmlCtxtReadIO (m->ctxt,
    902942                                   ReadCallback, CloseCallback,
    903                                    inputCtxt, aInput.uri(), NULL,
     943                                   new Data::InputCtxt (&aInput, m->trappedErr),
     944                                   aInput.uri(), NULL,
    904945                                   XML_PARSE_NOBLANKS);
    905946    if (doc == NULL)
     
    916957    }
    917958
     959    /* perform automatic document transformation if necessary */
     960    if (!m->autoConv.isNull())
     961    {
     962        Key root = Key (new XmlKeyBackend (xmlDocGetRootElement (doc)));
     963        if (!strcmp (root.name(), m->autoConv.root))
     964        {
     965            const char *ver = root.stringValue (m->autoConv.attr);
     966            if (strcmp (ver, m->autoConv.version))
     967            {
     968                /* version mismatch */
     969
     970                xmlDocPtr xsltDoc = NULL;
     971                xsltStylesheetPtr xslt = NULL;
     972                xsltTransformContextPtr tranCtxt = NULL;
     973                char *errorStr = NULL;
     974
     975                try
     976                {
     977                    /* parse the XSLT */
     978                    {
     979                        Input *xsltInput =
     980                            m->inputResolver->resolveEntity (m->autoConv.xslt, NULL);
     981                        /* NOTE: new InputCtxt instance will be deleted when the
     982                         * stream is closed by the libxml2 API */
     983                        xsltDoc = xmlCtxtReadIO (m->ctxt,
     984                                                 ReadCallback, CloseCallback,
     985                                                 new Data::InputCtxt (xsltInput, m->trappedErr),
     986                                                 m->autoConv.xslt, NULL,
     987                                                 0);
     988                        delete xsltInput;
     989                    }
     990
     991                    if (xsltDoc == NULL)
     992                    {
     993                        /* look if there was a forwared exception from the lower level */
     994                        if (m->trappedErr.get() != NULL)
     995                            m->trappedErr->rethrow();
     996
     997                        throw XmlError (xmlCtxtGetLastError (m->ctxt));
     998                    }
     999
     1000                    xslt = xsltParseStylesheetDoc (xsltDoc);
     1001                    if (xslt == NULL)
     1002                        throw LogicError (RT_SRC_POS);
     1003
     1004                    /* setup transformation error reporting */
     1005                    tranCtxt = xsltNewTransformContext (xslt, xsltDoc);
     1006                    if (tranCtxt == NULL)
     1007                        throw LogicError (RT_SRC_POS);
     1008                    xsltSetTransformErrorFunc (tranCtxt, &errorStr, ValidityErrorCallback);
     1009
     1010                    xmlDocPtr newDoc = xsltApplyStylesheetUser (xslt, doc, NULL,
     1011                                                                NULL, NULL, tranCtxt);
     1012                    if (newDoc == NULL)
     1013                        throw LogicError (RT_SRC_POS);
     1014
     1015                    if (errorStr != NULL)
     1016                    {
     1017                        xmlFreeDoc (newDoc);
     1018                        throw Error (errorStr);
     1019                        /* errorStr is freed in catch(...) below */
     1020                    }
     1021
     1022                    /* replace the old document on success */
     1023                    xmlFreeDoc (doc);
     1024                    doc = newDoc;
     1025
     1026                    xsltFreeTransformContext (tranCtxt);
     1027
     1028                    /* NOTE: xsltFreeStylesheet() also fress the document
     1029                     * passed to xsltParseStylesheetDoc(). */
     1030                    xsltFreeStylesheet (xslt);
     1031                }
     1032                catch (...)
     1033                {
     1034                    /* restore the previous entity resolver */
     1035                    xmlSetExternalEntityLoader (oldEntityLoader);
     1036                    sThat = NULL;
     1037
     1038                    RTStrFree (errorStr);
     1039
     1040                    if (tranCtxt != NULL)
     1041                        xsltFreeTransformContext (tranCtxt);
     1042
     1043                    /* NOTE: xsltFreeStylesheet() also fress the document
     1044                     * passed to xsltParseStylesheetDoc(). */
     1045                    if (xslt != NULL)
     1046                        xsltFreeStylesheet (xslt);
     1047                    else if (xsltDoc != NULL)
     1048                        xmlFreeDoc (xsltDoc);
     1049
     1050                    throw;
     1051                }
     1052            }
     1053        }
     1054    }
     1055
     1056    /* validate the document */
    9181057    if (aSchema != NULL)
    9191058    {
     
    9231062        char *errorStr = NULL;
    9241063
    925         /* validate the document */
    9261064        try
    9271065        {
     
    11611299        -- newMsgLen;
    11621300
    1163     if (str == NULL)
    1164     {
    1165         str = newMsg;
    1166         newMsg [newMsgLen] = '\0';
    1167     }
    1168     else
    1169     {
    1170         /* append to the existing string */
    1171         size_t strLen = strlen (str);
    1172         char *newStr = (char *) RTMemRealloc (str, strLen + 2 + newMsgLen + 1);
    1173         AssertReturnVoid (newStr != NULL);
    1174 
    1175         memcpy (newStr + strLen, ".\n", 2);
    1176         memcpy (newStr + strLen + 2, newMsg, newMsgLen);
    1177         newStr [strLen + 2 + newMsgLen] = '\0';
    1178         str = newStr;
    1179         RTStrFree (newMsg);
     1301    /* anything left? */
     1302    if (newMsgLen > 0)
     1303    {
     1304        if (str == NULL)
     1305        {
     1306            str = newMsg;
     1307            newMsg [newMsgLen] = '\0';
     1308        }
     1309        else
     1310        {
     1311            /* append to the existing string */
     1312            size_t strLen = strlen (str);
     1313            char *newStr = (char *) RTMemRealloc (str, strLen + 2 + newMsgLen + 1);
     1314            AssertReturnVoid (newStr != NULL);
     1315
     1316            memcpy (newStr + strLen, ".\n", 2);
     1317            memcpy (newStr + strLen + 2, newMsg, newMsgLen);
     1318            newStr [strLen + 2 + newMsgLen] = '\0';
     1319            str = newStr;
     1320            RTStrFree (newMsg);
     1321        }
    11801322    }
    11811323}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette