/** * @copyright * ==================================================================== * Copyright (c) 2000-2006, 2008 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== * @endcopyright * * @file svn_xml.h * @brief XML code shared by various Subversion libraries. */ #ifndef SVN_XML_H #define SVN_XML_H #include #include #include #include "svn_types.h" #include "svn_string.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** The namespace all Subversion XML uses. */ #define SVN_XML_NAMESPACE "svn:" /** Used as style argument to svn_xml_make_open_tag() and friends. */ enum svn_xml_open_tag_style { /** */ svn_xml_normal = 1, /** , no cosmetic newline */ svn_xml_protect_pcdata, /** */ svn_xml_self_closing }; /** Determine if a string of character @a data of length @a len is a * safe bet for use with the svn_xml_escape_* functions found in this * header. * * Return @c TRUE if it is, @c FALSE otherwise. * * Essentially, this function exists to determine whether or not * simply running a string of bytes through the Subversion XML escape * routines will produce legitimate XML. It should only be necessary * for data which might contain bytes that cannot be safely encoded * into XML (certain control characters, for example). */ svn_boolean_t svn_xml_is_xml_safe(const char *data, apr_size_t len); /** Create or append in @a *outstr an xml-escaped version of @a string, * suitable for output as character data. * * If @a *outstr is @c NULL, set @a *outstr to a new stringbuf allocated * in @a pool, else append to the existing stringbuf there. */ void svn_xml_escape_cdata_stringbuf(svn_stringbuf_t **outstr, const svn_stringbuf_t *string, apr_pool_t *pool); /** Same as svn_xml_escape_cdata_stringbuf(), but @a string is an * @c svn_string_t. */ void svn_xml_escape_cdata_string(svn_stringbuf_t **outstr, const svn_string_t *string, apr_pool_t *pool); /** Same as svn_xml_escape_cdata_stringbuf(), but @a string is a * NULL-terminated C string. */ void svn_xml_escape_cdata_cstring(svn_stringbuf_t **outstr, const char *string, apr_pool_t *pool); /** Create or append in @a *outstr an xml-escaped version of @a string, * suitable for output as an attribute value. * * If @a *outstr is @c NULL, set @a *outstr to a new stringbuf allocated * in @a pool, else append to the existing stringbuf there. */ void svn_xml_escape_attr_stringbuf(svn_stringbuf_t **outstr, const svn_stringbuf_t *string, apr_pool_t *pool); /** Same as svn_xml_escape_attr_stringbuf(), but @a string is an * @c svn_string_t. */ void svn_xml_escape_attr_string(svn_stringbuf_t **outstr, const svn_string_t *string, apr_pool_t *pool); /** Same as svn_xml_escape_attr_stringbuf(), but @a string is a * NULL-terminated C string. */ void svn_xml_escape_attr_cstring(svn_stringbuf_t **outstr, const char *string, apr_pool_t *pool); /** * Return UTF-8 string @a string if it contains no characters that are * unrepresentable in XML. Else, return a copy of @a string, * allocated in @a pool, with each unrepresentable character replaced * by "?\uuu", where "uuu" is the three-digit unsigned decimal value * of that character. * * Neither the input nor the output need be valid XML; however, the * output can always be safely XML-escaped. * * @note The current implementation treats all Unicode characters as * representable, except for most ASCII control characters (the * exceptions being CR, LF, and TAB, which are valid in XML). There * may be other UTF-8 characters that are invalid in XML; see * http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=90591 * and its thread for details. * * @since New in 1.2. */ const char * svn_xml_fuzzy_escape(const char *string, apr_pool_t *pool); /*---------------------------------------------------------------*/ /* Generalized Subversion XML Parsing */ /** A generalized Subversion XML parser object */ typedef struct svn_xml_parser_t svn_xml_parser_t; typedef void (*svn_xml_start_elem)(void *baton, const char *name, const char **atts); typedef void (*svn_xml_end_elem)(void *baton, const char *name); /* data is not NULL-terminated. */ typedef void (*svn_xml_char_data)(void *baton, const char *data, apr_size_t len); /** Create a general Subversion XML parser */ svn_xml_parser_t * svn_xml_make_parser(void *baton, svn_xml_start_elem start_handler, svn_xml_end_elem end_handler, svn_xml_char_data data_handler, apr_pool_t *pool); /** Free a general Subversion XML parser */ void svn_xml_free_parser(svn_xml_parser_t *svn_parser); /** Push @a len bytes of xml data in @a buf at @a svn_parser. * * If this is the final push, @a is_final must be set. * * An error will be returned if there was a syntax problem in the XML, * or if any of the callbacks set an error using * svn_xml_signal_bailout(). * * If an error is returned, the @c svn_xml_parser_t will have been freed * automatically, so the caller should not call svn_xml_free_parser(). */ svn_error_t * svn_xml_parse(svn_xml_parser_t *svn_parser, const char *buf, apr_size_t len, svn_boolean_t is_final); /** The way to officially bail out of xml parsing. * * Store @a error in @a svn_parser and set all expat callbacks to @c NULL. */ void svn_xml_signal_bailout(svn_error_t *error, svn_xml_parser_t *svn_parser); /*** Helpers for dealing with the data Expat gives us. ***/ /** Return the value associated with @a name in expat attribute array @a atts, * else return @c NULL. * * (There could never be a @c NULL attribute value in the XML, * although the empty string is possible.) * * @a atts is an array of c-strings: even-numbered indexes are names, * odd-numbers hold values. If all is right, it should end on an * even-numbered index pointing to @c NULL. */ const char * svn_xml_get_attr_value(const char *name, const char **atts); /* Converting between Expat attribute lists and APR hash tables. */ /** Create an attribute hash from @c va_list @a ap. * * The contents of @a ap are alternating char * keys and * char * vals, terminated by a final @c NULL falling on an * even index (zero-based). */ apr_hash_t * svn_xml_ap_to_hash(va_list ap, apr_pool_t *pool); /** Create a hash that corresponds to Expat xml attribute list @a atts. * * The hash's keys and values are char *'s. * * @a atts may be NULL, in which case you just get an empty hash back * (this makes life more convenient for some callers). */ apr_hash_t * svn_xml_make_att_hash(const char **atts, apr_pool_t *pool); /** Like svn_xml_make_att_hash(), but takes a hash and preserves any * key/value pairs already in it. */ void svn_xml_hash_atts_preserving(const char **atts, apr_hash_t *ht, apr_pool_t *pool); /** Like svn_xml_make_att_hash(), but takes a hash and overwrites * key/value pairs already in it that also appear in @a atts. */ void svn_xml_hash_atts_overlaying(const char **atts, apr_hash_t *ht, apr_pool_t *pool); /* Printing XML */ /** Create an XML header and return it in @a *str. * * Fully-formed XML documents should start out with a header, * something like * \ * * This function returns such a header. @a *str must either be @c NULL, in * which case a new string is created, or it must point to an existing * string to be appended to. */ void svn_xml_make_header(svn_stringbuf_t **str, apr_pool_t *pool); /** Store a new xml tag @a tagname in @a *str. * * If @a *str is @c NULL, set @a *str to a new stringbuf allocated * in @a pool, else append to the existing stringbuf there. * * Take the tag's attributes from varargs, a NULL-terminated list of * alternating char * key and char * val. Do xml-escaping * on each val. * * @a style is one of the enumerated styles in @c svn_xml_open_tag_style. */ void svn_xml_make_open_tag(svn_stringbuf_t **str, apr_pool_t *pool, enum svn_xml_open_tag_style style, const char *tagname, ...); /** Like svn_xml_make_open_tag(), but takes a @c va_list instead of being * variadic. */ void svn_xml_make_open_tag_v(svn_stringbuf_t **str, apr_pool_t *pool, enum svn_xml_open_tag_style style, const char *tagname, va_list ap); /** Like svn_xml_make_open_tag(), but takes a hash table of attributes * (char * keys mapping to char * values). * * You might ask, why not just provide svn_xml_make_tag_atts()? * * The reason is that a hash table is the most natural interface to an * attribute list; the fact that Expat uses char ** atts instead is * certainly a defensible implementation decision, but since we'd have * to have special code to support such lists throughout Subversion * anyway, we might as well write that code for the natural interface * (hashes) and then convert in the few cases where conversion is * needed. Someday it might even be nice to change expat-lite to work * with apr hashes. * * See conversion functions svn_xml_make_att_hash() and * svn_xml_make_att_hash_overlaying(). Callers should use those to * convert Expat attr lists into hashes when necessary. */ void svn_xml_make_open_tag_hash(svn_stringbuf_t **str, apr_pool_t *pool, enum svn_xml_open_tag_style style, const char *tagname, apr_hash_t *attributes); /** Store an xml close tag @a tagname in @a str. * * If @a *str is @c NULL, set @a *str to a new stringbuf allocated * in @a pool, else append to the existing stringbuf there. */ void svn_xml_make_close_tag(svn_stringbuf_t **str, apr_pool_t *pool, const char *tagname); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* SVN_XML_H */