]> mj.ucw.cz Git - libucw.git/blob - sherlock/xml/common.h
XML: The great reorganization... several improvements in the iface,
[libucw.git] / sherlock / xml / common.h
1 /*
2  *      Sherlock Library -- A simple XML parser
3  *
4  *      (c) 2007 Pavel Charvat <pchar@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #ifndef _SHERLOCK_XML_COMMON_H
11 #define _SHERLOCK_XML_COMMON_H
12
13 #include "sherlock/xml/xml.h"
14 #include "sherlock/xml/dtd.h"
15
16 /*** Debugging ***/
17
18 #ifdef LOCAL_DEBUG
19 #define TRACE(c, f, p...) do { DBG("XML %u: " f, xml_row(c), ##p); } while(0)
20 #else
21 #define TRACE(c, f, p...) do {} while(0)
22 #endif
23
24 /*** Error handling ***/
25
26 void NONRET xml_throw(struct xml_context *ctx);
27 void xml_warn(struct xml_context *ctx, const char *format, ...);
28 void xml_error(struct xml_context *ctx, const char *format, ...);
29 void NONRET xml_fatal(struct xml_context *ctx, const char *format, ...);
30
31 /*** Memory management ***/
32
33 struct xml_stack {
34   struct xml_stack *next;
35   struct mempool_state state;
36   uns flags;
37 };
38
39 static inline void *
40 xml_do_push(struct xml_context *ctx, uns size)
41 {
42   /* Saves ctx->stack and ctx->flags state */
43   struct mempool_state state;
44   mp_save(ctx->stack, &state);
45   struct xml_stack *s = mp_alloc(ctx->stack, size);
46   s->state = state;
47   s->flags = ctx->flags;
48   s->next = ctx->stack_list;
49   ctx->stack_list = s;
50   return s;
51 }
52
53 static inline void
54 xml_do_pop(struct xml_context *ctx, struct xml_stack *s)
55 {
56   /* Restore ctx->stack and ctx->flags state */
57   ctx->stack_list = s->next;
58   ctx->flags = s->flags;
59   mp_restore(ctx->stack, &s->state);
60 }
61
62 static inline void
63 xml_push(struct xml_context *ctx)
64 {
65   TRACE(ctx, "push");
66   xml_do_push(ctx, sizeof(struct xml_stack));
67 }
68
69 static inline void
70 xml_pop(struct xml_context *ctx)
71 {
72   TRACE(ctx, "pop");
73   ASSERT(ctx->stack_list);
74   xml_do_pop(ctx, ctx->stack_list);
75 }
76
77 struct xml_dom_stack {
78   struct xml_stack stack;
79   struct mempool_state state;
80 };
81
82 static inline struct xml_node *
83 xml_push_dom(struct xml_context *ctx)
84 {
85   /* Create a new DOM node */
86   TRACE(ctx, "push_dom");
87   struct xml_dom_stack *s = xml_do_push(ctx, sizeof(*s));
88   mp_save(ctx->pool, &s->state);
89   struct xml_node *n = mp_alloc(ctx->pool, sizeof(*n));
90   if (n->parent = ctx->node)
91     clist_add_tail(&n->parent->sons, &n->n);
92   return ctx->node = n;
93 }
94
95 static inline void
96 xml_pop_dom(struct xml_context *ctx, uns free)
97 {
98   /* Leave DOM subtree */
99   TRACE(ctx, "pop_dom");
100   ASSERT(ctx->node);
101   struct xml_node *p = ctx->node->parent;
102   struct xml_dom_stack *s = (void *)ctx->stack_list;
103   if (free)
104     {
105       /* See xml_pop_element() for cleanup of attribute hash table */
106       if (p)
107         clist_remove(&ctx->node->n);
108       mp_restore(ctx->pool, &s->state);
109     }
110   ctx->node = p;
111   xml_do_pop(ctx, &s->stack);
112 }
113
114 #define XML_HASH_HDR_SIZE ALIGN_TO(sizeof(void *), CPU_STRUCT_ALIGN)
115 #define XML_HASH_GIVE_ALLOC struct HASH_PREFIX(table); \
116   static inline void *HASH_PREFIX(alloc)(struct HASH_PREFIX(table) *t, uns size) \
117   { return mp_alloc(*(void **)((void *)t - XML_HASH_HDR_SIZE), size); } \
118   static inline void HASH_PREFIX(free)(struct HASH_PREFIX(table) *t UNUSED, void *p UNUSED) {}
119
120 void *xml_hash_new(struct mempool *pool, uns size);
121
122 static inline void
123 xml_start_chars(struct xml_context *ctx)
124 {
125   struct fastbuf *fb = &ctx->chars;
126   fb->bstop = fb->bptr = fb->buffer = mp_start_noalign(ctx->pool, 1);
127   fb->bufend = fb->buffer + mp_avail(ctx->pool);
128 }
129
130 static inline char *
131 xml_end_chars(struct xml_context *ctx, uns *len)
132 {
133   struct fastbuf *fb = &ctx->chars;
134   uns l = fb->bufend - fb->buffer;
135   if (fb->bptr == fb->bufend)
136     fb->bptr = mp_expand(ctx->pool) + l;
137   *fb->bptr = 0;
138   char *c = mp_end(ctx->pool, fb->bptr + 1);
139   fb->bptr = fb->bstop = fb->buffer = fb->bufend = NULL;
140   *len = l;
141   return c;
142 }
143
144 /*** Reading of document/external entities ***/
145
146 #define XML_BUF_SIZE 32                                 /* At least 8 -- hardcoded */
147
148 struct xml_source {
149   struct xml_source *next;                              /* Link list of pending fastbufs (xml_context.sources) */
150   struct fastbuf *fb;                                   /* Source fastbuf */
151   struct fastbuf *wrapped_fb;                           /* Original wrapped fastbuf (needed for cleanup) */
152   struct fastbuf wrap_fb;                               /* Fbmem wrapper */
153   u32 buf[2 * XML_BUF_SIZE];                            /* Read buffer with Unicode values and categories */
154   u32 *bptr, *bstop;                                    /* Current state of the buffer */
155   uns row;                                              /* File position */
156   char *expected_encoding;                              /* Initial encoding before any transformation has been made (expected in XMLDecl/TextDecl) */
157   char *fb_encoding;                                    /* Encoding of the source fastbuf */
158   char *decl_encoding;                                  /* Encoding read from the XMLDecl/TextDecl */
159   uns refill_cat1;                                      /* Character categories, which should be directly passed to the buffer */
160   uns refill_cat2;                                      /* Character categories, which should be processed as newlines (possibly in some built-in sequences) */
161   void (*refill)(struct xml_context *ctx);              /* Callback to decode source characters to the buffer */
162   unsigned short *refill_in_to_x;                       /* Libcharset input table */
163   uns saved_depth;                                      /* Saved ctx->depth */
164 };
165
166 void NONRET xml_fatal_nested(struct xml_context *ctx);
167
168 static inline void
169 xml_inc(struct xml_context *ctx)
170 {
171   /* Called after the first character of a block */
172   TRACE(ctx, "inc");
173   ctx->depth++;
174 }
175
176 static inline void
177 xml_dec(struct xml_context *ctx)
178 {
179   /* Called after the last character of a block */
180   TRACE(ctx, "dec");
181   if (unlikely(!ctx->depth--))
182     xml_fatal_nested(ctx);
183 }
184
185 #include "obj/sherlock/xml/unicat.h"
186
187 static inline uns
188 xml_char_cat(uns c)
189 {
190   if (c < 0x10000)
191     return 1U << xml_char_tab1[(c & 0xff) + xml_char_tab2[c >> 8]];
192   else if (likely(c < 0x110000))
193     return 1U << xml_char_tab3[c >> 16];
194   else
195     return 1;
196 }
197
198 static inline uns
199 xml_ascii_cat(uns c)
200 {
201   return xml_char_tab1[c];
202 }
203
204 struct xml_source *xml_push_source(struct xml_context *ctx, uns flags);
205 void xml_push_entity(struct xml_context *ctx, struct xml_dtd_ent *ent);
206
207 void xml_refill(struct xml_context *ctx);
208
209 static inline uns
210 xml_peek_char(struct xml_context *ctx)
211 {
212   if (ctx->bptr == ctx->bstop)
213     xml_refill(ctx);
214   return ctx->bptr[0];
215 }
216
217 static inline uns
218 xml_peek_cat(struct xml_context *ctx)
219 {
220   if (ctx->bptr == ctx->bstop)
221     xml_refill(ctx);
222   return ctx->bptr[1];
223 }
224
225 static inline uns
226 xml_get_char(struct xml_context *ctx)
227 {
228   uns c = xml_peek_char(ctx);
229   ctx->bptr += 2;
230   return c;
231 }
232
233 static inline uns
234 xml_get_cat(struct xml_context *ctx)
235 {
236   uns c = xml_peek_cat(ctx);
237   ctx->bptr += 2;
238   return c;
239 }
240
241 static inline uns
242 xml_last_char(struct xml_context *ctx)
243 {
244   return ctx->bptr[-2];
245 }
246
247 static inline uns
248 xml_last_cat(struct xml_context *ctx)
249 {
250   return ctx->bptr[-1];
251 }
252
253 static inline uns
254 xml_skip_char(struct xml_context *ctx)
255 {
256   uns c = ctx->bptr[0];
257   ctx->bptr += 2;
258   return c;
259 }
260
261 static inline uns
262 xml_unget_char(struct xml_context *ctx)
263 {
264   return *(ctx->bptr -= 2);
265 }
266
267 void xml_sources_cleanup(struct xml_context *ctx);
268
269 /*** Parsing ***/
270
271 void NONRET xml_fatal_expected(struct xml_context *ctx, uns c);
272 void NONRET xml_fatal_expected_white(struct xml_context *ctx);
273 void NONRET xml_fatal_expected_quot(struct xml_context *ctx);
274
275 static inline uns
276 xml_parse_white(struct xml_context *ctx, uns mandatory)
277 {
278   /* mandatory=1 -> S ::= (#x20 | #x9 | #xD | #xA)+
279    * mandatory=0 -> S? */
280   uns cnt = 0;
281   while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
282     {
283       xml_skip_char(ctx);
284       cnt++;
285     }
286   if (unlikely(mandatory && !cnt))
287     xml_fatal_expected_white(ctx);
288   return cnt;
289 }
290
291 static inline void
292 xml_parse_char(struct xml_context *ctx, uns c)
293 {
294   /* Consumes a given Unicode character */
295   if (unlikely(c != xml_get_char(ctx)))
296     xml_fatal_expected(ctx, c);
297 }
298
299 static inline void
300 xml_parse_seq(struct xml_context *ctx, const char *seq)
301 {
302   /* Consumes a given sequence of ASCII characters */
303   while (*seq)
304     xml_parse_char(ctx, *seq++);
305 }
306
307 void xml_parse_eq(struct xml_context *ctx);
308
309 static inline uns
310 xml_parse_quote(struct xml_context *ctx)
311 {
312   /* "'" | '"' */
313   uns c = xml_get_char(ctx);
314   if (unlikely(c != '\'' && c != '\"'))
315     xml_fatal_expected_quot(ctx);
316   return c;
317 }
318
319 char *xml_parse_name(struct xml_context *ctx, struct mempool *pool);
320 void xml_skip_name(struct xml_context *ctx);
321 char *xml_parse_nmtoken(struct xml_context *ctx, struct mempool *pool);
322
323 char *xml_parse_system_literal(struct xml_context *ctx, struct mempool *pool);
324 char *xml_parse_pubid_literal(struct xml_context *ctx, struct mempool *pool);
325
326 uns xml_parse_char_ref(struct xml_context *ctx);
327 void xml_parse_ref(struct xml_context *ctx);
328 void xml_parse_pe_ref(struct xml_context *ctx);
329
330 char *xml_parse_attr_value(struct xml_context *ctx, struct xml_dtd_attr *attr);
331
332 void xml_parse_notation_decl(struct xml_context *ctx);
333 void xml_parse_entity_decl(struct xml_context *ctx);
334 void xml_parse_element_decl(struct xml_context *ctx);
335 void xml_parse_attr_list_decl(struct xml_context *ctx);
336
337 void xml_push_comment(struct xml_context *ctx);
338 void xml_pop_comment(struct xml_context *ctx);
339 void xml_skip_comment(struct xml_context *ctx);
340
341 void xml_push_pi(struct xml_context *ctx);
342 void xml_pop_pi(struct xml_context *ctx);
343 void xml_skip_pi(struct xml_context *ctx);
344
345 void xml_attrs_table_init(struct xml_context *ctx);
346 void xml_attrs_table_cleanup(struct xml_context *ctx);
347
348 #endif