1 /** **************************************************************************
4 * Copyright 2008 Bryan Ischo <bryan@ischo.com>
6 * This file is part of libs3.
8 * libs3 is free software: you can redistribute it and/or modify it under the
9 * terms of the GNU General Public License as published by the Free Software
10 * Foundation, version 3 of the License.
12 * In addition, as a special exception, the copyright holders give
13 * permission to link the code of this library and its programs with the
14 * OpenSSL library, and distribute linked combinations including the two.
16 * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY
17 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
21 * You should have received a copy of the GNU General Public License version 3
22 * along with libs3, in a file named COPYING. If not, see
23 * <http://www.gnu.org/licenses/>.
25 ************************************************************************** **/
27 #include <libxml/parser.h>
29 #include "simplexml.h"
31 // Use libxml2 for parsing XML. XML is severely overused in modern
32 // computing. It is useful for only a very small subset of tasks, but
33 // software developers who don't know better and are afraid to go against the
34 // grain use it for everything, and in most cases, it is completely
35 // inappropriate. Usually, the document structure is severely under-specified
36 // as well, as is the case with S3. We do our best by just caring about the
37 // most important aspects of the S3 "XML document" responses: the elements and
38 // their values. The SAX API (just about the lamest API ever devised and
39 // proof that XML sucks - well, the real proof is how crappy all of the XML
40 // parsing libraries are, including libxml2 - but I digress) is used here
41 // because we don't need much from the parser and SAX is fast and low memory.
43 // Note that for simplicity we assume all ASCII here. No attempts are made to
44 // detect non-ASCII sequences in utf-8 and convert them into ASCII in any way.
45 // S3 appears to only use ASCII anyway.
48 static xmlEntityPtr saxGetEntity(void *user_data, const xmlChar *name)
52 return xmlGetPredefinedEntity(name);
56 static void saxStartElement(void *user_data, const xmlChar *nameUtf8,
61 SimpleXml *simpleXml = (SimpleXml *) user_data;
63 if (simpleXml->status != S3StatusOK) {
67 // Assume that name has no non-ASCII in it
68 char *name = (char *) nameUtf8;
70 // Append the element to the element path
71 int len = strlen(name);
73 if ((simpleXml->elementPathLen + len + 1) >=
74 (int) sizeof(simpleXml->elementPath)) {
75 // Cannot handle this element, stop!
76 simpleXml->status = S3StatusXmlParseFailure;
80 if (simpleXml->elementPathLen) {
81 simpleXml->elementPath[simpleXml->elementPathLen++] = '/';
83 strcpy(&(simpleXml->elementPath[simpleXml->elementPathLen]), name);
84 simpleXml->elementPathLen += len;
88 static void saxEndElement(void *user_data, const xmlChar *name)
92 SimpleXml *simpleXml = (SimpleXml *) user_data;
94 if (simpleXml->status != S3StatusOK) {
98 // Call back with 0 data
99 simpleXml->status = (*(simpleXml->callback))
100 (simpleXml->elementPath, 0, 0, simpleXml->callbackData);
102 while ((simpleXml->elementPathLen > 0) &&
103 (simpleXml->elementPath[simpleXml->elementPathLen] != '/')) {
104 simpleXml->elementPathLen--;
107 simpleXml->elementPath[simpleXml->elementPathLen] = 0;
111 static void saxCharacters(void *user_data, const xmlChar *ch, int len)
113 SimpleXml *simpleXml = (SimpleXml *) user_data;
115 if (simpleXml->status != S3StatusOK) {
119 simpleXml->status = (*(simpleXml->callback))
120 (simpleXml->elementPath, (char *) ch, len, simpleXml->callbackData);
124 static void saxError(void *user_data, const char *msg, ...)
128 SimpleXml *simpleXml = (SimpleXml *) user_data;
130 if (simpleXml->status != S3StatusOK) {
134 simpleXml->status = S3StatusXmlParseFailure;
138 static struct _xmlSAXHandler saxHandlerG =
140 0, // internalSubsetSAXFunc
141 0, // isStandaloneSAXFunc
142 0, // hasInternalSubsetSAXFunc
143 0, // hasExternalSubsetSAXFunc
144 0, // resolveEntitySAXFunc
145 &saxGetEntity, // getEntitySAXFunc
146 0, // entityDeclSAXFunc
147 0, // notationDeclSAXFunc
148 0, // attributeDeclSAXFunc
149 0, // elementDeclSAXFunc
150 0, // unparsedEntityDeclSAXFunc
151 0, // setDocumentLocatorSAXFunc
152 0, // startDocumentSAXFunc
153 0, // endDocumentSAXFunc
154 &saxStartElement, // startElementSAXFunc
155 &saxEndElement, // endElementSAXFunc
156 0, // referenceSAXFunc
157 &saxCharacters, // charactersSAXFunc
158 0, // ignorableWhitespaceSAXFunc
159 0, // processingInstructionSAXFunc
162 &saxError, // errorSAXFunc
163 &saxError, // fatalErrorSAXFunc
164 0, // getParameterEntitySAXFunc
165 &saxCharacters, // cdataBlockSAXFunc
166 0, // externalSubsetSAXFunc
169 0, // startElementNsSAX2Func
170 0, // endElementNsSAX2Func
171 0 // xmlStructuredErrorFunc serror;
174 void simplexml_initialize(SimpleXml *simpleXml,
175 SimpleXmlCallback *callback, void *callbackData)
177 simpleXml->callback = callback;
178 simpleXml->callbackData = callbackData;
179 simpleXml->elementPathLen = 0;
180 simpleXml->status = S3StatusOK;
181 simpleXml->xmlParser = 0;
185 void simplexml_deinitialize(SimpleXml *simpleXml)
187 if (simpleXml->xmlParser) {
188 xmlFreeParserCtxt(simpleXml->xmlParser);
193 S3Status simplexml_add(SimpleXml *simpleXml, const char *data, int dataLen)
195 if (!simpleXml->xmlParser &&
196 (!(simpleXml->xmlParser = xmlCreatePushParserCtxt
197 (&saxHandlerG, simpleXml, 0, 0, 0)))) {
198 return S3StatusInternalError;
201 if (xmlParseChunk((xmlParserCtxtPtr) simpleXml->xmlParser,
203 return S3StatusXmlParseFailure;
206 return simpleXml->status;