📄 mxml-file.c
字号:
/* * "$Id: mxml-file.c 329 2008-01-13 00:42:35Z mike $" * * File loading code for Mini-XML, a small XML-like file parsing library. * * Copyright 2003-2008 by Michael Sweet. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Contents: * * mxmlLoadFd() - Load a file descriptor into an XML node tree. * mxmlLoadFile() - Load a file into an XML node tree. * mxmlLoadString() - Load a string into an XML node tree. * mxmlSaveAllocString() - Save an XML node tree to an allocated string. * mxmlSaveFd() - Save an XML tree to a file descriptor. * mxmlSaveFile() - Save an XML tree to a file. * mxmlSaveString() - Save an XML node tree to a string. * mxmlSAXLoadFd() - Load a file descriptor into an XML node tree * using a SAX callback. * mxmlSAXLoadFile() - Load a file into an XML node tree * using a SAX callback. * mxmlSAXLoadString() - Load a string into an XML node tree * using a SAX callback. * mxmlSetCustomHandlers() - Set the handling functions for custom data. * mxmlSetErrorCallback() - Set the error message callback. * mxmlSetWrapMargin() - Set the the wrap margin when saving XML data. * mxml_add_char() - Add a character to a buffer, expanding as needed. * mxml_fd_getc() - Read a character from a file descriptor. * mxml_fd_putc() - Write a character to a file descriptor. * mxml_fd_read() - Read a buffer of data from a file descriptor. * mxml_fd_write() - Write a buffer of data to a file descriptor. * mxml_file_getc() - Get a character from a file. * mxml_file_putc() - Write a character to a file. * mxml_get_entity() - Get the character corresponding to an entity... * mxml_load_data() - Load data into an XML node tree. * mxml_parse_element() - Parse an element for any attributes... * mxml_string_getc() - Get a character from a string. * mxml_string_putc() - Write a character to a string. * mxml_write_name() - Write a name string. * mxml_write_node() - Save an XML node to a file. * mxml_write_string() - Write a string, escaping & and < as needed. * mxml_write_ws() - Do whitespace callback... *//* * Include necessary headers... */#include "mxml-private.h"#ifdef WIN32# include <io.h>#else# include <unistd.h>#endif /* WIN32 *//* * Character encoding... */#define ENCODE_UTF8 0 /* UTF-8 */#define ENCODE_UTF16BE 1 /* UTF-16 Big-Endian */#define ENCODE_UTF16LE 2 /* UTF-16 Little-Endian *//* * Macro to test for a bad XML character... */#define mxml_bad_char(ch) ((ch) < ' ' && (ch) != '\n' && (ch) != '\r' && (ch) != '\t')/* * Types and structures... */typedef int (*_mxml_getc_cb_t)(void *, int *);typedef int (*_mxml_putc_cb_t)(int, void *);typedef struct _mxml_fdbuf_s /**** File descriptor buffer ****/{ int fd; /* File descriptor */ unsigned char *current, /* Current position in buffer */ *end, /* End of buffer */ buffer[8192]; /* Character buffer */} _mxml_fdbuf_t;/* * Local functions... */static int mxml_add_char(int ch, char **ptr, char **buffer, int *bufsize);static int mxml_fd_getc(void *p, int *encoding);static int mxml_fd_putc(int ch, void *p);static int mxml_fd_read(_mxml_fdbuf_t *buf);static int mxml_fd_write(_mxml_fdbuf_t *buf);static int mxml_file_getc(void *p, int *encoding);static int mxml_file_putc(int ch, void *p);static int mxml_get_entity(mxml_node_t *parent, void *p, int *encoding, _mxml_getc_cb_t getc_cb);static inline int mxml_isspace(int ch) { return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'); }static mxml_node_t *mxml_load_data(mxml_node_t *top, void *p, mxml_load_cb_t cb, _mxml_getc_cb_t getc_cb, mxml_sax_cb_t sax_cb, void *sax_data);static int mxml_parse_element(mxml_node_t *node, void *p, int *encoding, _mxml_getc_cb_t getc_cb);static int mxml_string_getc(void *p, int *encoding);static int mxml_string_putc(int ch, void *p);static int mxml_write_name(const char *s, void *p, _mxml_putc_cb_t putc_cb);static int mxml_write_node(mxml_node_t *node, void *p, mxml_save_cb_t cb, int col, _mxml_putc_cb_t putc_cb, _mxml_global_t *global);static int mxml_write_string(const char *s, void *p, _mxml_putc_cb_t putc_cb);static int mxml_write_ws(mxml_node_t *node, void *p, mxml_save_cb_t cb, int ws, int col, _mxml_putc_cb_t putc_cb);/* * 'mxmlLoadFd()' - Load a file descriptor into an XML node tree. * * The nodes in the specified file are added to the specified top node. * If no top node is provided, the XML file MUST be well-formed with a * single parent node like <?xml> for the entire file. The callback * function returns the value type that should be used for child nodes. * If MXML_NO_CALLBACK is specified then all child nodes will be either * MXML_ELEMENT or MXML_TEXT nodes. * * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading * child nodes of the specified type. */mxml_node_t * /* O - First node or NULL if the file could not be read. */mxmlLoadFd(mxml_node_t *top, /* I - Top node */ int fd, /* I - File descriptor to read from */ mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */{ _mxml_fdbuf_t buf; /* File descriptor buffer */ /* * Initialize the file descriptor buffer... */ buf.fd = fd; buf.current = buf.buffer; buf.end = buf.buffer; /* * Read the XML data... */ return (mxml_load_data(top, &buf, cb, mxml_fd_getc, MXML_NO_CALLBACK, NULL));}/* * 'mxmlLoadFile()' - Load a file into an XML node tree. * * The nodes in the specified file are added to the specified top node. * If no top node is provided, the XML file MUST be well-formed with a * single parent node like <?xml> for the entire file. The callback * function returns the value type that should be used for child nodes. * If MXML_NO_CALLBACK is specified then all child nodes will be either * MXML_ELEMENT or MXML_TEXT nodes. * * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading * child nodes of the specified type. */mxml_node_t * /* O - First node or NULL if the file could not be read. */mxmlLoadFile(mxml_node_t *top, /* I - Top node */ FILE *fp, /* I - File to read from */ mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */{ /* * Read the XML data... */ return (mxml_load_data(top, fp, cb, mxml_file_getc, MXML_NO_CALLBACK, NULL));}/* * 'mxmlLoadString()' - Load a string into an XML node tree. * * The nodes in the specified string are added to the specified top node. * If no top node is provided, the XML string MUST be well-formed with a * single parent node like <?xml> for the entire string. The callback * function returns the value type that should be used for child nodes. * If MXML_NO_CALLBACK is specified then all child nodes will be either * MXML_ELEMENT or MXML_TEXT nodes. * * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading * child nodes of the specified type. */mxml_node_t * /* O - First node or NULL if the string has errors. */mxmlLoadString(mxml_node_t *top, /* I - Top node */ const char *s, /* I - String to load */ mxml_load_cb_t cb) /* I - Callback function or MXML_NO_CALLBACK */{ /* * Read the XML data... */ return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, MXML_NO_CALLBACK, NULL));}/* * 'mxmlSaveAllocString()' - Save an XML node tree to an allocated string. * * This function returns a pointer to a string containing the textual * representation of the XML node tree. The string should be freed * using the free() function when you are done with it. NULL is returned * if the node would produce an empty string or if the string cannot be * allocated. * * The callback argument specifies a function that returns a whitespace * string or NULL before and after each element. If MXML_NO_CALLBACK * is specified, whitespace will only be added before MXML_TEXT nodes * with leading whitespace and before attribute names inside opening * element tags. */char * /* O - Allocated string or NULL */mxmlSaveAllocString( mxml_node_t *node, /* I - Node to write */ mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */{ int bytes; /* Required bytes */ char buffer[8192]; /* Temporary buffer */ char *s; /* Allocated string */ /* * Write the node to the temporary buffer... */ bytes = mxmlSaveString(node, buffer, sizeof(buffer), cb); if (bytes <= 0) return (NULL); if (bytes < (int)(sizeof(buffer) - 1)) { /* * Node fit inside the buffer, so just duplicate that string and * return... */ return (strdup(buffer)); } /* * Allocate a buffer of the required size and save the node to the * new buffer... */ if ((s = malloc(bytes + 1)) == NULL) return (NULL); mxmlSaveString(node, s, bytes + 1, cb); /* * Return the allocated string... */ return (s);}/* * 'mxmlSaveFd()' - Save an XML tree to a file descriptor. * * The callback argument specifies a function that returns a whitespace * string or NULL before and after each element. If MXML_NO_CALLBACK * is specified, whitespace will only be added before MXML_TEXT nodes * with leading whitespace and before attribute names inside opening * element tags. */int /* O - 0 on success, -1 on error. */mxmlSaveFd(mxml_node_t *node, /* I - Node to write */ int fd, /* I - File descriptor to write to */ mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */{ int col; /* Final column */ _mxml_fdbuf_t buf; /* File descriptor buffer */ _mxml_global_t *global = _mxml_global(); /* Global data */ /* * Initialize the file descriptor buffer... */ buf.fd = fd; buf.current = buf.buffer; buf.end = buf.buffer + sizeof(buf.buffer) - 4; /* * Write the node... */ if ((col = mxml_write_node(node, &buf, cb, 0, mxml_fd_putc, global)) < 0) return (-1); if (col > 0) if (mxml_fd_putc('\n', &buf) < 0) return (-1); /* * Flush and return... */ return (mxml_fd_write(&buf));}/* * 'mxmlSaveFile()' - Save an XML tree to a file. * * The callback argument specifies a function that returns a whitespace * string or NULL before and after each element. If MXML_NO_CALLBACK * is specified, whitespace will only be added before MXML_TEXT nodes * with leading whitespace and before attribute names inside opening * element tags. */int /* O - 0 on success, -1 on error. */mxmlSaveFile(mxml_node_t *node, /* I - Node to write */ FILE *fp, /* I - File to write to */ mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */{ int col; /* Final column */ _mxml_global_t *global = _mxml_global(); /* Global data */ /* * Write the node... */ if ((col = mxml_write_node(node, fp, cb, 0, mxml_file_putc, global)) < 0) return (-1); if (col > 0) if (putc('\n', fp) < 0) return (-1); /* * Return 0 (success)... */ return (0);}/* * 'mxmlSaveString()' - Save an XML node tree to a string. * * This function returns the total number of bytes that would be * required for the string but only copies (bufsize - 1) characters * into the specified buffer. * * The callback argument specifies a function that returns a whitespace * string or NULL before and after each element. If MXML_NO_CALLBACK * is specified, whitespace will only be added before MXML_TEXT nodes * with leading whitespace and before attribute names inside opening * element tags. */int /* O - Size of string */mxmlSaveString(mxml_node_t *node, /* I - Node to write */ char *buffer, /* I - String buffer */ int bufsize, /* I - Size of string buffer */ mxml_save_cb_t cb) /* I - Whitespace callback or MXML_NO_CALLBACK */{ int col; /* Final column */ char *ptr[2]; /* Pointers for putc_cb */ _mxml_global_t *global = _mxml_global(); /* Global data */ /* * Write the node... */ ptr[0] = buffer; ptr[1] = buffer + bufsize; if ((col = mxml_write_node(node, ptr, cb, 0, mxml_string_putc, global)) < 0) return (-1); if (col > 0) mxml_string_putc('\n', ptr); /* * Nul-terminate the buffer... */ if (ptr[0] >= ptr[1]) buffer[bufsize - 1] = '\0'; else ptr[0][0] = '\0'; /* * Return the number of characters... */ return (ptr[0] - buffer);}/* * 'mxmlSAXLoadFd()' - Load a file descriptor into an XML node tree * using a SAX callback. * * The nodes in the specified file are added to the specified top node. * If no top node is provided, the XML file MUST be well-formed with a * single parent node like <?xml> for the entire file. The callback * function returns the value type that should be used for child nodes. * If MXML_NO_CALLBACK is specified then all child nodes will be either * MXML_ELEMENT or MXML_TEXT nodes. * * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading * child nodes of the specified type. * * The SAX callback must call mxmlRetain() for any nodes that need to * be kept for later use. Otherwise, nodes are deleted when the parent * node is closed or after each data, comment, CDATA, or directive node. * * @since Mini-XML 2.3@ */mxml_node_t * /* O - First node or NULL if the file could not be read. */mxmlSAXLoadFd(mxml_node_t *top, /* I - Top node */ int fd, /* I - File descriptor to read from */ mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */ mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */ void *sax_data) /* I - SAX user data */{ _mxml_fdbuf_t buf; /* File descriptor buffer */ /* * Initialize the file descriptor buffer... */ buf.fd = fd; buf.current = buf.buffer; buf.end = buf.buffer; /* * Read the XML data... */ return (mxml_load_data(top, &buf, cb, mxml_fd_getc, sax_cb, sax_data));}/* * 'mxmlSAXLoadFile()' - Load a file into an XML node tree * using a SAX callback. * * The nodes in the specified file are added to the specified top node. * If no top node is provided, the XML file MUST be well-formed with a * single parent node like <?xml> for the entire file. The callback * function returns the value type that should be used for child nodes. * If MXML_NO_CALLBACK is specified then all child nodes will be either * MXML_ELEMENT or MXML_TEXT nodes. * * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading * child nodes of the specified type. * * The SAX callback must call mxmlRetain() for any nodes that need to * be kept for later use. Otherwise, nodes are deleted when the parent * node is closed or after each data, comment, CDATA, or directive node. * * @since Mini-XML 2.3@ */mxml_node_t * /* O - First node or NULL if the file could not be read. */mxmlSAXLoadFile( mxml_node_t *top, /* I - Top node */ FILE *fp, /* I - File to read from */ mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */ mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */ void *sax_data) /* I - SAX user data */{ /* * Read the XML data... */ return (mxml_load_data(top, fp, cb, mxml_file_getc, sax_cb, sax_data));}/* * 'mxmlSAXLoadString()' - Load a string into an XML node tree * using a SAX callback. * * The nodes in the specified string are added to the specified top node. * If no top node is provided, the XML string MUST be well-formed with a * single parent node like <?xml> for the entire string. The callback * function returns the value type that should be used for child nodes. * If MXML_NO_CALLBACK is specified then all child nodes will be either * MXML_ELEMENT or MXML_TEXT nodes. * * The constants MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, * MXML_REAL_CALLBACK, and MXML_TEXT_CALLBACK are defined for loading * child nodes of the specified type. * * The SAX callback must call mxmlRetain() for any nodes that need to * be kept for later use. Otherwise, nodes are deleted when the parent * node is closed or after each data, comment, CDATA, or directive node. * * @since Mini-XML 2.3@ */mxml_node_t * /* O - First node or NULL if the string has errors. */mxmlSAXLoadString( mxml_node_t *top, /* I - Top node */ const char *s, /* I - String to load */ mxml_load_cb_t cb, /* I - Callback function or MXML_NO_CALLBACK */ mxml_sax_cb_t sax_cb, /* I - SAX callback or MXML_NO_CALLBACK */ void *sax_data) /* I - SAX user data */{ /* * Read the XML data... */ return (mxml_load_data(top, (void *)&s, cb, mxml_string_getc, sax_cb, sax_data));}/* * 'mxmlSetCustomHandlers()' - Set the handling functions for custom data. * * The load function accepts a node pointer and a data string and must * return 0 on success and non-zero on error. * * The save function accepts a node pointer and must return a malloc'd * string on success and NULL on error. * */voidmxmlSetCustomHandlers( mxml_custom_load_cb_t load, /* I - Load function */ mxml_custom_save_cb_t save) /* I - Save function */{ _mxml_global_t *global = _mxml_global(); /* Global data */ global->custom_load_cb = load; global->custom_save_cb = save;}/* * 'mxmlSetErrorCallback()' - Set the error message callback. */voidmxmlSetErrorCallback(mxml_error_cb_t cb)/* I - Error callback function */{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -