1 /*	$Id: axp.c 20800 2012-01-19 05:13:45Z m-oki $	*/
2 
3 /*
4  * Copyright (c) 2012, Internet Initiative Japan, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * Arms Xml Processor API routines.
32  * requires: expat
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include <sys/queue.h>
40 
41 #include <axp_extern.h>
42 #include <libarms/malloc.h>
43 #include <xml/axp_internal.h>
44 
45 AXP *
axp_create(struct axp_schema * as,const char * encoding,void * userdata,AXP_BUILDCALLBACK func)46 axp_create(struct axp_schema *as, const char *encoding,
47 	   void *userdata, AXP_BUILDCALLBACK func)
48 {
49 	AXP *obj;
50 	struct axp_schema_entry *ent;
51 	int i;
52 	char *buf;
53 
54 	/* allocate all data structures first for easy error handling */
55 	obj = MALLOC(sizeof(AXP));
56 	buf = MALLOC(AXP_BUFSIZE);
57 	ent = MALLOC(sizeof(*ent));
58 	if (obj == NULL || buf == NULL || ent == NULL)
59 		goto free_and_return;
60 
61 	obj->parser = XML_ParserCreate(encoding);
62 	if (obj->parser == NULL) {
63 		goto free_and_return;
64 	}
65 	XML_SetUserData(obj->parser, obj);
66 
67 	/* XXX? copy? */
68 	obj->schema = as;
69 
70 	obj->userdata = userdata;
71 	obj->state = AXP_PARSE_START;
72 	obj->tagstate = AXP_PARSE_TAG;
73 	obj->buf = buf;
74 	obj->len = 0;
75 	axp_register_handler(obj);
76 
77 	ent->schema = obj->schema;
78 	for (i = 0; i < AXP_MAX_HASH_ARRAY; i++) {
79 		LIST_INIT(&obj->valhash[i]);
80 	}
81 	LIST_INIT(&obj->sc_stack);
82 	LIST_INSERT_HEAD(&obj->sc_stack, ent, next);
83 
84 	return obj;
85 
86 free_and_return:
87 	if (obj != NULL)
88 		 FREE(obj);
89 	if (buf != NULL)
90 		 FREE(buf);
91 	if (ent != NULL)
92 		 FREE(ent);
93 	return NULL;
94 }
95 
96 int
axp_parse(AXP * obj,const char * buf,size_t len)97 axp_parse(AXP *obj, const char *buf, size_t len)
98 {
99 	int error;
100 
101 	if (obj->state == AXP_PARSE_END)
102 		return -1;
103 
104 	obj->state = AXP_PARSE_CONTENT;
105 	error = XML_Parse(obj->parser, buf, (int)len, 0);
106 	if (error == XML_STATUS_ERROR) {
107 #ifdef XML_DEBUG
108 		char errbuf[40 + 1];
109 		int offset, errlen;
110 
111 		fprintf(stderr, "Parse error at line %ld:\n%s\n",
112 			XML_GetCurrentLineNumber(obj->parser),
113 			XML_ErrorString(XML_GetErrorCode(obj->parser)));
114 		offset = XML_GetCurrentByteCount(obj->parser);
115 		if (offset == 0) {
116 			fprintf(stderr, "No column info.\n");
117 		}
118 		else {
119 			errlen = len - offset;
120 			if (errlen > 40)
121 				errlen = 40;
122 			memcpy(errbuf, buf + offset, errlen);
123 			errbuf[errlen] = '\0';
124 			fprintf(stderr, "Error Position: %s\n", errbuf);
125 		}
126 #endif
127 		obj->state = AXP_PARSE_ERROR;
128 		return -1;
129 	}
130 	return 0;
131 }
132 
133 int
axp_endparse(AXP * obj)134 axp_endparse(AXP *obj)
135 {
136 	int error;
137 
138 	error = XML_Parse(obj->parser, 0, 0, 1); /* Done */
139 	if (error == XML_STATUS_ERROR) {
140 #if XML_DEBUG
141 		fprintf(stderr, "Parse error at line %ld:\n%s\n",
142 			XML_GetCurrentLineNumber(obj->parser),
143 			XML_ErrorString(XML_GetErrorCode(obj->parser)));
144 #endif
145 		obj->state = AXP_PARSE_ERROR;
146 		return -1;
147 	}
148 	obj->state = AXP_PARSE_END;
149 	return 0;
150 }
151 
152 int
axp_destroy(AXP * obj)153 axp_destroy(AXP *obj)
154 {
155 	int i;
156 
157 	if (obj != 0) {
158 		struct axp_schema_entry *ent;
159 
160 		/* free expat parser */
161 		XML_ParserFree(obj->parser);
162 		/* free var and attr */
163 		for (i = 0; i < AXP_MAX_HASH_ARRAY; i++) {
164 			struct axp_val_storage *p;
165 
166 			while ((p = LIST_FIRST(&obj->valhash[i])) != 0) {
167 				struct axp_attr_entry *attr;
168 
169 				while ((attr = LIST_FIRST(&p->attr)) != 0) {
170 					LIST_REMOVE(attr, next);
171 					FREE(attr->prop);
172 					FREE(attr->value);
173 					FREE(attr);
174 				}
175 				LIST_REMOVE(p, next);
176 				if (p->type == AXP_TYPE_TEXT &&
177 				    p->value != NULL)
178 					FREE(p->value);
179 				FREE(p);
180 			}
181 		}
182 		/* free stack */
183 		while ((ent = LIST_FIRST(&obj->sc_stack)) != 0) {
184 			LIST_REMOVE(ent, next);
185 			FREE(ent);
186 		}
187 		/* free buffer */
188 		FREE(obj->buf);
189 		/* free obj */
190 		FREE(obj);
191 	}
192 	return 0;
193 }
194 
195 int
axp_get_tagstate(AXP * obj)196 axp_get_tagstate(AXP *obj)
197 {
198 	return obj->tagstate;
199 }
200 
201 int
axp_set_userdata(AXP * obj,void * userdata)202 axp_set_userdata(AXP *obj, void *userdata)
203 {
204 	obj->userdata = userdata;
205 	return 0;
206 }
207 
208 void *
axp_get_userdata(AXP * obj)209 axp_get_userdata(AXP *obj)
210 {
211 	return obj->userdata;
212 }
213 
214 static void *
axp_find_var(AXP * obj,int tag)215 axp_find_var(AXP *obj, int tag)
216 {
217 	struct axp_val_storage *p;
218 	int hash;
219 
220 	hash = tag % AXP_MAX_HASH_ARRAY;
221 	LIST_FOREACH(p, &obj->valhash[hash], next) {
222 		if (p->tag == tag)
223 			return p;
224 	}
225 	return 0;
226 }
227 
228 /* XXX int or string */
229 int
axp_refer(AXP * obj,int tagtype,void * valp)230 axp_refer(AXP *obj, int tagtype, void *valp)
231 {
232 	struct axp_val_storage *p;
233 	p = axp_find_var(obj, tagtype);
234 	if (p) {
235 		*(void **)valp = p->value;
236 		return 0;
237 	} else {
238 		return -1;
239 	}
240 }
241 
242 /*
243  * note: tagtype validation is disabled now.
244  */
245 int
axp_set(AXP * obj,int tagtype,void * valp)246 axp_set(AXP *obj, int tagtype, void *valp)
247 {
248 	return axp_set_value(obj, tagtype, valp, AXP_TYPE_TEXT);
249 }
250 
251 void
axp_reset(AXP * obj,int tagtype)252 axp_reset(AXP *obj, int tagtype)
253 {
254 	struct axp_val_storage *p;
255 
256 	p = axp_find_var(obj, tagtype);
257 	if (p) {
258 		struct axp_attr_entry *attr;
259 
260 		/* reuse p, clear all attribute */
261 		while ((attr = LIST_FIRST(&p->attr)) != 0) {
262 			LIST_REMOVE(attr, next);
263 			FREE(attr->prop);
264 			FREE(attr->value);
265 			FREE(attr);
266 		}
267 	}
268 }
269 
270 int
axp_set_value(AXP * obj,int tagtype,void * valp,int type)271 axp_set_value(AXP *obj, int tagtype, void *valp, int type)
272 {
273 	struct axp_val_storage *p;
274 
275 	p = axp_find_var(obj, tagtype);
276 	if (p) {
277 		if (p->type == AXP_TYPE_TEXT) {
278 			if (p->value)
279 				FREE(p->value);
280 			if (valp)
281 				p->value = STRDUP(valp);
282 			else
283 				p->value = valp;
284 		} else {
285 			p->value = valp;
286 		}
287 	} else {
288 		int hash;
289 
290 		hash = tagtype % AXP_MAX_HASH_ARRAY;
291 		p = MALLOC(sizeof(struct axp_val_storage));
292 		p->tag = tagtype;
293 		p->type = type;
294 		if (p->type == AXP_TYPE_TEXT && valp != NULL) {
295 			p->value = STRDUP(valp);
296 		} else {
297 			p->value = valp;
298 		}
299 		LIST_INIT(&p->attr);
300 		LIST_INSERT_HEAD(&obj->valhash[hash], p, next);
301 	}
302 	return 0;
303 }
304 
305 int
axp_set_attr(AXP * obj,int tagtype,const char * prop,const char * value)306 axp_set_attr(AXP *obj, int tagtype, const char *prop, const char *value)
307 {
308 	struct axp_val_storage *p;
309 	struct axp_attr_entry *attr;
310 
311 	p = axp_find_var(obj, tagtype);
312 	if (!p) {
313 		/* subset case, or empty */
314 		axp_set(obj, tagtype, 0);
315 		/* again */
316 		p = axp_find_var(obj, tagtype);
317 	}
318 	LIST_FOREACH(attr, &p->attr, next) {
319 		if (!strcmp(attr->prop, prop)) {
320 			/* found, overwrite value */
321 			FREE(attr->value);
322 			attr->value = STRDUP(value);
323 			return 0;
324 		}
325 	}
326 	/* not found, add new entry */
327 	attr = MALLOC(sizeof(*attr));
328 	attr->prop = STRDUP(prop);
329 	attr->value = STRDUP(value);
330 	LIST_INSERT_HEAD(&p->attr, attr, next);
331 	return 0;
332 }
333 
334 const char *
axp_find_attr(AXP * obj,int tagtype,char * prop)335 axp_find_attr(AXP *obj, int tagtype, char *prop)
336 {
337 	struct axp_val_storage *p;
338 	struct axp_attr_entry *attr;
339 
340 	p = axp_find_var(obj, tagtype);
341 	if (!p) {
342 		/* tag don't have any attribute */
343 		return 0;
344 	}
345 	LIST_FOREACH(attr, &p->attr, next) {
346 		if (!strcmp(attr->prop, prop)) {
347 			return attr->value;
348 		}
349 	}
350 	/* attribute not found */
351 	return 0;
352 }
353