mxml-file.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: mxml-file.c 329 2008-01-13 00:42:35Z mike $"
00003  *
00004  * File loading code for Mini-XML, a small XML-like file parsing library.
00005  *
00006  * Copyright 2003-2008 by Michael Sweet.
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Library General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * Contents:
00019  *
00020  *   mxmlLoadFd()            - Load a file descriptor into an XML node tree.
00021  *   mxmlLoadFile()          - Load a file into an XML node tree.
00022  *   mxmlLoadString()        - Load a string into an XML node tree.
00023  *   mxmlSaveAllocString()   - Save an XML node tree to an allocated string.
00024  *   mxmlSaveFd()            - Save an XML tree to a file descriptor.
00025  *   mxmlSaveFile()          - Save an XML tree to a file.
00026  *   mxmlSaveString()        - Save an XML node tree to a string.
00027  *   mxmlSAXLoadFd()         - Load a file descriptor into an XML node tree
00028  *                             using a SAX callback.
00029  *   mxmlSAXLoadFile()       - Load a file into an XML node tree
00030  *                             using a SAX callback.
00031  *   mxmlSAXLoadString()     - Load a string into an XML node tree
00032  *                             using a SAX callback.
00033  *   mxmlSetCustomHandlers() - Set the handling functions for custom data.
00034  *   mxmlSetErrorCallback()  - Set the error message callback.
00035  *   mxmlSetWrapMargin()     - Set the the wrap margin when saving XML data.
00036  *   mxml_add_char()         - Add a character to a buffer, expanding as needed.
00037  *   mxml_fd_getc()          - Read a character from a file descriptor.
00038  *   mxml_fd_putc()          - Write a character to a file descriptor.
00039  *   mxml_fd_read()          - Read a buffer of data from a file descriptor.
00040  *   mxml_fd_write()         - Write a buffer of data to a file descriptor.
00041  *   mxml_file_getc()        - Get a character from a file.
00042  *   mxml_file_putc()        - Write a character to a file.
00043  *   mxml_get_entity()       - Get the character corresponding to an entity...
00044  *   mxml_load_data()        - Load data into an XML node tree.
00045  *   mxml_parse_element()    - Parse an element for any attributes...
00046  *   mxml_string_getc()      - Get a character from a string.
00047  *   mxml_string_putc()      - Write a character to a string.
00048  *   mxml_write_name()       - Write a name string.
00049  *   mxml_write_node()       - Save an XML node to a file.
00050  *   mxml_write_string()     - Write a string, escaping & and < as needed.
00051  *   mxml_write_ws()         - Do whitespace callback...
00052  */
00053 
00054 /*
00055  * Include necessary headers...
00056  */
00057 
00058 #include "mxml-private.h"
00059 #ifdef WIN32
00060 #  include <io.h>
00061 #else
00062 #  include <unistd.h>
00063 #endif /* WIN32 */
00064 
00065 
00066 /*
00067  * Character encoding...
00068  */
00069 
00070 #define ENCODE_UTF8 0       /* UTF-8 */
00071 #define ENCODE_UTF16BE  1       /* UTF-16 Big-Endian */
00072 #define ENCODE_UTF16LE  2       /* UTF-16 Little-Endian */
00073 
00074 
00075 /*
00076  * Macro to test for a bad XML character...
00077  */
00078 
00079 #define mxml_bad_char(ch) ((ch) < ' ' && (ch) != '\n' && (ch) != '\r' && (ch) != '\t')
00080 
00081 
00082 /*
00083  * Types and structures...
00084  */
00085 
00086 typedef int (*_mxml_getc_cb_t)(void *, int *);
00087 typedef int (*_mxml_putc_cb_t)(int, void *);
00088 
00089 typedef struct _mxml_fdbuf_s        /**** File descriptor buffer ****/
00090 {
00091   int       fd;         /* File descriptor */
00092   unsigned char *current,       /* Current position in buffer */
00093         *end,           /* End of buffer */
00094         buffer[8192];       /* Character buffer */
00095 } _mxml_fdbuf_t;
00096 
00097 
00098 /*
00099  * Local functions...
00100  */
00101 
00102 static int      mxml_add_char(int ch, char **ptr, char **buffer,
00103                           int *bufsize);
00104 static int      mxml_fd_getc(void *p, int *encoding);
00105 static int      mxml_fd_putc(int ch, void *p);
00106 static int      mxml_fd_read(_mxml_fdbuf_t *buf);
00107 static int      mxml_fd_write(_mxml_fdbuf_t *buf);
00108 static int      mxml_file_getc(void *p, int *encoding);
00109 static int      mxml_file_putc(int ch, void *p);
00110 static int      mxml_get_entity(mxml_node_t *parent, void *p,
00111                             int *encoding,
00112                     _mxml_getc_cb_t getc_cb);
00113 static inline int   mxml_isspace(int ch)
00114             {
00115               return (ch == ' ' || ch == '\t' || ch == '\r' ||
00116                       ch == '\n');
00117             }
00118 static mxml_node_t  *mxml_load_data(mxml_node_t *top, void *p,
00119                             mxml_load_cb_t cb,
00120                             _mxml_getc_cb_t getc_cb,
00121                                         mxml_sax_cb_t sax_cb, void *sax_data);
00122 static int      mxml_parse_element(mxml_node_t *node, void *p,
00123                                int *encoding,
00124                        _mxml_getc_cb_t getc_cb);
00125 static int      mxml_string_getc(void *p, int *encoding);
00126 static int      mxml_string_putc(int ch, void *p);
00127 static int      mxml_write_name(const char *s, void *p,
00128                     _mxml_putc_cb_t putc_cb);
00129 static int      mxml_write_node(mxml_node_t *node, void *p,
00130                             mxml_save_cb_t cb, int col,
00131                     _mxml_putc_cb_t putc_cb,
00132                     _mxml_global_t *global);
00133 static int      mxml_write_string(const char *s, void *p,
00134                       _mxml_putc_cb_t putc_cb);
00135 static int      mxml_write_ws(mxml_node_t *node, void *p,
00136                           mxml_save_cb_t cb, int ws,
00137                       int col, _mxml_putc_cb_t putc_cb);
00138 
00139 
00140 /*
00141  * 'mxmlLoadFd()' - Load a file descriptor into an XML node tree.
00142  *
00143  * The nodes in the specified file are added to the specified top node.
00144  * If no top node is provided, the XML file MUST be well-formed with a
00145  * single parent node like <?xml> for the entire file. The callback
00146  * function returns the value type that should be used for child nodes.
00147  * If MXML_NO_CALLBACK is specified then all child nodes will be either
00148  * MXML_ELEMENT or MXML_TEXT nodes.
00149  *
00150  * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
00151  * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
00152  * child nodes of the specified type.
00153  */
00154 
00155 mxml_node_t *               /* O - First node or NULL if the file could not be read. */
00156 mxmlLoadFd(mxml_node_t    *top,     /* I - Top node */
00157            int            fd,       /* I - File descriptor to read from */
00158            mxml_load_cb_t cb)       /* I - Callback function or MXML_NO_CALLBACK */
00159 {
00160   _mxml_fdbuf_t buf;            /* File descriptor buffer */
00161 
00162 
00163  /*
00164   * Initialize the file descriptor buffer...
00165   */
00166 
00167   buf.fd      = fd;
00168   buf.current = buf.buffer;
00169   buf.end     = buf.buffer;
00170 
00171  /*
00172   * Read the XML data...
00173   */
00174 
00175   return (mxml_load_data(top, &buf, cb, mxml_fd_getc, MXML_NO_CALLBACK, NULL));
00176 }
00177 
00178 
00179 /*
00180  * 'mxmlLoadFile()' - Load a file into an XML node tree.
00181  *
00182  * The nodes in the specified file are added to the specified top node.
00183  * If no top node is provided, the XML file MUST be well-formed with a
00184  * single parent node like <?xml> for the entire file. The callback
00185  * function returns the value type that should be used for child nodes.
00186  * If MXML_NO_CALLBACK is specified then all child nodes will be either
00187  * MXML_ELEMENT or MXML_TEXT nodes.
00188  *
00189  * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
00190  * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
00191  * child nodes of the specified type.
00192  */
00193 
00194 mxml_node_t *               /* O - First node or NULL if the file could not be read. */
00195 mxmlLoadFile(mxml_node_t    *top,   /* I - Top node */
00196              FILE           *fp,    /* I - File to read from */
00197              mxml_load_cb_t cb)     /* I - Callback function or MXML_NO_CALLBACK */
00198 {
00199  /*
00200   * Read the XML data...
00201   */
00202 
00203   return (mxml_load_data(top, fp, cb, mxml_file_getc, MXML_NO_CALLBACK, NULL));
00204 }
00205 
00206 
00207 /*
00208  * 'mxmlLoadString()' - Load a string into an XML node tree.
00209  *
00210  * The nodes in the specified string are added to the specified top node.
00211  * If no top node is provided, the XML string MUST be well-formed with a
00212  * single parent node like <?xml> for the entire string. The callback
00213  * function returns the value type that should be used for child nodes.
00214  * If MXML_NO_CALLBACK is specified then all child nodes will be either
00215  * MXML_ELEMENT or MXML_TEXT nodes.
00216  *
00217  * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
00218  * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
00219  * child nodes of the specified type.
00220  */
00221 
00222 mxml_node_t *               /* O - First node or NULL if the string has errors. */
00223 mxmlLoadString(mxml_node_t    *top, /* I - Top node */
00224                const char     *s,   /* I - String to load */
00225                mxml_load_cb_t cb)   /* I - Callback function or MXML_NO_CALLBACK */
00226 {
00227  /*
00228   * Read the XML data...
00229   */
00230 
00231   return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, MXML_NO_CALLBACK,
00232                          NULL));
00233 }
00234 
00235 
00236 /*
00237  * 'mxmlSaveAllocString()' - Save an XML node tree to an allocated string.
00238  *
00239  * This function returns a pointer to a string containing the textual
00240  * representation of the XML node tree.  The string should be freed
00241  * using the free() function when you are done with it.  NULL is returned
00242  * if the node would produce an empty string or if the string cannot be
00243  * allocated.
00244  *
00245  * The callback argument specifies a function that returns a whitespace
00246  * string or NULL before and after each element. If MXML_NO_CALLBACK
00247  * is specified, whitespace will only be added before MXML_TEXT nodes
00248  * with leading whitespace and before attribute names inside opening
00249  * element tags.
00250  */
00251 
00252 char *                  /* O - Allocated string or NULL */
00253 mxmlSaveAllocString(
00254     mxml_node_t    *node,       /* I - Node to write */
00255     mxml_save_cb_t cb)          /* I - Whitespace callback or MXML_NO_CALLBACK */
00256 {
00257   int   bytes;              /* Required bytes */
00258   char  buffer[8192];           /* Temporary buffer */
00259   char  *s;             /* Allocated string */
00260 
00261 
00262  /*
00263   * Write the node to the temporary buffer...
00264   */
00265 
00266   bytes = mxmlSaveString(node, buffer, sizeof(buffer), cb);
00267 
00268   if (bytes <= 0)
00269     return (NULL);
00270 
00271   if (bytes < (int)(sizeof(buffer) - 1))
00272   {
00273    /*
00274     * Node fit inside the buffer, so just duplicate that string and
00275     * return...
00276     */
00277 
00278     return (strdup(buffer));
00279   }
00280 
00281  /*
00282   * Allocate a buffer of the required size and save the node to the
00283   * new buffer...
00284   */
00285 
00286   if ((s = malloc(bytes + 1)) == NULL)
00287     return (NULL);
00288 
00289   mxmlSaveString(node, s, bytes + 1, cb);
00290 
00291  /*
00292   * Return the allocated string...
00293   */
00294 
00295   return (s);
00296 }
00297 
00298 
00299 /*
00300  * 'mxmlSaveFd()' - Save an XML tree to a file descriptor.
00301  *
00302  * The callback argument specifies a function that returns a whitespace
00303  * string or NULL before and after each element. If MXML_NO_CALLBACK
00304  * is specified, whitespace will only be added before MXML_TEXT nodes
00305  * with leading whitespace and before attribute names inside opening
00306  * element tags.
00307  */
00308 
00309 int                 /* O - 0 on success, -1 on error. */
00310 mxmlSaveFd(mxml_node_t    *node,    /* I - Node to write */
00311            int            fd,       /* I - File descriptor to write to */
00312        mxml_save_cb_t cb)       /* I - Whitespace callback or MXML_NO_CALLBACK */
00313 {
00314   int       col;            /* Final column */
00315   _mxml_fdbuf_t buf;            /* File descriptor buffer */
00316   _mxml_global_t *global = _mxml_global();
00317                     /* Global data */
00318 
00319 
00320  /*
00321   * Initialize the file descriptor buffer...
00322   */
00323 
00324   buf.fd      = fd;
00325   buf.current = buf.buffer;
00326   buf.end     = buf.buffer + sizeof(buf.buffer) - 4;
00327 
00328  /*
00329   * Write the node...
00330   */
00331 
00332   if ((col = mxml_write_node(node, &buf, cb, 0, mxml_fd_putc, global)) < 0)
00333     return (-1);
00334 
00335   if (col > 0)
00336     if (mxml_fd_putc('\n', &buf) < 0)
00337       return (-1);
00338 
00339  /*
00340   * Flush and return...
00341   */
00342 
00343   return (mxml_fd_write(&buf));
00344 }
00345 
00346 
00347 /*
00348  * 'mxmlSaveFile()' - Save an XML tree to a file.
00349  *
00350  * The callback argument specifies a function that returns a whitespace
00351  * string or NULL before and after each element. If MXML_NO_CALLBACK
00352  * is specified, whitespace will only be added before MXML_TEXT nodes
00353  * with leading whitespace and before attribute names inside opening
00354  * element tags.
00355  */
00356 
00357 int                 /* O - 0 on success, -1 on error. */
00358 mxmlSaveFile(mxml_node_t    *node,  /* I - Node to write */
00359              FILE           *fp,    /* I - File to write to */
00360          mxml_save_cb_t cb)     /* I - Whitespace callback or MXML_NO_CALLBACK */
00361 {
00362   int   col;                /* Final column */
00363   _mxml_global_t *global = _mxml_global();
00364                     /* Global data */
00365 
00366 
00367  /*
00368   * Write the node...
00369   */
00370 
00371   if ((col = mxml_write_node(node, fp, cb, 0, mxml_file_putc, global)) < 0)
00372     return (-1);
00373 
00374   if (col > 0)
00375     if (putc('\n', fp) < 0)
00376       return (-1);
00377 
00378  /*
00379   * Return 0 (success)...
00380   */
00381 
00382   return (0);
00383 }
00384 
00385 
00386 /*
00387  * 'mxmlSaveString()' - Save an XML node tree to a string.
00388  *
00389  * This function returns the total number of bytes that would be
00390  * required for the string but only copies (bufsize - 1) characters
00391  * into the specified buffer.
00392  *
00393  * The callback argument specifies a function that returns a whitespace
00394  * string or NULL before and after each element. If MXML_NO_CALLBACK
00395  * is specified, whitespace will only be added before MXML_TEXT nodes
00396  * with leading whitespace and before attribute names inside opening
00397  * element tags.
00398  */
00399 
00400 int                 /* O - Size of string */
00401 mxmlSaveString(mxml_node_t    *node,    /* I - Node to write */
00402                char           *buffer,  /* I - String buffer */
00403                int            bufsize,  /* I - Size of string buffer */
00404                mxml_save_cb_t cb)   /* I - Whitespace callback or MXML_NO_CALLBACK */
00405 {
00406   int   col;                /* Final column */
00407   char  *ptr[2];            /* Pointers for putc_cb */
00408   _mxml_global_t *global = _mxml_global();
00409                     /* Global data */
00410 
00411 
00412  /*
00413   * Write the node...
00414   */
00415 
00416   ptr[0] = buffer;
00417   ptr[1] = buffer + bufsize;
00418 
00419   if ((col = mxml_write_node(node, ptr, cb, 0, mxml_string_putc, global)) < 0)
00420     return (-1);
00421 
00422   if (col > 0)
00423     mxml_string_putc('\n', ptr);
00424 
00425  /*
00426   * Nul-terminate the buffer...
00427   */
00428 
00429   if (ptr[0] >= ptr[1])
00430     buffer[bufsize - 1] = '\0';
00431   else
00432     ptr[0][0] = '\0';
00433 
00434  /*
00435   * Return the number of characters...
00436   */
00437 
00438   return (ptr[0] - buffer);
00439 }
00440 
00441 
00442 /*
00443  * 'mxmlSAXLoadFd()' - Load a file descriptor into an XML node tree
00444  *                     using a SAX callback.
00445  *
00446  * The nodes in the specified file are added to the specified top node.
00447  * If no top node is provided, the XML file MUST be well-formed with a
00448  * single parent node like <?xml> for the entire file. The callback
00449  * function returns the value type that should be used for child nodes.
00450  * If MXML_NO_CALLBACK is specified then all child nodes will be either
00451  * MXML_ELEMENT or MXML_TEXT nodes.
00452  *
00453  * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
00454  * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
00455  * child nodes of the specified type.
00456  *
00457  * The SAX callback must call mxmlRetain() for any nodes that need to
00458  * be kept for later use. Otherwise, nodes are deleted when the parent
00459  * node is closed or after each data, comment, CDATA, or directive node.
00460  *
00461  * @since Mini-XML 2.3@
00462  */
00463 
00464 mxml_node_t *               /* O - First node or NULL if the file could not be read. */
00465 mxmlSAXLoadFd(mxml_node_t    *top,  /* I - Top node */
00466               int            fd,    /* I - File descriptor to read from */
00467               mxml_load_cb_t cb,    /* I - Callback function or MXML_NO_CALLBACK */
00468               mxml_sax_cb_t  sax_cb,    /* I - SAX callback or MXML_NO_CALLBACK */
00469               void           *sax_data) /* I - SAX user data */
00470 {
00471   _mxml_fdbuf_t buf;            /* File descriptor buffer */
00472 
00473 
00474  /*
00475   * Initialize the file descriptor buffer...
00476   */
00477 
00478   buf.fd      = fd;
00479   buf.current = buf.buffer;
00480   buf.end     = buf.buffer;
00481 
00482  /*
00483   * Read the XML data...
00484   */
00485 
00486   return (mxml_load_data(top, &buf, cb, mxml_fd_getc, sax_cb, sax_data));
00487 }
00488 
00489 
00490 /*
00491  * 'mxmlSAXLoadFile()' - Load a file into an XML node tree
00492  *                       using a SAX callback.
00493  *
00494  * The nodes in the specified file are added to the specified top node.
00495  * If no top node is provided, the XML file MUST be well-formed with a
00496  * single parent node like <?xml> for the entire file. The callback
00497  * function returns the value type that should be used for child nodes.
00498  * If MXML_NO_CALLBACK is specified then all child nodes will be either
00499  * MXML_ELEMENT or MXML_TEXT nodes.
00500  *
00501  * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
00502  * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
00503  * child nodes of the specified type.
00504  *
00505  * The SAX callback must call mxmlRetain() for any nodes that need to
00506  * be kept for later use. Otherwise, nodes are deleted when the parent
00507  * node is closed or after each data, comment, CDATA, or directive node.
00508  *
00509  * @since Mini-XML 2.3@
00510  */
00511 
00512 mxml_node_t *               /* O - First node or NULL if the file could not be read. */
00513 mxmlSAXLoadFile(
00514     mxml_node_t    *top,        /* I - Top node */
00515     FILE           *fp,         /* I - File to read from */
00516     mxml_load_cb_t cb,          /* I - Callback function or MXML_NO_CALLBACK */
00517     mxml_sax_cb_t  sax_cb,      /* I - SAX callback or MXML_NO_CALLBACK */
00518     void           *sax_data)       /* I - SAX user data */
00519 {
00520  /*
00521   * Read the XML data...
00522   */
00523 
00524   return (mxml_load_data(top, fp, cb, mxml_file_getc, sax_cb, sax_data));
00525 }
00526 
00527 
00528 /*
00529  * 'mxmlSAXLoadString()' - Load a string into an XML node tree
00530  *                         using a SAX callback.
00531  *
00532  * The nodes in the specified string are added to the specified top node.
00533  * If no top node is provided, the XML string MUST be well-formed with a
00534  * single parent node like <?xml> for the entire string. The callback
00535  * function returns the value type that should be used for child nodes.
00536  * If MXML_NO_CALLBACK is specified then all child nodes will be either
00537  * MXML_ELEMENT or MXML_TEXT nodes.
00538  *
00539  * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK,
00540  * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading
00541  * child nodes of the specified type.
00542  *
00543  * The SAX callback must call mxmlRetain() for any nodes that need to
00544  * be kept for later use. Otherwise, nodes are deleted when the parent
00545  * node is closed or after each data, comment, CDATA, or directive node.
00546  *
00547  * @since Mini-XML 2.3@
00548  */
00549 
00550 mxml_node_t *               /* O - First node or NULL if the string has errors. */
00551 mxmlSAXLoadString(
00552     mxml_node_t    *top,        /* I - Top node */
00553     const char     *s,          /* I - String to load */
00554     mxml_load_cb_t cb,          /* I - Callback function or MXML_NO_CALLBACK */
00555     mxml_sax_cb_t  sax_cb,      /* I - SAX callback or MXML_NO_CALLBACK */
00556     void           *sax_data)       /* I - SAX user data */
00557 {
00558  /*
00559   * Read the XML data...
00560   */
00561 
00562   return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, sax_cb, sax_data));
00563 }
00564 
00565 
00566 /*
00567  * 'mxmlSetCustomHandlers()' - Set the handling functions for custom data.
00568  *
00569  * The load function accepts a node pointer and a data string and must
00570  * return 0 on success and non-zero on error.
00571  *
00572  * The save function accepts a node pointer and must return a malloc'd
00573  * string on success and NULL on error.
00574  *
00575  */
00576 
00577 void
00578 mxmlSetCustomHandlers(
00579     mxml_custom_load_cb_t load,     /* I - Load function */
00580     mxml_custom_save_cb_t save)     /* I - Save function */
00581 {
00582   _mxml_global_t *global = _mxml_global();
00583                     /* Global data */
00584 
00585 
00586   global->custom_load_cb = load;
00587   global->custom_save_cb = save;
00588 }
00589 
00590 
00591 /*
00592  * 'mxmlSetErrorCallback()' - Set the error message callback.
00593  */
00594 
00595 void
00596 mxmlSetErrorCallback(mxml_error_cb_t cb)/* I - Error callback function */
00597 {
00598   _mxml_global_t *global = _mxml_global();
00599                     /* Global data */
00600 
00601 
00602   global->error_cb = cb;
00603 }
00604 
00605 
00606 /*
00607  * 'mxmlSetWrapMargin()' - Set the the wrap margin when saving XML data.
00608  *
00609  * Wrapping is disabled when "column" is <= 0.
00610  *
00611  * @since Mini-XML 2.3@
00612  */
00613 
00614 void
00615 mxmlSetWrapMargin(int column)       /* I - Column for wrapping */
00616 {
00617   _mxml_global_t *global = _mxml_global();
00618                     /* Global data */
00619 
00620 
00621   if (column <= 0)
00622     global->wrap = 2147483647;
00623   else
00624     global->wrap = column;
00625 }
00626 
00627 
00628 /*
00629  * 'mxml_add_char()' - Add a character to a buffer, expanding as needed.
00630  */
00631 
00632 static int              /* O  - 0 on success, -1 on error */
00633 mxml_add_char(int  ch,          /* I  - Character to add */
00634               char **bufptr,        /* IO - Current position in buffer */
00635           char **buffer,        /* IO - Current buffer */
00636           int  *bufsize)        /* IO - Current buffer size */
00637 {
00638   char  *newbuffer;         /* New buffer value */
00639 
00640 
00641   if (*bufptr >= (*buffer + *bufsize - 4))
00642   {
00643    /*
00644     * Increase the size of the buffer...
00645     */
00646 
00647     if (*bufsize < 1024)
00648       (*bufsize) *= 2;
00649     else
00650       (*bufsize) += 1024;
00651 
00652     if ((newbuffer = realloc(*buffer, *bufsize)) == NULL)
00653     {
00654       free(*buffer);
00655 
00656       mxml_error("Unable to expand string buffer to %d bytes!", *bufsize);
00657 
00658       return (-1);
00659     }
00660 
00661     *bufptr = newbuffer + (*bufptr - *buffer);
00662     *buffer = newbuffer;
00663   }
00664 
00665   if (ch < 0x80)
00666   {
00667    /*
00668     * Single byte ASCII...
00669     */
00670 
00671     *(*bufptr)++ = ch;
00672   }
00673   else if (ch < 0x800)
00674   {
00675    /*
00676     * Two-byte UTF-8...
00677     */
00678 
00679     *(*bufptr)++ = 0xc0 | (ch >> 6);
00680     *(*bufptr)++ = 0x80 | (ch & 0x3f);
00681   }
00682   else if (ch < 0x10000)
00683   {
00684    /*
00685     * Three-byte UTF-8...
00686     */
00687 
00688     *(*bufptr)++ = 0xe0 | (ch >> 12);
00689     *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
00690     *(*bufptr)++ = 0x80 | (ch & 0x3f);
00691   }
00692   else
00693   {
00694    /*
00695     * Four-byte UTF-8...
00696     */
00697 
00698     *(*bufptr)++ = 0xf0 | (ch >> 18);
00699     *(*bufptr)++ = 0x80 | ((ch >> 12) & 0x3f);
00700     *(*bufptr)++ = 0x80 | ((ch >> 6) & 0x3f);
00701     *(*bufptr)++ = 0x80 | (ch & 0x3f);
00702   }
00703 
00704   return (0);
00705 }
00706 
00707 
00708 /*
00709  * 'mxml_fd_getc()' - Read a character from a file descriptor.
00710  */
00711 
00712 static int              /* O  - Character or EOF */
00713 mxml_fd_getc(void *p,           /* I  - File descriptor buffer */
00714              int  *encoding)        /* IO - Encoding */
00715 {
00716   _mxml_fdbuf_t *buf;           /* File descriptor buffer */
00717   int       ch,         /* Current character */
00718         temp;           /* Temporary character */
00719 
00720 
00721  /*
00722   * Grab the next character in the buffer...
00723   */
00724 
00725   buf = (_mxml_fdbuf_t *)p;
00726 
00727   if (buf->current >= buf->end)
00728     if (mxml_fd_read(buf) < 0)
00729       return (EOF);
00730 
00731   ch = *(buf->current)++;
00732 
00733   switch (*encoding)
00734   {
00735     case ENCODE_UTF8 :
00736        /*
00737     * Got a UTF-8 character; convert UTF-8 to Unicode and return...
00738     */
00739 
00740     if (!(ch & 0x80))
00741     {
00742 #if DEBUG > 1
00743           printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
00744 #endif /* DEBUG > 1 */
00745 
00746       if (mxml_bad_char(ch))
00747       {
00748         mxml_error("Bad control character 0x%02x not allowed by XML standard!",
00749                    ch);
00750         return (EOF);
00751       }
00752 
00753       return (ch);
00754         }
00755     else if (ch == 0xfe)
00756     {
00757      /*
00758       * UTF-16 big-endian BOM?
00759       */
00760 
00761       if (buf->current >= buf->end)
00762         if (mxml_fd_read(buf) < 0)
00763           return (EOF);
00764 
00765       ch = *(buf->current)++;
00766 
00767       if (ch != 0xff)
00768         return (EOF);
00769 
00770       *encoding = ENCODE_UTF16BE;
00771 
00772       return (mxml_fd_getc(p, encoding));
00773     }
00774     else if (ch == 0xff)
00775     {
00776      /*
00777       * UTF-16 little-endian BOM?
00778       */
00779 
00780       if (buf->current >= buf->end)
00781         if (mxml_fd_read(buf) < 0)
00782           return (EOF);
00783 
00784       ch = *(buf->current)++;
00785 
00786       if (ch != 0xfe)
00787         return (EOF);
00788 
00789       *encoding = ENCODE_UTF16LE;
00790 
00791       return (mxml_fd_getc(p, encoding));
00792     }
00793     else if ((ch & 0xe0) == 0xc0)
00794     {
00795      /*
00796       * Two-byte value...
00797       */
00798 
00799       if (buf->current >= buf->end)
00800         if (mxml_fd_read(buf) < 0)
00801           return (EOF);
00802 
00803       temp = *(buf->current)++;
00804 
00805       if ((temp & 0xc0) != 0x80)
00806         return (EOF);
00807 
00808       ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
00809 
00810       if (ch < 0x80)
00811         return (EOF);
00812     }
00813     else if ((ch & 0xf0) == 0xe0)
00814     {
00815      /*
00816       * Three-byte value...
00817       */
00818 
00819       if (buf->current >= buf->end)
00820         if (mxml_fd_read(buf) < 0)
00821           return (EOF);
00822 
00823       temp = *(buf->current)++;
00824 
00825       if ((temp & 0xc0) != 0x80)
00826         return (EOF);
00827 
00828       ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
00829 
00830       if (buf->current >= buf->end)
00831         if (mxml_fd_read(buf) < 0)
00832           return (EOF);
00833 
00834       temp = *(buf->current)++;
00835 
00836       if ((temp & 0xc0) != 0x80)
00837         return (EOF);
00838 
00839       ch = (ch << 6) | (temp & 0x3f);
00840 
00841       if (ch < 0x800)
00842         return (EOF);
00843     }
00844     else if ((ch & 0xf8) == 0xf0)
00845     {
00846      /*
00847       * Four-byte value...
00848       */
00849 
00850       if (buf->current >= buf->end)
00851         if (mxml_fd_read(buf) < 0)
00852           return (EOF);
00853 
00854       temp = *(buf->current)++;
00855 
00856       if ((temp & 0xc0) != 0x80)
00857         return (EOF);
00858 
00859       ch = ((ch & 0x07) << 6) | (temp & 0x3f);
00860 
00861       if (buf->current >= buf->end)
00862         if (mxml_fd_read(buf) < 0)
00863           return (EOF);
00864 
00865       temp = *(buf->current)++;
00866 
00867       if ((temp & 0xc0) != 0x80)
00868         return (EOF);
00869 
00870       ch = (ch << 6) | (temp & 0x3f);
00871 
00872       if (buf->current >= buf->end)
00873         if (mxml_fd_read(buf) < 0)
00874           return (EOF);
00875 
00876       temp = *(buf->current)++;
00877 
00878       if ((temp & 0xc0) != 0x80)
00879         return (EOF);
00880 
00881       ch = (ch << 6) | (temp & 0x3f);
00882 
00883       if (ch < 0x10000)
00884         return (EOF);
00885     }
00886     else
00887       return (EOF);
00888     break;
00889 
00890     case ENCODE_UTF16BE :
00891        /*
00892         * Read UTF-16 big-endian char...
00893     */
00894 
00895     if (buf->current >= buf->end)
00896       if (mxml_fd_read(buf) < 0)
00897         return (EOF);
00898 
00899     temp = *(buf->current)++;
00900 
00901     ch = (ch << 8) | temp;
00902 
00903     if (mxml_bad_char(ch))
00904     {
00905       mxml_error("Bad control character 0x%02x not allowed by XML standard!",
00906                  ch);
00907       return (EOF);
00908     }
00909         else if (ch >= 0xd800 && ch <= 0xdbff)
00910     {
00911      /*
00912       * Multi-word UTF-16 char...
00913       */
00914 
00915           int lch;
00916 
00917       if (buf->current >= buf->end)
00918         if (mxml_fd_read(buf) < 0)
00919           return (EOF);
00920 
00921       lch = *(buf->current)++;
00922 
00923       if (buf->current >= buf->end)
00924         if (mxml_fd_read(buf) < 0)
00925           return (EOF);
00926 
00927       temp = *(buf->current)++;
00928 
00929       lch = (lch << 8) | temp;
00930 
00931           if (lch < 0xdc00 || lch >= 0xdfff)
00932         return (EOF);
00933 
00934           ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
00935     }
00936     break;
00937 
00938     case ENCODE_UTF16LE :
00939        /*
00940         * Read UTF-16 little-endian char...
00941     */
00942 
00943     if (buf->current >= buf->end)
00944       if (mxml_fd_read(buf) < 0)
00945         return (EOF);
00946 
00947     temp = *(buf->current)++;
00948 
00949     ch |= (temp << 8);
00950 
00951         if (mxml_bad_char(ch))
00952     {
00953       mxml_error("Bad control character 0x%02x not allowed by XML standard!",
00954                  ch);
00955       return (EOF);
00956     }
00957         else if (ch >= 0xd800 && ch <= 0xdbff)
00958     {
00959      /*
00960       * Multi-word UTF-16 char...
00961       */
00962 
00963           int lch;
00964 
00965       if (buf->current >= buf->end)
00966         if (mxml_fd_read(buf) < 0)
00967           return (EOF);
00968 
00969       lch = *(buf->current)++;
00970 
00971       if (buf->current >= buf->end)
00972         if (mxml_fd_read(buf) < 0)
00973           return (EOF);
00974 
00975       temp = *(buf->current)++;
00976 
00977       lch |= (temp << 8);
00978 
00979           if (lch < 0xdc00 || lch >= 0xdfff)
00980         return (EOF);
00981 
00982           ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
00983     }
00984     break;
00985   }
00986 
00987 #if DEBUG > 1
00988   printf("mxml_fd_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
00989 #endif /* DEBUG > 1 */
00990 
00991   return (ch);
00992 }
00993 
00994 
00995 /*
00996  * 'mxml_fd_putc()' - Write a character to a file descriptor.
00997  */
00998 
00999 static int              /* O - 0 on success, -1 on error */
01000 mxml_fd_putc(int  ch,           /* I - Character */
01001              void *p)           /* I - File descriptor buffer */
01002 {
01003   _mxml_fdbuf_t *buf;           /* File descriptor buffer */
01004 
01005 
01006  /*
01007   * Flush the write buffer as needed - note above that "end" still leaves
01008   * 4 characters at the end so that we can avoid a lot of extra tests...
01009   */
01010 
01011   buf = (_mxml_fdbuf_t *)p;
01012 
01013   if (buf->current >= buf->end)
01014     if (mxml_fd_write(buf) < 0)
01015       return (-1);
01016 
01017   if (ch < 0x80)
01018   {
01019    /*
01020     * Write ASCII character directly...
01021     */
01022 
01023     *(buf->current)++ = ch;
01024   }
01025   else if (ch < 0x800)
01026   {
01027    /*
01028     * Two-byte UTF-8 character...
01029     */
01030 
01031     *(buf->current)++ = 0xc0 | (ch >> 6);
01032     *(buf->current)++ = 0x80 | (ch & 0x3f);
01033   }
01034   else if (ch < 0x10000)
01035   {
01036    /*
01037     * Three-byte UTF-8 character...
01038     */
01039 
01040     *(buf->current)++ = 0xe0 | (ch >> 12);
01041     *(buf->current)++ = 0x80 | ((ch >> 6) & 0x3f);
01042     *(buf->current)++ = 0x80 | (ch & 0x3f);
01043   }
01044   else
01045   {
01046    /*
01047     * Four-byte UTF-8 character...
01048     */
01049 
01050     *(buf->current)++ = 0xf0 | (ch >> 18);
01051     *(buf->current)++ = 0x80 | ((ch >> 12) & 0x3f);
01052     *(buf->current)++ = 0x80 | ((ch >> 6) & 0x3f);
01053     *(buf->current)++ = 0x80 | (ch & 0x3f);
01054   }
01055 
01056  /*
01057   * Return successfully...
01058   */
01059 
01060   return (0);
01061 }
01062 
01063 
01064 /*
01065  * 'mxml_fd_read()' - Read a buffer of data from a file descriptor.
01066  */
01067 
01068 static int              /* O - 0 on success, -1 on error */
01069 mxml_fd_read(_mxml_fdbuf_t *buf)        /* I - File descriptor buffer */
01070 {
01071   int   bytes;              /* Bytes read... */
01072 
01073 
01074  /*
01075   * Range check input...
01076   */
01077 
01078   if (!buf)
01079     return (-1);
01080 
01081  /*
01082   * Read from the file descriptor...
01083   */
01084 
01085   while ((bytes = read(buf->fd, buf->buffer, sizeof(buf->buffer))) < 0)
01086 #ifdef EINTR
01087     if (errno != EAGAIN && errno != EINTR)
01088 #else
01089     if (errno != EAGAIN)
01090 #endif /* EINTR */
01091       return (-1);
01092 
01093   if (bytes == 0)
01094     return (-1);
01095 
01096  /*
01097   * Update the pointers and return success...
01098   */
01099 
01100   buf->current = buf->buffer;
01101   buf->end     = buf->buffer + bytes;
01102 
01103   return (0);
01104 }
01105 
01106 
01107 /*
01108  * 'mxml_fd_write()' - Write a buffer of data to a file descriptor.
01109  */
01110 
01111 static int              /* O - 0 on success, -1 on error */
01112 mxml_fd_write(_mxml_fdbuf_t *buf)   /* I - File descriptor buffer */
01113 {
01114   int       bytes;          /* Bytes written */
01115   unsigned char *ptr;           /* Pointer into buffer */
01116 
01117 
01118  /*
01119   * Range check...
01120   */
01121 
01122   if (!buf)
01123     return (-1);
01124 
01125  /*
01126   * Return 0 if there is nothing to write...
01127   */
01128 
01129   if (buf->current == buf->buffer)
01130     return (0);
01131 
01132  /*
01133   * Loop until we have written everything...
01134   */
01135 
01136   for (ptr = buf->buffer; ptr < buf->current; ptr += bytes)
01137     if ((bytes = write(buf->fd, ptr, buf->current - ptr)) < 0)
01138       return (-1);
01139 
01140  /*
01141   * All done, reset pointers and return success...
01142   */
01143 
01144   buf->current = buf->buffer;
01145 
01146   return (0);
01147 }
01148 
01149 
01150 /*
01151  * 'mxml_file_getc()' - Get a character from a file.
01152  */
01153 
01154 static int              /* O  - Character or EOF */
01155 mxml_file_getc(void *p,         /* I  - Pointer to file */
01156                int  *encoding)      /* IO - Encoding */
01157 {
01158   int   ch,             /* Character from file */
01159     temp;               /* Temporary character */
01160   FILE  *fp;                /* Pointer to file */
01161 
01162 
01163  /*
01164   * Read a character from the file and see if it is EOF or ASCII...
01165   */
01166 
01167   fp = (FILE *)p;
01168   ch = getc(fp);
01169 
01170   if (ch == EOF)
01171     return (EOF);
01172 
01173   switch (*encoding)
01174   {
01175     case ENCODE_UTF8 :
01176        /*
01177     * Got a UTF-8 character; convert UTF-8 to Unicode and return...
01178     */
01179 
01180     if (!(ch & 0x80))
01181     {
01182       if (mxml_bad_char(ch))
01183       {
01184         mxml_error("Bad control character 0x%02x not allowed by XML standard!",
01185                    ch);
01186         return (EOF);
01187       }
01188 
01189 #if DEBUG > 1
01190           printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
01191 #endif /* DEBUG > 1 */
01192 
01193       return (ch);
01194         }
01195     else if (ch == 0xfe)
01196     {
01197      /*
01198       * UTF-16 big-endian BOM?
01199       */
01200 
01201           ch = getc(fp);
01202       if (ch != 0xff)
01203         return (EOF);
01204 
01205       *encoding = ENCODE_UTF16BE;
01206 
01207       return (mxml_file_getc(p, encoding));
01208     }
01209     else if (ch == 0xff)
01210     {
01211      /*
01212       * UTF-16 little-endian BOM?
01213       */
01214 
01215           ch = getc(fp);
01216       if (ch != 0xfe)
01217         return (EOF);
01218 
01219       *encoding = ENCODE_UTF16LE;
01220 
01221       return (mxml_file_getc(p, encoding));
01222     }
01223     else if ((ch & 0xe0) == 0xc0)
01224     {
01225      /*
01226       * Two-byte value...
01227       */
01228 
01229       if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
01230         return (EOF);
01231 
01232       ch = ((ch & 0x1f) << 6) | (temp & 0x3f);
01233 
01234       if (ch < 0x80)
01235         return (EOF);
01236     }
01237     else if ((ch & 0xf0) == 0xe0)
01238     {
01239      /*
01240       * Three-byte value...
01241       */
01242 
01243       if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
01244         return (EOF);
01245 
01246       ch = ((ch & 0x0f) << 6) | (temp & 0x3f);
01247 
01248       if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
01249         return (EOF);
01250 
01251       ch = (ch << 6) | (temp & 0x3f);
01252 
01253       if (ch < 0x800)
01254         return (EOF);
01255     }
01256     else if ((ch & 0xf8) == 0xf0)
01257     {
01258      /*
01259       * Four-byte value...
01260       */
01261 
01262       if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
01263         return (EOF);
01264 
01265       ch = ((ch & 0x07) << 6) | (temp & 0x3f);
01266 
01267       if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
01268         return (EOF);
01269 
01270       ch = (ch << 6) | (temp & 0x3f);
01271 
01272       if ((temp = getc(fp)) == EOF || (temp & 0xc0) != 0x80)
01273         return (EOF);
01274 
01275       ch = (ch << 6) | (temp & 0x3f);
01276 
01277       if (ch < 0x10000)
01278         return (EOF);
01279     }
01280     else
01281       return (EOF);
01282     break;
01283 
01284     case ENCODE_UTF16BE :
01285        /*
01286         * Read UTF-16 big-endian char...
01287     */
01288 
01289     ch = (ch << 8) | getc(fp);
01290 
01291     if (mxml_bad_char(ch))
01292     {
01293       mxml_error("Bad control character 0x%02x not allowed by XML standard!",
01294                  ch);
01295       return (EOF);
01296     }
01297         else if (ch >= 0xd800 && ch <= 0xdbff)
01298     {
01299      /*
01300       * Multi-word UTF-16 char...
01301       */
01302 
01303           int lch = (getc(fp) << 8) | getc(fp);
01304 
01305           if (lch < 0xdc00 || lch >= 0xdfff)
01306         return (EOF);
01307 
01308           ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
01309     }
01310     break;
01311 
01312     case ENCODE_UTF16LE :
01313        /*
01314         * Read UTF-16 little-endian char...
01315     */
01316 
01317     ch |= (getc(fp) << 8);
01318 
01319         if (mxml_bad_char(ch))
01320     {
01321       mxml_error("Bad control character 0x%02x not allowed by XML standard!",
01322                  ch);
01323       return (EOF);
01324     }
01325         else if (ch >= 0xd800 && ch <= 0xdbff)
01326     {
01327      /*
01328       * Multi-word UTF-16 char...
01329       */
01330 
01331           int lch = getc(fp) | (getc(fp) << 8);
01332 
01333           if (lch < 0xdc00 || lch >= 0xdfff)
01334         return (EOF);
01335 
01336           ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
01337     }
01338     break;
01339   }
01340 
01341 #if DEBUG > 1
01342   printf("mxml_file_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
01343 #endif /* DEBUG > 1 */
01344 
01345   return (ch);
01346 }
01347 
01348 
01349 /*
01350  * 'mxml_file_putc()' - Write a character to a file.
01351  */
01352 
01353 static int              /* O - 0 on success, -1 on failure */
01354 mxml_file_putc(int  ch,         /* I - Character to write */
01355                void *p)         /* I - Pointer to file */
01356 {
01357   char  buffer[4],          /* Buffer for character */
01358     *bufptr;            /* Pointer into buffer */
01359   int   buflen;             /* Number of bytes to write */
01360 
01361 
01362   if (ch < 0x80)
01363     return (putc(ch, (FILE *)p) == EOF ? -1 : 0);
01364 
01365   bufptr = buffer;
01366 
01367   if (ch < 0x800)
01368   {
01369    /*
01370     * Two-byte UTF-8 character...
01371     */
01372 
01373     *bufptr++ = 0xc0 | (ch >> 6);
01374     *bufptr++ = 0x80 | (ch & 0x3f);
01375   }
01376   else if (ch < 0x10000)
01377   {
01378    /*
01379     * Three-byte UTF-8 character...
01380     */
01381 
01382     *bufptr++ = 0xe0 | (ch >> 12);
01383     *bufptr++ = 0x80 | ((ch >> 6) & 0x3f);
01384     *bufptr++ = 0x80 | (ch & 0x3f);
01385   }
01386   else
01387   {
01388    /*
01389     * Four-byte UTF-8 character...
01390     */
01391 
01392     *bufptr++ = 0xf0 | (ch >> 18);
01393     *bufptr++ = 0x80 | ((ch >> 12) & 0x3f);
01394     *bufptr++ = 0x80 | ((ch >> 6) & 0x3f);
01395     *bufptr++ = 0x80 | (ch & 0x3f);
01396   }
01397 
01398   buflen = bufptr - buffer;
01399 
01400   return (fwrite(buffer, 1, buflen, (FILE *)p) < buflen ? -1 : 0);
01401 }
01402 
01403 
01404 /*
01405  * 'mxml_get_entity()' - Get the character corresponding to an entity...
01406  */
01407 
01408 static int              /* O  - Character value or EOF on error */
01409 mxml_get_entity(mxml_node_t *parent,    /* I  - Parent node */
01410         void        *p,     /* I  - Pointer to source */
01411         int         *encoding,  /* IO - Character encoding */
01412                 int         (*getc_cb)(void *, int *))
01413                     /* I  - Get character function */
01414 {
01415   int   ch;             /* Current character */
01416   char  entity[64],         /* Entity string */
01417     *entptr;            /* Pointer into entity */
01418 
01419 
01420   entptr = entity;
01421 
01422   while ((ch = (*getc_cb)(p, encoding)) != EOF)
01423     if (ch > 126 || (!isalnum(ch) && ch != '#'))
01424       break;
01425     else if (entptr < (entity + sizeof(entity) - 1))
01426       *entptr++ = ch;
01427     else
01428     {
01429       mxml_error("Entity name too long under parent <%s>!",
01430              parent ? parent->value.element.name : "null");
01431       break;
01432     }
01433 
01434   *entptr = '\0';
01435 
01436   if (ch != ';')
01437   {
01438     mxml_error("Character entity \"%s\" not terminated under parent <%s>!",
01439            entity, parent ? parent->value.element.name : "null");
01440     return (EOF);
01441   }
01442 
01443   if (entity[0] == '#')
01444   {
01445     if (entity[1] == 'x')
01446       ch = strtol(entity + 2, NULL, 16);
01447     else
01448       ch = strtol(entity + 1, NULL, 10);
01449   }
01450   else if ((ch = mxmlEntityGetValue(entity)) < 0)
01451     mxml_error("Entity name \"%s;\" not supported under parent <%s>!",
01452            entity, parent ? parent->value.element.name : "null");
01453 
01454   if (mxml_bad_char(ch))
01455   {
01456     mxml_error("Bad control character 0x%02x under parent <%s> not allowed by XML standard!",
01457                ch, parent ? parent->value.element.name : "null");
01458     return (EOF);
01459   }
01460 
01461   return (ch);
01462 }
01463 
01464 
01465 /*
01466  * 'mxml_load_data()' - Load data into an XML node tree.
01467  */
01468 
01469 static mxml_node_t *            /* O - First node or NULL if the file could not be read. */
01470 mxml_load_data(
01471     mxml_node_t     *top,       /* I - Top node */
01472     void            *p,         /* I - Pointer to data */
01473     mxml_load_cb_t  cb,         /* I - Callback function or MXML_NO_CALLBACK */
01474     _mxml_getc_cb_t getc_cb,        /* I - Read function */
01475     mxml_sax_cb_t   sax_cb,     /* I - SAX callback or MXML_NO_CALLBACK */
01476     void            *sax_data)      /* I - SAX user data */
01477 {
01478   mxml_node_t   *node,          /* Current node */
01479         *first,         /* First node added */
01480         *parent;        /* Current parent node */
01481   int       ch,         /* Character from file */
01482         whitespace;     /* Non-zero if whitespace seen */
01483   char      *buffer,        /* String buffer */
01484         *bufptr;        /* Pointer into buffer */
01485   int       bufsize;        /* Size of buffer */
01486   mxml_type_t   type;           /* Current node type */
01487   int       encoding;       /* Character encoding */
01488   _mxml_global_t *global = _mxml_global();
01489                     /* Global data */
01490   static const char * const types[] =   /* Type strings... */
01491         {
01492           "MXML_ELEMENT",   /* XML element with attributes */
01493           "MXML_INTEGER",   /* Integer value */
01494           "MXML_OPAQUE",    /* Opaque string */
01495           "MXML_REAL",      /* Real value */
01496           "MXML_TEXT",      /* Text fragment */
01497           "MXML_CUSTOM"     /* Custom data */
01498         };
01499 
01500 
01501  /*
01502   * Read elements and other nodes from the file...
01503   */
01504 
01505   if ((buffer = malloc(64)) == NULL)
01506   {
01507     mxml_error("Unable to allocate string buffer!");
01508     return (NULL);
01509   }
01510 
01511   bufsize    = 64;
01512   bufptr     = buffer;
01513   parent     = top;
01514   first      = NULL;
01515   whitespace = 0;
01516   encoding   = ENCODE_UTF8;
01517 
01518   if (cb && parent)
01519     type = (*cb)(parent);
01520   else
01521     type = MXML_TEXT;
01522 
01523   while ((ch = (*getc_cb)(p, &encoding)) != EOF)
01524   {
01525     if ((ch == '<' ||
01526          (mxml_isspace(ch) && type != MXML_OPAQUE && type != MXML_CUSTOM)) &&
01527         bufptr > buffer)
01528     {
01529      /*
01530       * Add a new value node...
01531       */
01532 
01533       *bufptr = '\0';
01534 
01535       switch (type)
01536       {
01537     case MXML_INTEGER :
01538             node = mxmlNewInteger(parent, strtol(buffer, &bufptr, 0));
01539         break;
01540 
01541     case MXML_OPAQUE :
01542             node = mxmlNewOpaque(parent, buffer);
01543         break;
01544 
01545     case MXML_REAL :
01546             node = mxmlNewReal(parent, strtod(buffer, &bufptr));
01547         break;
01548 
01549     case MXML_TEXT :
01550             node = mxmlNewText(parent, whitespace, buffer);
01551         break;
01552 
01553     case MXML_CUSTOM :
01554         if (global->custom_load_cb)
01555         {
01556          /*
01557           * Use the callback to fill in the custom data...
01558           */
01559 
01560               node = mxmlNewCustom(parent, NULL, NULL);
01561 
01562           if ((*global->custom_load_cb)(node, buffer))
01563           {
01564             mxml_error("Bad custom value '%s' in parent <%s>!",
01565                    buffer, parent ? parent->value.element.name : "null");
01566         mxmlDelete(node);
01567         node = NULL;
01568           }
01569           break;
01570         }
01571 
01572         default : /* Ignore... */
01573         node = NULL;
01574         break;
01575       }
01576 
01577       if (*bufptr)
01578       {
01579        /*
01580         * Bad integer/real number value...
01581     */
01582 
01583         mxml_error("Bad %s value '%s' in parent <%s>!",
01584                type == MXML_INTEGER ? "integer" : "real", buffer,
01585            parent ? parent->value.element.name : "null");
01586     break;
01587       }
01588 
01589       bufptr     = buffer;
01590       whitespace = mxml_isspace(ch) && type == MXML_TEXT;
01591 
01592       if (!node && type != MXML_IGNORE)
01593       {
01594        /*
01595     * Print error and return...
01596     */
01597 
01598     mxml_error("Unable to add value node of type %s to parent <%s>!",
01599                types[type], parent ? parent->value.element.name : "null");
01600     goto error;
01601       }
01602 
01603       if (sax_cb)
01604       {
01605         (*sax_cb)(node, MXML_SAX_DATA, sax_data);
01606 
01607         if (!mxmlRelease(node))
01608           node = NULL;
01609       }
01610 
01611       if (!first && node)
01612         first = node;
01613     }
01614     else if (mxml_isspace(ch) && type == MXML_TEXT)
01615       whitespace = 1;
01616 
01617    /*
01618     * Add lone whitespace node if we have an element and existing
01619     * whitespace...
01620     */
01621 
01622     if (ch == '<' && whitespace && type == MXML_TEXT)
01623     {
01624       node = mxmlNewText(parent, whitespace, "");
01625 
01626       if (sax_cb)
01627       {
01628         (*sax_cb)(node, MXML_SAX_DATA, sax_data);
01629 
01630         if (!mxmlRelease(node))
01631           node = NULL;
01632       }
01633 
01634       if (!first && node)
01635         first = node;
01636 
01637       whitespace = 0;
01638     }
01639 
01640     if (ch == '<')
01641     {
01642      /*
01643       * Start of open/close tag...
01644       */
01645 
01646       bufptr = buffer;
01647 
01648       while ((ch = (*getc_cb)(p, &encoding)) != EOF)
01649         if (mxml_isspace(ch) || ch == '>' || (ch == '/' && bufptr > buffer))
01650       break;
01651     else if (ch == '<')
01652     {
01653       mxml_error("Bare < in element!");
01654       goto error;
01655     }
01656     else if (ch == '&')
01657     {
01658       if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
01659         goto error;
01660 
01661       if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
01662         goto error;
01663     }
01664     else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
01665       goto error;
01666     else if (((bufptr - buffer) == 1 && buffer[0] == '?') ||
01667              ((bufptr - buffer) == 3 && !strncmp(buffer, "!--", 3)) ||
01668              ((bufptr - buffer) == 8 && !strncmp(buffer, "![CDATA[", 8)))
01669       break;
01670 
01671       *bufptr = '\0';
01672 
01673       if (!strcmp(buffer, "!--"))
01674       {
01675        /*
01676         * Gather rest of comment...
01677     */
01678 
01679     while ((ch = (*getc_cb)(p, &encoding)) != EOF)
01680     {
01681       if (ch == '>' && bufptr > (buffer + 4) &&
01682           bufptr[-3] != '-' && bufptr[-2] == '-' && bufptr[-1] == '-')
01683         break;
01684       else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
01685         goto error;
01686     }
01687 
01688        /*
01689         * Error out if we didn't get the whole comment...
01690     */
01691 
01692         if (ch != '>')
01693     {
01694      /*
01695       * Print error and return...
01696       */
01697 
01698       mxml_error("Early EOF in comment node!");
01699       goto error;
01700     }
01701 
01702 
01703        /*
01704         * Otherwise add this as an element under the current parent...
01705     */
01706 
01707     *bufptr = '\0';
01708 
01709     if ((node = mxmlNewElement(parent, buffer)) == NULL)
01710     {
01711      /*
01712       * Just print error for now...
01713       */
01714 
01715       mxml_error("Unable to add comment node to parent <%s>!",
01716                  parent ? parent->value.element.name : "null");
01717       break;
01718     }
01719 
01720         if (sax_cb)
01721         {
01722           (*sax_cb)(node, MXML_SAX_COMMENT, sax_data);
01723 
01724           if (!mxmlRelease(node))
01725             node = NULL;
01726         }
01727 
01728     if (node && !first)
01729       first = node;
01730       }
01731       else if (!strcmp(buffer, "![CDATA["))
01732       {
01733        /*
01734         * Gather CDATA section...
01735     */
01736 
01737     while ((ch = (*getc_cb)(p, &encoding)) != EOF)
01738     {
01739       if (ch == '>' && !strncmp(bufptr - 2, "]]", 2))
01740         break;
01741       else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
01742         goto error;
01743     }
01744 
01745        /*
01746         * Error out if we didn't get the whole comment...
01747     */
01748 
01749         if (ch != '>')
01750     {
01751      /*
01752       * Print error and return...
01753       */
01754 
01755       mxml_error("Early EOF in CDATA node!");
01756       goto error;
01757     }
01758 
01759 
01760        /*
01761         * Otherwise add this as an element under the current parent...
01762     */
01763 
01764     *bufptr = '\0';
01765 
01766     if ((node = mxmlNewElement(parent, buffer)) == NULL)
01767     {
01768      /*
01769       * Print error and return...
01770       */
01771 
01772       mxml_error("Unable to add CDATA node to parent <%s>!",
01773                  parent ? parent->value.element.name : "null");
01774       goto error;
01775     }
01776 
01777         if (sax_cb)
01778         {
01779           (*sax_cb)(node, MXML_SAX_CDATA, sax_data);
01780 
01781           if (!mxmlRelease(node))
01782             node = NULL;
01783         }
01784 
01785     if (node && !first)
01786       first = node;
01787       }
01788       else if (buffer[0] == '?')
01789       {
01790        /*
01791         * Gather rest of processing instruction...
01792     */
01793 
01794     while ((ch = (*getc_cb)(p, &encoding)) != EOF)
01795     {
01796       if (ch == '>' && bufptr > buffer && bufptr[-1] == '?')
01797         break;
01798       else if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
01799         goto error;
01800     }
01801 
01802        /*
01803         * Error out if we didn't get the whole processing instruction...
01804     */
01805 
01806         if (ch != '>')
01807     {
01808      /*
01809       * Print error and return...
01810       */
01811 
01812       mxml_error("Early EOF in processing instruction node!");
01813       goto error;
01814     }
01815 
01816        /*
01817         * Otherwise add this as an element under the current parent...
01818     */
01819 
01820     *bufptr = '\0';
01821 
01822     if ((node = mxmlNewElement(parent, buffer)) == NULL)
01823     {
01824      /*
01825       * Print error and return...
01826       */
01827 
01828       mxml_error("Unable to add processing instruction node to parent <%s>!",
01829                  parent ? parent->value.element.name : "null");
01830       goto error;
01831     }
01832 
01833         if (sax_cb)
01834         {
01835           (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
01836 
01837           if (!mxmlRelease(node))
01838             node = NULL;
01839         }
01840 
01841         if (node)
01842     {
01843       if (!first)
01844             first = node;
01845 
01846       if (!parent)
01847       {
01848         parent = node;
01849 
01850         if (cb)
01851           type = (*cb)(parent);
01852       }
01853     }
01854       }
01855       else if (buffer[0] == '!')
01856       {
01857        /*
01858         * Gather rest of declaration...
01859     */
01860 
01861     do
01862     {
01863       if (ch == '>')
01864         break;
01865       else
01866       {
01867             if (ch == '&')
01868           if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
01869         goto error;
01870 
01871         if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
01872           goto error;
01873       }
01874     }
01875         while ((ch = (*getc_cb)(p, &encoding)) != EOF);
01876 
01877        /*
01878         * Error out if we didn't get the whole declaration...
01879     */
01880 
01881         if (ch != '>')
01882     {
01883      /*
01884       * Print error and return...
01885       */
01886 
01887       mxml_error("Early EOF in declaration node!");
01888       goto error;
01889     }
01890 
01891        /*
01892         * Otherwise add this as an element under the current parent...
01893     */
01894 
01895     *bufptr = '\0';
01896 
01897     if ((node = mxmlNewElement(parent, buffer)) == NULL)
01898     {
01899      /*
01900       * Print error and return...
01901       */
01902 
01903       mxml_error("Unable to add declaration node to parent <%s>!",
01904                  parent ? parent->value.element.name : "null");
01905       goto error;
01906     }
01907 
01908         if (sax_cb)
01909         {
01910           (*sax_cb)(node, MXML_SAX_DIRECTIVE, sax_data);
01911 
01912           if (!mxmlRelease(node))
01913             node = NULL;
01914         }
01915 
01916         if (node)
01917     {
01918       if (!first)
01919             first = node;
01920 
01921       if (!parent)
01922       {
01923         parent = node;
01924 
01925         if (cb)
01926           type = (*cb)(parent);
01927       }
01928     }
01929       }
01930       else if (buffer[0] == '/')
01931       {
01932        /*
01933         * Handle close tag...
01934     */
01935 
01936         if (!parent || strcmp(buffer + 1, parent->value.element.name))
01937     {
01938      /*
01939       * Close tag doesn't match tree; print an error for now...
01940       */
01941 
01942       mxml_error("Mismatched close tag <%s> under parent <%s>!",
01943                  buffer, parent ? parent->value.element.name : "(null)");
01944           goto error;
01945     }
01946 
01947        /*
01948         * Keep reading until we see >...
01949     */
01950 
01951         while (ch != '>' && ch != EOF)
01952       ch = (*getc_cb)(p, &encoding);
01953 
01954         node   = parent;
01955         parent = parent->parent;
01956 
01957         if (sax_cb)
01958         {
01959           (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
01960 
01961           mxmlRelease(node);
01962         }
01963 
01964        /*
01965     * Ascend into the parent and set the value type as needed...
01966     */
01967 
01968     if (cb && parent)
01969       type = (*cb)(parent);
01970       }
01971       else
01972       {
01973        /*
01974         * Handle open tag...
01975     */
01976 
01977         if ((node = mxmlNewElement(parent, buffer)) == NULL)
01978     {
01979      /*
01980       * Just print error for now...
01981       */
01982 
01983       mxml_error("Unable to add element node to parent <%s>!",
01984                  parent ? parent->value.element.name : "null");
01985       goto error;
01986     }
01987 
01988         if (mxml_isspace(ch))
01989         {
01990       if ((ch = mxml_parse_element(node, p, &encoding, getc_cb)) == EOF)
01991         goto error;
01992         }
01993         else if (ch == '/')
01994     {
01995       if ((ch = (*getc_cb)(p, &encoding)) != '>')
01996       {
01997         mxml_error("Expected > but got '%c' instead for element <%s/>!",
01998                    ch, buffer);
01999             mxmlDelete(node);
02000             goto error;
02001       }
02002 
02003       ch = '/';
02004     }
02005 
02006         if (sax_cb)
02007           (*sax_cb)(node, MXML_SAX_ELEMENT_OPEN, sax_data);
02008 
02009         if (!first)
02010       first = node;
02011 
02012     if (ch == EOF)
02013       break;
02014 
02015         if (ch != '/')
02016     {
02017      /*
02018       * Descend into this node, setting the value type as needed...
02019       */
02020 
02021       parent = node;
02022 
02023       if (cb && parent)
02024         type = (*cb)(parent);
02025     }
02026         else if (sax_cb)
02027         {
02028           (*sax_cb)(node, MXML_SAX_ELEMENT_CLOSE, sax_data);
02029 
02030           if (!mxmlRelease(node) && first == node)
02031             first = NULL;
02032         }
02033       }
02034 
02035       bufptr  = buffer;
02036     }
02037     else if (ch == '&')
02038     {
02039      /*
02040       * Add character entity to current buffer...
02041       */
02042 
02043       if ((ch = mxml_get_entity(parent, p, &encoding, getc_cb)) == EOF)
02044     goto error;
02045 
02046       if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
02047     goto error;
02048     }
02049     else if (type == MXML_OPAQUE || type == MXML_CUSTOM || !mxml_isspace(ch))
02050     {
02051      /*
02052       * Add character to current buffer...
02053       */
02054 
02055       if (mxml_add_char(ch, &bufptr, &buffer, &bufsize))
02056     goto error;
02057     }
02058   }
02059 
02060  /*
02061   * Free the string buffer - we don't need it anymore...
02062   */
02063 
02064   free(buffer);
02065 
02066  /*
02067   * Find the top element and return it...
02068   */
02069 
02070   if (parent)
02071   {
02072     node = parent;
02073 
02074     while (parent->parent != top && parent->parent)
02075       parent = parent->parent;
02076 
02077     if (node != parent)
02078     {
02079       mxml_error("Missing close tag </%s> under parent <%s>!",
02080              node->value.element.name,
02081          node->parent ? node->parent->value.element.name : "(null)");
02082 
02083       mxmlDelete(first);
02084 
02085       return (NULL);
02086     }
02087   }
02088 
02089   if (parent)
02090     return (parent);
02091   else
02092     return (first);
02093 
02094  /*
02095   * Common error return...
02096   */
02097 
02098 error:
02099 
02100   mxmlDelete(first);
02101 
02102   free(buffer);
02103 
02104   return (NULL);
02105 }
02106 
02107 
02108 /*
02109  * 'mxml_parse_element()' - Parse an element for any attributes...
02110  */
02111 
02112 static int              /* O  - Terminating character */
02113 mxml_parse_element(
02114     mxml_node_t     *node,      /* I  - Element node */
02115     void            *p,         /* I  - Data to read from */
02116     int             *encoding,      /* IO - Encoding */
02117     _mxml_getc_cb_t getc_cb)        /* I  - Data callback */
02118 {
02119   int   ch,             /* Current character in file */
02120     quote;              /* Quoting character */
02121   char  *name,              /* Attribute name */
02122     *value,             /* Attribute value */
02123     *ptr;               /* Pointer into name/value */
02124   int   namesize,           /* Size of name string */
02125     valsize;            /* Size of value string */
02126 
02127 
02128  /*
02129   * Initialize the name and value buffers...
02130   */
02131 
02132   if ((name = malloc(64)) == NULL)
02133   {
02134     mxml_error("Unable to allocate memory for name!");
02135     return (EOF);
02136   }
02137 
02138   namesize = 64;
02139 
02140   if ((value = malloc(64)) == NULL)
02141   {
02142     free(name);
02143     mxml_error("Unable to allocate memory for value!");
02144     return (EOF);
02145   }
02146 
02147   valsize = 64;
02148 
02149  /*
02150   * Loop until we hit a >, /, ?, or EOF...
02151   */
02152 
02153   while ((ch = (*getc_cb)(p, encoding)) != EOF)
02154   {
02155 #if DEBUG > 1
02156     fprintf(stderr, "parse_element: ch='%c'\n", ch);
02157 #endif /* DEBUG > 1 */
02158 
02159    /*
02160     * Skip leading whitespace...
02161     */
02162 
02163     if (mxml_isspace(ch))
02164       continue;
02165 
02166    /*
02167     * Stop at /, ?, or >...
02168     */
02169 
02170     if (ch == '/' || ch == '?')
02171     {
02172      /*
02173       * Grab the > character and print an error if it isn't there...
02174       */
02175 
02176       quote = (*getc_cb)(p, encoding);
02177 
02178       if (quote != '>')
02179       {
02180         mxml_error("Expected '>' after '%c' for element %s, but got '%c'!",
02181                ch, node->value.element.name, quote);
02182         goto error;
02183       }
02184 
02185       break;
02186     }
02187     else if (ch == '<')
02188     {
02189       mxml_error("Bare < in element %s!", node->value.element.name);
02190       goto error;
02191     }
02192     else if (ch == '>')
02193       break;
02194 
02195    /*
02196     * Read the attribute name...
02197     */
02198 
02199     name[0] = ch;
02200     ptr     = name + 1;
02201 
02202     if (ch == '\"' || ch == '\'')
02203     {
02204      /*
02205       * Name is in quotes, so get a quoted string...
02206       */
02207 
02208       quote = ch;
02209 
02210       while ((ch = (*getc_cb)(p, encoding)) != EOF)
02211       {
02212         if (ch == '&')
02213       if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
02214         goto error;
02215 
02216     if (mxml_add_char(ch, &ptr, &name, &namesize))
02217       goto error;
02218 
02219     if (ch == quote)
02220           break;
02221       }
02222     }
02223     else
02224     {
02225      /*
02226       * Grab an normal, non-quoted name...
02227       */
02228 
02229       while ((ch = (*getc_cb)(p, encoding)) != EOF)
02230     if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>' ||
02231         ch == '?')
02232           break;
02233     else
02234     {
02235           if (ch == '&')
02236         if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
02237           goto error;
02238 
02239       if (mxml_add_char(ch, &ptr, &name, &namesize))
02240         goto error;
02241     }
02242     }
02243 
02244     *ptr = '\0';
02245 
02246     if (mxmlElementGetAttr(node, name))
02247       goto error;
02248 
02249     while (ch != EOF && mxml_isspace(ch))
02250       ch = (*getc_cb)(p, encoding);
02251 
02252     if (ch == '=')
02253     {
02254      /*
02255       * Read the attribute value...
02256       */
02257 
02258       while ((ch = (*getc_cb)(p, encoding)) != EOF && mxml_isspace(ch));
02259 
02260       if (ch == EOF)
02261       {
02262         mxml_error("Missing value for attribute '%s' in element %s!",
02263                name, node->value.element.name);
02264         goto error;
02265       }
02266 
02267       if (ch == '\'' || ch == '\"')
02268       {
02269        /*
02270         * Read quoted value...
02271     */
02272 
02273         quote = ch;
02274     ptr   = value;
02275 
02276         while ((ch = (*getc_cb)(p, encoding)) != EOF)
02277       if (ch == quote)
02278         break;
02279       else
02280       {
02281         if (ch == '&')
02282           if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
02283             goto error;
02284 
02285         if (mxml_add_char(ch, &ptr, &value, &valsize))
02286           goto error;
02287       }
02288 
02289         *ptr = '\0';
02290       }
02291       else
02292       {
02293        /*
02294         * Read unquoted value...
02295     */
02296 
02297     value[0] = ch;
02298     ptr      = value + 1;
02299 
02300     while ((ch = (*getc_cb)(p, encoding)) != EOF)
02301       if (mxml_isspace(ch) || ch == '=' || ch == '/' || ch == '>')
02302             break;
02303       else
02304       {
02305         if (ch == '&')
02306           if ((ch = mxml_get_entity(node, p, encoding, getc_cb)) == EOF)
02307             goto error;
02308 
02309         if (mxml_add_char(ch, &ptr, &value, &valsize))
02310           goto error;
02311       }
02312 
02313         *ptr = '\0';
02314       }
02315 
02316      /*
02317       * Set the attribute with the given string value...
02318       */
02319 
02320       mxmlElementSetAttr(node, name, value);
02321     }
02322     else
02323     {
02324       mxml_error("Missing value for attribute '%s' in element %s!",
02325              name, node->value.element.name);
02326       goto error;
02327     }
02328 
02329    /*
02330     * Check the end character...
02331     */
02332 
02333     if (ch == '/' || ch == '?')
02334     {
02335      /*
02336       * Grab the > character and print an error if it isn't there...
02337       */
02338 
02339       quote = (*getc_cb)(p, encoding);
02340 
02341       if (quote != '>')
02342       {
02343         mxml_error("Expected '>' after '%c' for element %s, but got '%c'!",
02344                ch, node->value.element.name, quote);
02345         ch = EOF;
02346       }
02347 
02348       break;
02349     }
02350     else if (ch == '>')
02351       break;
02352   }
02353 
02354  /*
02355   * Free the name and value buffers and return...
02356   */
02357 
02358   free(name);
02359   free(value);
02360 
02361   return (ch);
02362 
02363  /*
02364   * Common error return point...
02365   */
02366 
02367 error:
02368 
02369   free(name);
02370   free(value);
02371 
02372   return (EOF);
02373 }
02374 
02375 
02376 /*
02377  * 'mxml_string_getc()' - Get a character from a string.
02378  */
02379 
02380 static int              /* O  - Character or EOF */
02381 mxml_string_getc(void *p,       /* I  - Pointer to file */
02382                  int  *encoding)    /* IO - Encoding */
02383 {
02384   int       ch;         /* Character */
02385   const char    **s;            /* Pointer to string pointer */
02386 
02387 
02388   s = (const char **)p;
02389 
02390   if ((ch = (*s)[0] & 255) != 0 || *encoding == ENCODE_UTF16LE)
02391   {
02392    /*
02393     * Got character; convert UTF-8 to integer and return...
02394     */
02395 
02396     (*s)++;
02397 
02398     switch (*encoding)
02399     {
02400       case ENCODE_UTF8 :
02401       if (!(ch & 0x80))
02402       {
02403 #if DEBUG > 1
02404             printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
02405 #endif /* DEBUG > 1 */
02406 
02407         if (mxml_bad_char(ch))
02408         {
02409           mxml_error("Bad control character 0x%02x not allowed by XML standard!",
02410                  ch);
02411           return (EOF);
02412         }
02413 
02414         return (ch);
02415           }
02416       else if (ch == 0xfe)
02417       {
02418        /*
02419         * UTF-16 big-endian BOM?
02420         */
02421 
02422             if (((*s)[0] & 255) != 0xff)
02423           return (EOF);
02424 
02425         *encoding = ENCODE_UTF16BE;
02426         (*s)++;
02427 
02428         return (mxml_string_getc(p, encoding));
02429       }
02430       else if (ch == 0xff)
02431       {
02432        /*
02433         * UTF-16 little-endian BOM?
02434         */
02435 
02436             if (((*s)[0] & 255) != 0xfe)
02437           return (EOF);
02438 
02439         *encoding = ENCODE_UTF16LE;
02440         (*s)++;
02441 
02442         return (mxml_string_getc(p, encoding));
02443       }
02444       else if ((ch & 0xe0) == 0xc0)
02445       {
02446        /*
02447         * Two-byte value...
02448         */
02449 
02450         if (((*s)[0] & 0xc0) != 0x80)
02451               return (EOF);
02452 
02453         ch = ((ch & 0x1f) << 6) | ((*s)[0] & 0x3f);
02454 
02455         (*s)++;
02456 
02457         if (ch < 0x80)
02458           return (EOF);
02459 
02460 #if DEBUG > 1
02461             printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
02462 #endif /* DEBUG > 1 */
02463 
02464         return (ch);
02465       }
02466       else if ((ch & 0xf0) == 0xe0)
02467       {
02468        /*
02469         * Three-byte value...
02470         */
02471 
02472         if (((*s)[0] & 0xc0) != 0x80 ||
02473             ((*s)[1] & 0xc0) != 0x80)
02474               return (EOF);
02475 
02476         ch = ((((ch & 0x0f) << 6) | ((*s)[0] & 0x3f)) << 6) | ((*s)[1] & 0x3f);
02477 
02478         (*s) += 2;
02479 
02480         if (ch < 0x800)
02481           return (EOF);
02482 
02483 #if DEBUG > 1
02484             printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
02485 #endif /* DEBUG > 1 */
02486 
02487         return (ch);
02488       }
02489       else if ((ch & 0xf8) == 0xf0)
02490       {
02491        /*
02492         * Four-byte value...
02493         */
02494 
02495         if (((*s)[0] & 0xc0) != 0x80 ||
02496             ((*s)[1] & 0xc0) != 0x80 ||
02497             ((*s)[2] & 0xc0) != 0x80)
02498               return (EOF);
02499 
02500         ch = ((((((ch & 0x07) << 6) | ((*s)[0] & 0x3f)) << 6) |
02501                ((*s)[1] & 0x3f)) << 6) | ((*s)[2] & 0x3f);
02502 
02503         (*s) += 3;
02504 
02505         if (ch < 0x10000)
02506           return (EOF);
02507 
02508 #if DEBUG > 1
02509             printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
02510 #endif /* DEBUG > 1 */
02511 
02512         return (ch);
02513       }
02514       else
02515         return (EOF);
02516 
02517       case ENCODE_UTF16BE :
02518      /*
02519           * Read UTF-16 big-endian char...
02520       */
02521 
02522       ch = (ch << 8) | ((*s)[0] & 255);
02523       (*s) ++;
02524 
02525           if (mxml_bad_char(ch))
02526       {
02527         mxml_error("Bad control character 0x%02x not allowed by XML standard!",
02528                    ch);
02529         return (EOF);
02530       }
02531           else if (ch >= 0xd800 && ch <= 0xdbff)
02532       {
02533        /*
02534         * Multi-word UTF-16 char...
02535         */
02536 
02537             int lch;            /* Lower word */
02538 
02539 
02540             if (!(*s)[0])
02541           return (EOF);
02542 
02543             lch = (((*s)[0] & 255) << 8) | ((*s)[1] & 255);
02544         (*s) += 2;
02545 
02546             if (lch < 0xdc00 || lch >= 0xdfff)
02547           return (EOF);
02548 
02549             ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
02550       }
02551 
02552 #if DEBUG > 1
02553           printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
02554 #endif /* DEBUG > 1 */
02555 
02556       return (ch);
02557 
02558       case ENCODE_UTF16LE :
02559      /*
02560           * Read UTF-16 little-endian char...
02561       */
02562 
02563       ch = ch | (((*s)[0] & 255) << 8);
02564 
02565       if (!ch)
02566       {
02567         (*s) --;
02568         return (EOF);
02569       }
02570 
02571       (*s) ++;
02572 
02573           if (mxml_bad_char(ch))
02574       {
02575         mxml_error("Bad control character 0x%02x not allowed by XML standard!",
02576                    ch);
02577         return (EOF);
02578       }
02579           else if (ch >= 0xd800 && ch <= 0xdbff)
02580       {
02581        /*
02582         * Multi-word UTF-16 char...
02583         */
02584 
02585             int lch;            /* Lower word */
02586 
02587 
02588             if (!(*s)[1])
02589           return (EOF);
02590 
02591             lch = (((*s)[1] & 255) << 8) | ((*s)[0] & 255);
02592         (*s) += 2;
02593 
02594             if (lch < 0xdc00 || lch >= 0xdfff)
02595           return (EOF);
02596 
02597             ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000;
02598       }
02599 
02600 #if DEBUG > 1
02601           printf("mxml_string_getc: %c (0x%04x)\n", ch < ' ' ? '.' : ch, ch);
02602 #endif /* DEBUG > 1 */
02603 
02604       return (ch);
02605     }
02606   }
02607 
02608   return (EOF);
02609 }
02610 
02611 
02612 /*
02613  * 'mxml_string_putc()' - Write a character to a string.
02614  */
02615 
02616 static int              /* O - 0 on success, -1 on failure */
02617 mxml_string_putc(int  ch,       /* I - Character to write */
02618                  void *p)       /* I - Pointer to string pointers */
02619 {
02620   char  **pp;               /* Pointer to string pointers */
02621 
02622 
02623   pp = (char **)p;
02624 
02625   if (ch < 0x80)
02626   {
02627    /*
02628     * Plain ASCII doesn't need special encoding...
02629     */
02630 
02631     if (pp[0] < pp[1])
02632       pp[0][0] = ch;
02633 
02634     pp[0] ++;
02635   }
02636   else if (ch < 0x800)
02637   {
02638    /*
02639     * Two-byte UTF-8 character...
02640     */
02641 
02642     if ((pp[0] + 1) < pp[1])
02643     {
02644       pp[0][0] = 0xc0 | (ch >> 6);
02645       pp[0][1] = 0x80 | (ch & 0x3f);
02646     }
02647 
02648     pp[0] += 2;
02649   }
02650   else if (ch < 0x10000)
02651   {
02652    /*
02653     * Three-byte UTF-8 character...
02654     */
02655 
02656     if ((pp[0] + 2) < pp[1])
02657     {
02658       pp[0][0] = 0xe0 | (ch >> 12);
02659       pp[0][1] = 0x80 | ((ch >> 6) & 0x3f);
02660       pp[0][2] = 0x80 | (ch & 0x3f);
02661     }
02662 
02663     pp[0] += 3;
02664   }
02665   else
02666   {
02667    /*
02668     * Four-byte UTF-8 character...
02669     */
02670 
02671     if ((pp[0] + 2) < pp[1])
02672     {
02673       pp[0][0] = 0xf0 | (ch >> 18);
02674       pp[0][1] = 0x80 | ((ch >> 12) & 0x3f);
02675       pp[0][2] = 0x80 | ((ch >> 6) & 0x3f);
02676       pp[0][3] = 0x80 | (ch & 0x3f);
02677     }
02678 
02679     pp[0] += 4;
02680   }
02681 
02682   return (0);
02683 }
02684 
02685 
02686 /*
02687  * 'mxml_write_name()' - Write a name string.
02688  */
02689 
02690 static int              /* O - 0 on success, -1 on failure */
02691 mxml_write_name(const char *s,      /* I - Name to write */
02692                 void       *p,      /* I - Write pointer */
02693         int        (*putc_cb)(int, void *))
02694                     /* I - Write callback */
02695 {
02696   char      quote;          /* Quote character */
02697   const char    *name;          /* Entity name */
02698 
02699 
02700   if (*s == '\"' || *s == '\'')
02701   {
02702    /*
02703     * Write a quoted name string...
02704     */
02705 
02706     if ((*putc_cb)(*s, p) < 0)
02707       return (-1);
02708 
02709     quote = *s++;
02710 
02711     while (*s && *s != quote)
02712     {
02713       if ((name = mxmlEntityGetName(*s)) != NULL)
02714       {
02715     if ((*putc_cb)('&', p) < 0)
02716           return (-1);
02717 
02718         while (*name)
02719     {
02720       if ((*putc_cb)(*name, p) < 0)
02721             return (-1);
02722 
02723           name ++;
02724     }
02725 
02726     if ((*putc_cb)(';', p) < 0)
02727           return (-1);
02728       }
02729       else if ((*putc_cb)(*s, p) < 0)
02730     return (-1);
02731 
02732       s ++;
02733     }
02734 
02735    /*
02736     * Write the end quote...
02737     */
02738 
02739     if ((*putc_cb)(quote, p) < 0)
02740       return (-1);
02741   }
02742   else
02743   {
02744    /*
02745     * Write a non-quoted name string...
02746     */
02747 
02748     while (*s)
02749     {
02750       if ((*putc_cb)(*s, p) < 0)
02751     return (-1);
02752 
02753       s ++;
02754     }
02755   }
02756 
02757   return (0);
02758 }
02759 
02760 
02761 /*
02762  * 'mxml_write_node()' - Save an XML node to a file.
02763  */
02764 
02765 static int              /* O - Column or -1 on error */
02766 mxml_write_node(mxml_node_t     *node,  /* I - Node to write */
02767                 void            *p, /* I - File to write to */
02768             mxml_save_cb_t  cb, /* I - Whitespace callback */
02769         int             col,    /* I - Current column */
02770         _mxml_putc_cb_t putc_cb,/* I - Output callback */
02771         _mxml_global_t  *global)/* I - Global data */
02772 {
02773   int       i,          /* Looping var */
02774         width;          /* Width of attr + value */
02775   mxml_attr_t   *attr;          /* Current attribute */
02776   char      s[255];         /* Temporary string */
02777 
02778 
02779   while (node != NULL)
02780   {
02781    /*
02782     * Print the node value...
02783     */
02784 
02785     switch (node->type)
02786     {
02787       case MXML_ELEMENT :
02788           col = mxml_write_ws(node, p, cb, MXML_WS_BEFORE_OPEN, col, putc_cb);
02789 
02790           if ((*putc_cb)('<', p) < 0)
02791         return (-1);
02792           if (node->value.element.name[0] == '?' ||
02793           !strncmp(node->value.element.name, "!--", 3) ||
02794           !strncmp(node->value.element.name, "![CDATA[", 8))
02795           {
02796        /*
02797         * Comments, CDATA, and processing instructions do not
02798         * use character entities.
02799         */
02800 
02801         const char  *ptr;       /* Pointer into name */
02802 
02803 
02804         for (ptr = node->value.element.name; *ptr; ptr ++)
02805           if ((*putc_cb)(*ptr, p) < 0)
02806             return (-1);
02807 
02808            /*
02809         * Prefer a newline for whitespace after ?xml...
02810         */
02811 
02812             if (!strncmp(node->value.element.name, "?xml", 4))
02813               col = global->wrap;
02814       }
02815       else if (mxml_write_name(node->value.element.name, p, putc_cb) < 0)
02816         return (-1);
02817 
02818           col += strlen(node->value.element.name) + 1;
02819 
02820       for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
02821            i > 0;
02822            i --, attr ++)
02823       {
02824         width = strlen(attr->name);
02825 
02826         if (attr->value)
02827           width += strlen(attr->value) + 3;
02828 
02829         if ((col + width) > global->wrap)
02830         {
02831           if ((*putc_cb)('\n', p) < 0)
02832             return (-1);
02833 
02834           col = 0;
02835         }
02836         else
02837         {
02838           if ((*putc_cb)(' ', p) < 0)
02839             return (-1);
02840 
02841           col ++;
02842         }
02843 
02844             if (mxml_write_name(attr->name, p, putc_cb) < 0)
02845           return (-1);
02846 
02847         if (attr->value)
02848         {
02849               if ((*putc_cb)('=', p) < 0)
02850         return (-1);
02851               if ((*putc_cb)('\"', p) < 0)
02852         return (-1);
02853           if (mxml_write_string(attr->value, p, putc_cb) < 0)
02854         return (-1);
02855               if ((*putc_cb)('\"', p) < 0)
02856         return (-1);
02857             }
02858 
02859             col += width;
02860       }
02861 
02862       if (node->child)
02863       {
02864            /*
02865         * Write children...
02866         */
02867 
02868         if ((*putc_cb)('>', p) < 0)
02869           return (-1);
02870         else
02871           col ++;
02872 
02873             col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
02874 
02875         if ((col = mxml_write_node(node->child, p, cb, col, putc_cb,
02876                                    global)) < 0)
02877           return (-1);
02878 
02879            /*
02880         * The ? and ! elements are special-cases and have no end tags...
02881         */
02882 
02883             if (node->value.element.name[0] != '!' &&
02884             node->value.element.name[0] != '?')
02885         {
02886               col = mxml_write_ws(node, p, cb, MXML_WS_BEFORE_CLOSE, col, putc_cb);
02887 
02888               if ((*putc_cb)('<', p) < 0)
02889         return (-1);
02890               if ((*putc_cb)('/', p) < 0)
02891         return (-1);
02892               if (mxml_write_string(node->value.element.name, p, putc_cb) < 0)
02893         return (-1);
02894               if ((*putc_cb)('>', p) < 0)
02895         return (-1);
02896 
02897               col += strlen(node->value.element.name) + 3;
02898 
02899               col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_CLOSE, col, putc_cb);
02900         }
02901       }
02902       else if (node->value.element.name[0] == '!' ||
02903                node->value.element.name[0] == '?')
02904       {
02905            /*
02906         * The ? and ! elements are special-cases...
02907         */
02908 
02909         if ((*putc_cb)('>', p) < 0)
02910           return (-1);
02911         else
02912           col ++;
02913 
02914             col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
02915           }
02916       else
02917       {
02918             if ((*putc_cb)(' ', p) < 0)
02919           return (-1);
02920             if ((*putc_cb)('/', p) < 0)
02921           return (-1);
02922             if ((*putc_cb)('>', p) < 0)
02923           return (-1);
02924 
02925         col += 3;
02926 
02927             col = mxml_write_ws(node, p, cb, MXML_WS_AFTER_OPEN, col, putc_cb);
02928       }
02929           break;
02930 
02931       case MXML_INTEGER :
02932       if (node->prev)
02933       {
02934         if (col > global->wrap)
02935         {
02936           if ((*putc_cb)('\n', p) < 0)
02937             return (-1);
02938 
02939           col = 0;
02940         }
02941         else if ((*putc_cb)(' ', p) < 0)
02942           return (-1);
02943         else
02944           col ++;
02945           }
02946 
02947           sprintf(s, "%d", node->value.integer);
02948       if (mxml_write_string(s, p, putc_cb) < 0)
02949         return (-1);
02950 
02951       col += strlen(s);
02952           break;
02953 
02954       case MXML_OPAQUE :
02955           if (mxml_write_string(node->value.opaque, p, putc_cb) < 0)
02956         return (-1);
02957 
02958           col += strlen(node->value.opaque);
02959           break;
02960 
02961       case MXML_REAL :
02962       if (node->prev)
02963       {
02964         if (col > global->wrap)
02965         {
02966           if ((*putc_cb)('\n', p) < 0)
02967             return (-1);
02968 
02969           col = 0;
02970         }
02971         else if ((*putc_cb)(' ', p) < 0)
02972           return (-1);
02973         else
02974           col ++;
02975           }
02976 
02977           sprintf(s, "%f", node->value.real);
02978       if (mxml_write_string(s, p, putc_cb) < 0)
02979         return (-1);
02980 
02981       col += strlen(s);
02982           break;
02983 
02984       case MXML_TEXT :
02985       if (node->value.text.whitespace && col > 0)
02986       {
02987         if (col > global->wrap)
02988         {
02989           if ((*putc_cb)('\n', p) < 0)
02990             return (-1);
02991 
02992           col = 0;
02993         }
02994         else if ((*putc_cb)(' ', p) < 0)
02995           return (-1);
02996         else
02997           col ++;
02998           }
02999 
03000           if (mxml_write_string(node->value.text.string, p, putc_cb) < 0)
03001         return (-1);
03002 
03003       col += strlen(node->value.text.string);
03004           break;
03005 
03006       case MXML_CUSTOM :
03007           if (global->custom_save_cb)
03008       {
03009         char    *data;      /* Custom data string */
03010         const char  *newline;   /* Last newline in string */
03011 
03012 
03013             if ((data = (*global->custom_save_cb)(node)) == NULL)
03014           return (-1);
03015 
03016             if (mxml_write_string(data, p, putc_cb) < 0)
03017           return (-1);
03018 
03019             if ((newline = strrchr(data, '\n')) == NULL)
03020           col += strlen(data);
03021         else
03022               col = strlen(newline);
03023 
03024             free(data);
03025         break;
03026       }
03027 
03028       default : /* Should never happen */
03029           return (-1);
03030     }
03031 
03032    /*
03033     * Next node...
03034     */
03035 
03036     node = node->next;
03037   }
03038 
03039   return (col);
03040 }
03041 
03042 
03043 /*
03044  * 'mxml_write_string()' - Write a string, escaping & and < as needed.
03045  */
03046 
03047 static int              /* O - 0 on success, -1 on failure */
03048 mxml_write_string(
03049     const char      *s,         /* I - String to write */
03050     void            *p,         /* I - Write pointer */
03051     _mxml_putc_cb_t putc_cb)        /* I - Write callback */
03052 {
03053   const char    *name;          /* Entity name, if any */
03054 
03055 
03056   while (*s)
03057   {
03058     if ((name = mxmlEntityGetName(*s)) != NULL)
03059     {
03060       if ((*putc_cb)('&', p) < 0)
03061         return (-1);
03062 
03063       while (*name)
03064       {
03065     if ((*putc_cb)(*name, p) < 0)
03066           return (-1);
03067         name ++;
03068       }
03069 
03070       if ((*putc_cb)(';', p) < 0)
03071         return (-1);
03072     }
03073     else if ((*putc_cb)(*s, p) < 0)
03074       return (-1);
03075 
03076     s ++;
03077   }
03078 
03079   return (0);
03080 }
03081 
03082 
03083 /*
03084  * 'mxml_write_ws()' - Do whitespace callback...
03085  */
03086 
03087 static int              /* O - New column */
03088 mxml_write_ws(mxml_node_t     *node,    /* I - Current node */
03089               void            *p,   /* I - Write pointer */
03090               mxml_save_cb_t  cb,   /* I - Callback function */
03091           int             ws,   /* I - Where value */
03092           int             col,  /* I - Current column */
03093               _mxml_putc_cb_t putc_cb)  /* I - Write callback */
03094 {
03095   const char    *s;         /* Whitespace string */
03096 
03097 
03098   if (cb && (s = (*cb)(node, ws)) != NULL)
03099   {
03100     while (*s)
03101     {
03102       if ((*putc_cb)(*s, p) < 0)
03103     return (-1);
03104       else if (*s == '\n')
03105     col = 0;
03106       else if (*s == '\t')
03107       {
03108     col += MXML_TAB;
03109     col = col - (col % MXML_TAB);
03110       }
03111       else
03112     col ++;
03113 
03114       s ++;
03115     }
03116   }
03117 
03118   return (col);
03119 }

Generated by  doxygen 1.6.2