bd8616b070b8db4108f8bc3f2f73c05f2f8f6388
[bluesky.git] / libs3-1.4 / src / simplexml.c
1 /** **************************************************************************
2  * simplexml.c
3  * 
4  * Copyright 2008 Bryan Ischo <bryan@ischo.com>
5  * 
6  * This file is part of libs3.
7  * 
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.
11  *
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.
15  *
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
19  * details.
20  *
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/>.
24  *
25  ************************************************************************** **/
26
27 #include <libxml/parser.h>
28 #include <string.h>
29 #include "simplexml.h"
30
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.
42 //
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.
46
47
48 static xmlEntityPtr saxGetEntity(void *user_data, const xmlChar *name)
49 {
50     (void) user_data;
51
52     return xmlGetPredefinedEntity(name);
53 }
54
55
56 static void saxStartElement(void *user_data, const xmlChar *nameUtf8,
57                             const xmlChar **attr)
58 {
59     (void) attr;
60
61     SimpleXml *simpleXml = (SimpleXml *) user_data;
62
63     if (simpleXml->status != S3StatusOK) {
64         return;
65     }
66     
67     // Assume that name has no non-ASCII in it
68     char *name = (char *) nameUtf8;
69
70     // Append the element to the element path
71     int len = strlen(name);
72
73     if ((simpleXml->elementPathLen + len + 1) >= 
74         (int) sizeof(simpleXml->elementPath)) {
75         // Cannot handle this element, stop!
76         simpleXml->status = S3StatusXmlParseFailure;
77         return;
78     }
79
80     if (simpleXml->elementPathLen) {
81         simpleXml->elementPath[simpleXml->elementPathLen++] = '/';
82     }
83     strcpy(&(simpleXml->elementPath[simpleXml->elementPathLen]), name);
84     simpleXml->elementPathLen += len;
85 }
86
87
88 static void saxEndElement(void *user_data, const xmlChar *name)
89 {
90     (void) name;
91
92     SimpleXml *simpleXml = (SimpleXml *) user_data;
93
94     if (simpleXml->status != S3StatusOK) {
95         return;
96     }
97
98     // Call back with 0 data
99     simpleXml->status = (*(simpleXml->callback))
100         (simpleXml->elementPath, 0, 0, simpleXml->callbackData);
101
102     while ((simpleXml->elementPathLen > 0) &&
103            (simpleXml->elementPath[simpleXml->elementPathLen] != '/')) {
104         simpleXml->elementPathLen--;
105     }
106
107     simpleXml->elementPath[simpleXml->elementPathLen] = 0;
108 }
109
110
111 static void saxCharacters(void *user_data, const xmlChar *ch, int len)
112 {
113     SimpleXml *simpleXml = (SimpleXml *) user_data;
114
115     if (simpleXml->status != S3StatusOK) {
116         return;
117     }
118
119     simpleXml->status = (*(simpleXml->callback))
120         (simpleXml->elementPath, (char *) ch, len, simpleXml->callbackData);
121 }
122
123
124 static void saxError(void *user_data, const char *msg, ...)
125 {
126     (void) msg;
127
128     SimpleXml *simpleXml = (SimpleXml *) user_data;
129
130     if (simpleXml->status != S3StatusOK) {
131         return;
132     }
133
134     simpleXml->status = S3StatusXmlParseFailure;
135 }
136
137
138 static struct _xmlSAXHandler saxHandlerG =
139 {
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
160     0, // commentSAXFunc
161     0, // warningSAXFunc
162     &saxError, // errorSAXFunc
163     &saxError, // fatalErrorSAXFunc
164     0, // getParameterEntitySAXFunc
165     &saxCharacters, // cdataBlockSAXFunc
166     0, // externalSubsetSAXFunc
167     0, // initialized
168     0, // _private
169     0, // startElementNsSAX2Func
170     0, // endElementNsSAX2Func
171     0 // xmlStructuredErrorFunc serror;
172 };
173
174 void simplexml_initialize(SimpleXml *simpleXml, 
175                           SimpleXmlCallback *callback, void *callbackData)
176 {
177     simpleXml->callback = callback;
178     simpleXml->callbackData = callbackData;
179     simpleXml->elementPathLen = 0;
180     simpleXml->status = S3StatusOK;
181     simpleXml->xmlParser = 0;
182 }
183
184
185 void simplexml_deinitialize(SimpleXml *simpleXml)
186 {
187     if (simpleXml->xmlParser) {
188         xmlFreeParserCtxt(simpleXml->xmlParser);
189     }
190 }
191
192
193 S3Status simplexml_add(SimpleXml *simpleXml, const char *data, int dataLen)
194 {
195     if (!simpleXml->xmlParser &&
196         (!(simpleXml->xmlParser = xmlCreatePushParserCtxt
197            (&saxHandlerG, simpleXml, 0, 0, 0)))) {
198         return S3StatusInternalError;
199     }
200
201     if (xmlParseChunk((xmlParserCtxtPtr) simpleXml->xmlParser, 
202                       data, dataLen, 0)) {
203         return S3StatusXmlParseFailure;
204     }
205
206     return simpleXml->status;
207 }