/home/dko/projects/mobilec/tags/MobileC-v1.10.2/MobileC-v1.10.2/src/mxml-2.2.2/mxml-file.c

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

Generated on Fri Jul 11 17:59:45 2008 for Mobile-C by  doxygen 1.5.4