00001 /** 00002 * @copyright 00003 * ==================================================================== 00004 * Copyright (c) 2000-2006 CollabNet. All rights reserved. 00005 * 00006 * This software is licensed as described in the file COPYING, which 00007 * you should have received as part of this distribution. The terms 00008 * are also available at http://subversion.tigris.org/license-1.html. 00009 * If newer versions of this license are posted there, you may use a 00010 * newer version instead, at your option. 00011 * 00012 * This software consists of voluntary contributions made by many 00013 * individuals. For exact contribution history, see the revision 00014 * history and logs, available at http://subversion.tigris.org/. 00015 * ==================================================================== 00016 * @endcopyright 00017 * 00018 * @file svn_xml.h 00019 * @brief XML code shared by various Subversion libraries. 00020 */ 00021 00022 00023 00024 #ifndef SVN_XML_H 00025 #define SVN_XML_H 00026 00027 #include <apr.h> 00028 #include <apr_pools.h> 00029 #include <apr_hash.h> 00030 00031 #include "svn_error.h" 00032 #include "svn_string.h" 00033 00034 #ifdef __cplusplus 00035 extern "C" { 00036 #endif /* __cplusplus */ 00037 00038 /** The namespace all Subversion XML uses. */ 00039 #define SVN_XML_NAMESPACE "svn:" 00040 00041 /** Used as style argument to svn_xml_make_open_tag() and friends. */ 00042 enum svn_xml_open_tag_style { 00043 /** <tag ...> */ 00044 svn_xml_normal = 1, 00045 00046 /** <tag ...>, no cosmetic newline */ 00047 svn_xml_protect_pcdata, 00048 00049 /** <tag .../> */ 00050 svn_xml_self_closing 00051 }; 00052 00053 00054 00055 /** Determine if a string of character @a data of length @a len is a 00056 * safe bet for use with the svn_xml_escape_* functions found in this 00057 * header. 00058 * 00059 * Return @c TRUE if it is, @c FALSE otherwise. 00060 * 00061 * Essentially, this function exists to determine whether or not 00062 * simply running a string of bytes through the Subversion XML escape 00063 * routines will produce legitimate XML. It should only be necessary 00064 * for data which might contain bytes that cannot be safely encoded 00065 * into XML (certain control characters, for example). 00066 */ 00067 svn_boolean_t svn_xml_is_xml_safe(const char *data, 00068 apr_size_t len); 00069 00070 /** Create or append in @a *outstr an xml-escaped version of @a string, 00071 * suitable for output as character data. 00072 * 00073 * If @a *outstr is @c NULL, store a new stringbuf, else append to the 00074 * existing stringbuf there. 00075 */ 00076 void svn_xml_escape_cdata_stringbuf(svn_stringbuf_t **outstr, 00077 const svn_stringbuf_t *string, 00078 apr_pool_t *pool); 00079 00080 /** Same as svn_xml_escape_cdata_stringbuf(), but @a string is an 00081 * @c svn_string_t. 00082 */ 00083 void svn_xml_escape_cdata_string(svn_stringbuf_t **outstr, 00084 const svn_string_t *string, 00085 apr_pool_t *pool); 00086 00087 /** Same as svn_xml_escape_cdata_stringbuf(), but @a string is a 00088 * null-terminated C string. 00089 */ 00090 void svn_xml_escape_cdata_cstring(svn_stringbuf_t **outstr, 00091 const char *string, 00092 apr_pool_t *pool); 00093 00094 00095 /** Create or append in @a *outstr an xml-escaped version of @a string, 00096 * suitable for output as an attribute value. 00097 * 00098 * If @a *outstr is @c NULL, store a new stringbuf, else append to the 00099 * existing stringbuf there. 00100 */ 00101 void svn_xml_escape_attr_stringbuf(svn_stringbuf_t **outstr, 00102 const svn_stringbuf_t *string, 00103 apr_pool_t *pool); 00104 00105 /** Same as svn_xml_escape_attr_stringbuf(), but @a string is an 00106 * @c svn_string_t. 00107 */ 00108 void svn_xml_escape_attr_string(svn_stringbuf_t **outstr, 00109 const svn_string_t *string, 00110 apr_pool_t *pool); 00111 00112 /** Same as svn_xml_escape_attr_stringbuf(), but @a string is a 00113 * null-terminated C string. 00114 */ 00115 void svn_xml_escape_attr_cstring(svn_stringbuf_t **outstr, 00116 const char *string, 00117 apr_pool_t *pool); 00118 00119 /** 00120 * Return UTF-8 string @a string if it contains no characters that are 00121 * unrepresentable in XML. Else, return a copy of @a string, 00122 * allocated in @a pool, with each unrepresentable character replaced 00123 * by "?\uuu", where "uuu" is the three-digit unsigned decimal value 00124 * of that character. 00125 * 00126 * Neither the input nor the output need be valid XML; however, the 00127 * output can always be safely XML-escaped. 00128 * 00129 * @note The current implementation treats all Unicode characters as 00130 * representable, except for most ASCII control characters (the 00131 * exceptions being CR, LF, and TAB, which are valid in XML). There 00132 * may be other UTF-8 characters that are invalid in XML; see 00133 * http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=90591 00134 * and its thread for details. 00135 * 00136 * @since New in 1.2. 00137 */ 00138 const char *svn_xml_fuzzy_escape(const char *string, 00139 apr_pool_t *pool); 00140 00141 00142 /*---------------------------------------------------------------*/ 00143 00144 /* Generalized Subversion XML Parsing */ 00145 00146 /** A generalized Subversion XML parser object */ 00147 typedef struct svn_xml_parser_t svn_xml_parser_t; 00148 00149 typedef void (*svn_xml_start_elem)(void *baton, 00150 const char *name, 00151 const char **atts); 00152 00153 typedef void (*svn_xml_end_elem)(void *baton, const char *name); 00154 00155 /* data is not NULL-terminated. */ 00156 typedef void (*svn_xml_char_data)(void *baton, 00157 const char *data, 00158 apr_size_t len); 00159 00160 00161 /** Create a general Subversion XML parser */ 00162 svn_xml_parser_t *svn_xml_make_parser(void *baton, 00163 svn_xml_start_elem start_handler, 00164 svn_xml_end_elem end_handler, 00165 svn_xml_char_data data_handler, 00166 apr_pool_t *pool); 00167 00168 00169 /** Free a general Subversion XML parser */ 00170 void svn_xml_free_parser(svn_xml_parser_t *svn_parser); 00171 00172 00173 /** Push @a len bytes of xml data in @a buf at @a svn_parser. 00174 * 00175 * If this is the final push, @a is_final must be set. 00176 * 00177 * An error will be returned if there was a syntax problem in the XML, 00178 * or if any of the callbacks set an error using 00179 * svn_xml_signal_bailout(). 00180 * 00181 * If an error is returned, the @c svn_xml_parser_t will have been freed 00182 * automatically, so the caller should not call svn_xml_free_parser(). 00183 */ 00184 svn_error_t *svn_xml_parse(svn_xml_parser_t *parser, 00185 const char *buf, 00186 apr_size_t len, 00187 svn_boolean_t is_final); 00188 00189 00190 00191 /** The way to officially bail out of xml parsing. 00192 * 00193 * Store @a error in @a svn_parser and set all expat callbacks to @c NULL. 00194 */ 00195 void svn_xml_signal_bailout(svn_error_t *error, 00196 svn_xml_parser_t *svn_parser); 00197 00198 00199 00200 00201 00202 /*** Helpers for dealing with the data Expat gives us. ***/ 00203 00204 /** Return the value associated with @a name in expat attribute array @a atts, 00205 * else return @c NULL. 00206 * 00207 * (There could never be a @c NULL attribute value in the XML, 00208 * although the empty string is possible.) 00209 * 00210 * @a atts is an array of c-strings: even-numbered indexes are names, 00211 * odd-numbers hold values. If all is right, it should end on an 00212 * even-numbered index pointing to @c NULL. 00213 */ 00214 const char *svn_xml_get_attr_value(const char *name, const char **atts); 00215 00216 00217 00218 /* Converting between Expat attribute lists and APR hash tables. */ 00219 00220 00221 /** Create an attribute hash from @c va_list @a ap. 00222 * 00223 * The contents of @a ap are alternating <tt>char *</tt> keys and 00224 * <tt>char *</tt> vals, terminated by a final @c NULL falling on an 00225 * even index (zero-based). 00226 */ 00227 apr_hash_t *svn_xml_ap_to_hash(va_list ap, apr_pool_t *pool); 00228 00229 /** Create a hash that corresponds to Expat xml attribute list @a atts. 00230 * 00231 * The hash's keys and values are <tt>char *</tt>'s. 00232 * 00233 * @a atts may be null, in which case you just get an empty hash back 00234 * (this makes life more convenient for some callers). 00235 */ 00236 apr_hash_t *svn_xml_make_att_hash(const char **atts, apr_pool_t *pool); 00237 00238 00239 /** Like svn_xml_make_att_hash(), but takes a hash and preserves any 00240 * key/value pairs already in it. 00241 */ 00242 void svn_xml_hash_atts_preserving(const char **atts, 00243 apr_hash_t *ht, 00244 apr_pool_t *pool); 00245 00246 /** Like svn_xml_make_att_hash(), but takes a hash and overwrites 00247 * key/value pairs already in it that also appear in @a atts. 00248 */ 00249 void svn_xml_hash_atts_overlaying(const char **atts, 00250 apr_hash_t *ht, 00251 apr_pool_t *pool); 00252 00253 00254 00255 /* Printing XML */ 00256 00257 /** Create an XML header and return it in @a *str. 00258 * 00259 * Fully-formed XML documents should start out with a header, 00260 * something like 00261 * <?xml version="1.0" encoding="utf-8"?> 00262 * 00263 * This function returns such a header. @a *str must either be @c NULL, in 00264 * which case a new string is created, or it must point to an existing 00265 * string to be appended to. 00266 */ 00267 void svn_xml_make_header(svn_stringbuf_t **str, apr_pool_t *pool); 00268 00269 00270 /** Store a new xml tag @a tagname in @a *str. 00271 * 00272 * If @a str is @c NULL, allocate @a *str in @a pool; else append the new 00273 * tag to @a *str, allocating in @a str's pool 00274 * 00275 * Take the tag's attributes from varargs, a null-terminated list of 00276 * alternating <tt>char *</tt> key and <tt>char *</tt> val. Do xml-escaping 00277 * on each val. 00278 * 00279 * @a style is one of the enumerated styles in @c svn_xml_open_tag_style. 00280 */ 00281 void svn_xml_make_open_tag(svn_stringbuf_t **str, 00282 apr_pool_t *pool, 00283 enum svn_xml_open_tag_style style, 00284 const char *tagname, 00285 ...); 00286 00287 00288 /** Like svn_xml_make_open_tag(), but takes a @c va_list instead of being 00289 * variadic. 00290 */ 00291 void svn_xml_make_open_tag_v(svn_stringbuf_t **str, 00292 apr_pool_t *pool, 00293 enum svn_xml_open_tag_style style, 00294 const char *tagname, 00295 va_list ap); 00296 00297 00298 /** Like svn_xml_make_open_tag(), but takes a hash table of attributes 00299 * (<tt>char *</tt> keys mapping to <tt>char *</tt> values). 00300 * 00301 * You might ask, why not just provide svn_xml_make_tag_atts()? 00302 * 00303 * The reason is that a hash table is the most natural interface to an 00304 * attribute list; the fact that Expat uses <tt>char **</tt> atts instead is 00305 * certainly a defensible implementation decision, but since we'd have 00306 * to have special code to support such lists throughout Subversion 00307 * anyway, we might as well write that code for the natural interface 00308 * (hashes) and then convert in the few cases where conversion is 00309 * needed. Someday it might even be nice to change expat-lite to work 00310 * with apr hashes. 00311 * 00312 * See conversion functions svn_xml_make_att_hash() and 00313 * svn_xml_make_att_hash_overlaying(). Callers should use those to 00314 * convert Expat attr lists into hashes when necessary. 00315 */ 00316 void svn_xml_make_open_tag_hash(svn_stringbuf_t **str, 00317 apr_pool_t *pool, 00318 enum svn_xml_open_tag_style style, 00319 const char *tagname, 00320 apr_hash_t *attributes); 00321 00322 00323 /** Makes a close tag. */ 00324 void svn_xml_make_close_tag(svn_stringbuf_t **str, 00325 apr_pool_t *pool, 00326 const char *tagname); 00327 00328 00329 00330 #ifdef __cplusplus 00331 } 00332 #endif /* __cplusplus */ 00333 00334 #endif /* SVN_XML_H */