/home/dko/projects/mobilec/trunk/src/mxml-2.2.2/mxml-file.c

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

Generated on Fri May 16 14:49:54 2008 for Mobile-C by  doxygen 1.5.4