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

Go to the documentation of this file.
00001 /* SVN FILE INFO
00002  * $Revision: 174 $ : Last Committed Revision
00003  * $Date: 2008年06月24日 10:50:29 -0700 (2008年6月24日) $ : 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 Tue Oct 28 17:03:22 2008 for Mobile-C by doxygen 1.5.5

AltStyle によって変換されたページ (->オリジナル) /