diff options
author | Jonathan Beck | 2008-12-11 23:05:29 +0100 |
---|---|---|
committer | Jonathan Beck | 2008-12-11 23:05:29 +0100 |
commit | 31379321cec6bf6c6d670e0738d1b1e23dc92ac1 (patch) | |
tree | 47aad4a390bcab10ff4fc6c36b35f0b89c06c1eb /src/xplist.c | |
parent | 18d1ee3b0f17325fdffe0cf3e2770a3f0f45a1b9 (diff) | |
download | libplist-31379321cec6bf6c6d670e0738d1b1e23dc92ac1.tar.gz libplist-31379321cec6bf6c6d670e0738d1b1e23dc92ac1.tar.bz2 |
dissect plists in three file (abstract binary xml)
Diffstat (limited to 'src/xplist.c')
-rw-r--r-- | src/xplist.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/src/xplist.c b/src/xplist.c new file mode 100644 index 0000000..a87b259 --- /dev/null +++ b/src/xplist.c @@ -0,0 +1,306 @@ +/* + * plist.c + * XML plist implementation + * + * Copyright (c) 2008 Jonathan Beck All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <string.h> +#include <assert.h> +#include "utils.h" +#include "plist.h" +#include <wchar.h> +#include <stdlib.h> +#include <stdio.h> + + +#include <libxml/parser.h> +#include <libxml/tree.h> + + +const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\ +<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\ +<plist version=\"1.0\">\n\ +</plist>\0"; + + +/** Formats a block of text to be a given indentation and width. + * + * The total width of the return string will be depth + cols. + * + * @param buf The string to format. + * @param cols The number of text columns for returned block of text. + * @param depth The number of tabs to indent the returned block of text. + * + * @return The formatted string. + */ +char *format_string(const char *buf, int cols, int depth) +{ + int colw = depth + cols + 1; + int len = strlen(buf); + int nlines = len / cols + 1; + char *new_buf = (char *) malloc(nlines * colw + depth + 1); + int i = 0; + int j = 0; + + assert(cols >= 0); + assert(depth >= 0); + + // Inserts new lines and tabs at appropriate locations + for (i = 0; i < nlines; i++) { + new_buf[i * colw] = '\n'; + for (j = 0; j < depth; j++) + new_buf[i * colw + 1 + j] = '\t'; + memcpy(new_buf + i * colw + 1 + depth, buf + i * cols, cols); + } + new_buf[len + (1 + depth) * nlines] = '\n'; + + // Inserts final row of indentation and termination character + for (j = 0; j < depth; j++) + new_buf[len + (1 + depth) * nlines + 1 + j] = '\t'; + new_buf[len + (1 + depth) * nlines + depth + 1] = '\0'; + + return new_buf; +} + + + +struct xml_node { + xmlNodePtr xml; + uint32_t depth; +}; + +/** Creates a new plist XML document. + * + * @return The plist XML document. + */ +xmlDocPtr new_plist() +{ + char *plist = strdup(plist_base); + xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0); + + if (!plist_xml) + return NULL; + + free(plist); + + return plist_xml; +} + +/** Destroys a previously created XML document. + * + * @param plist The XML document to destroy. + */ +void free_plist(xmlDocPtr plist) +{ + if (!plist) + return; + + xmlFreeDoc(plist); +} + +void node_to_xml(GNode * node, gpointer xml_struct) +{ + if (!node) + return; + + struct xml_node *xstruct = (struct xml_node *) xml_struct; + struct plist_data *node_data = (struct plist_data *) node->data; + + xmlNodePtr child_node = NULL; + char isStruct = FALSE; + + gchar *tag = NULL; + gchar *val = NULL; + + switch (node_data->type) { + case PLIST_BOOLEAN: + { + if (node_data->boolval) + tag = "true"; + else + tag = "false"; + } + break; + + case PLIST_UINT: + tag = "integer"; + val = g_strdup_printf("%lu", (long unsigned int) node_data->intval); + break; + + case PLIST_REAL: + tag = "real"; + val = g_strdup_printf("%Lf", (long double) node_data->realval); + break; + + case PLIST_STRING: + tag = "string"; + val = g_strdup(node_data->strval); + break; + + case PLIST_UNICODE: + tag = "string"; + val = g_strdup((gchar *) node_data->unicodeval); + break; + + case PLIST_KEY: + tag = "key"; + val = g_strdup((gchar *) node_data->strval); + break; + + case PLIST_DATA: + tag = "data"; + val = format_string(node_data->buff, 60, xstruct->depth); + break; + case PLIST_ARRAY: + tag = "array"; + isStruct = TRUE; + break; + case PLIST_DICT: + tag = "dict"; + isStruct = TRUE; + break; + case PLIST_DATE: //TODO : handle date tag + default: + break; + } + + int i = 0; + for (i = 0; i < xstruct->depth; i++) { + xmlNodeAddContent(xstruct->xml, "\t"); + } + child_node = xmlNewChild(xstruct->xml, NULL, tag, val); + xmlNodeAddContent(xstruct->xml, "\n"); + g_free(val); + + //add return for structured types + if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) + xmlNodeAddContent(child_node, "\n"); + + if (isStruct) { + struct xml_node child = { child_node, xstruct->depth + 1 }; + g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, &child); + } + //fix indent for structured types + if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) { + + for (i = 0; i < xstruct->depth; i++) { + xmlNodeAddContent(child_node, "\t"); + } + } + + return; +} + +void xml_to_node(xmlNodePtr xml_node, GNode * plist_node) +{ + xmlNodePtr node = NULL; + + for (node = xml_node->children; node; node = node->next) { + + while (node && !xmlStrcmp(node->name, "text")) + node = node->next; + if (!node) + break; + + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + GNode *subnode = g_node_new(data); + g_node_append(plist_node, subnode); + + if (!xmlStrcmp(node->name, "true")) { + data->boolval = 1; + data->type = PLIST_BOOLEAN; + continue; + } + + if (!xmlStrcmp(node->name, "false")) { + data->boolval = 0; + data->type = PLIST_BOOLEAN; + continue; + } + + if (!xmlStrcmp(node->name, "integer")) { + char *strval = xmlNodeGetContent(node); + data->intval = atoi(strval); + data->type = PLIST_UINT; + continue; + } + + if (!xmlStrcmp(node->name, "real")) { + char *strval = xmlNodeGetContent(node); + data->realval = atof(strval); + data->type = PLIST_REAL; + continue; + } + + if (!xmlStrcmp(node->name, "date")) + continue; //TODO : handle date tag + + if (!xmlStrcmp(node->name, "string")) { + data->strval = strdup(xmlNodeGetContent(node)); + data->type = PLIST_STRING; + continue; + } + + if (!xmlStrcmp(node->name, "key")) { + data->strval = strdup(xmlNodeGetContent(node)); + data->type = PLIST_KEY; + continue; + } + + if (!xmlStrcmp(node->name, "data")) { + data->buff = strdup(xmlNodeGetContent(node)); + data->type = PLIST_DATA; + continue; + } + + if (!xmlStrcmp(node->name, "array")) { + data->type = PLIST_ARRAY; + xml_to_node(node, subnode); + continue; + } + + if (!xmlStrcmp(node->name, "dict")) { + data->type = PLIST_DICT; + xml_to_node(node, subnode); + continue; + } + } +} + +void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length) +{ + if (!plist || !plist_xml || *plist_xml) + return; + xmlDocPtr plist_doc = new_plist(); + xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); + struct xml_node root = { root_node, 0 }; + g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, &root); + xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, length); +} + +void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist) +{ + xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0); + xmlNodePtr root_node = xmlDocGetRootElement(plist_doc); + + struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1); + *plist = g_node_new(data); + data->type = PLIST_DICT; + xml_to_node(root_node, *plist); +} |