genx4r 0.04

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("genx4r");
4
+
5
+ create_makefile("genx4r");
@@ -0,0 +1,1940 @@
1
+ /*
2
+ * Copyright (c) 2004 by Tim Bray and Sun Microsystems. For copying
3
+ * permission, see http://www.tbray.org/ongoing/genx/COPYING
4
+ */
5
+
6
+ #define GENX_VERSION "beta5"
7
+
8
+ #include <stdlib.h>
9
+ #include <string.h>
10
+
11
+ #include "genx.h"
12
+
13
+ #define Boolean int
14
+ #define True 1
15
+ #define False 0
16
+ #define STRLEN_XMLNS_COLON 6
17
+
18
+
19
+ /*******************************
20
+ * writer state
21
+ */
22
+ typedef enum
23
+ {
24
+ SEQUENCE_NO_DOC,
25
+ SEQUENCE_PRE_DOC,
26
+ SEQUENCE_POST_DOC,
27
+ SEQUENCE_START_TAG,
28
+ SEQUENCE_ATTRIBUTES,
29
+ SEQUENCE_CONTENT
30
+ } writerSequence;
31
+
32
+ /*******************************
33
+ * generic pointer list
34
+ */
35
+ typedef struct
36
+ {
37
+ genxWriter writer;
38
+ int count;
39
+ int space;
40
+ void * * pointers;
41
+ } plist;
42
+
43
+ /*******************************
44
+ * text collector, for attribute values
45
+ */
46
+ typedef struct
47
+ {
48
+ utf8 buf;
49
+ int used;
50
+ int space;
51
+ } collector;
52
+
53
+ /*******************************
54
+ * Structs with opaquely-exposed handles
55
+ */
56
+
57
+ /*
58
+ * This one's tricky, to handle stacking namespaces
59
+ * 'declaration' is the current attribute which would be used to
60
+ * declare the currently-effective prefix
61
+ * 'defDeclaration' is a appropriate declaration when this is being
62
+ * used with the default prefix as passed to genxDeclareNamespace
63
+ * baroque is true if this namespace has been used with more than one
64
+ * prefix, or is the default namespace but has been unset
65
+ */
66
+ struct genxNamespace_rec
67
+ {
68
+ genxWriter writer;
69
+ utf8 name;
70
+ int declCount;
71
+ Boolean baroque;
72
+ genxAttribute declaration;
73
+ genxAttribute defaultDecl;
74
+ };
75
+
76
+ struct genxElement_rec
77
+ {
78
+ genxWriter writer;
79
+ utf8 type;
80
+ genxNamespace ns;
81
+ };
82
+
83
+ typedef enum
84
+ {
85
+ ATTR_NSDECL,
86
+ ATTR_NAKED,
87
+ ATTR_PREFIXED
88
+ } attrType;
89
+
90
+ struct genxAttribute_rec
91
+ {
92
+ genxWriter writer;
93
+ utf8 name;
94
+ genxNamespace ns;
95
+ collector value;
96
+ int provided; /* provided for current element? */
97
+ attrType atype;
98
+ };
99
+
100
+ /*******************************
101
+ * genx's sandbox
102
+ */
103
+ struct genxWriter_rec
104
+ {
105
+ FILE * file;
106
+ genxSender * sender;
107
+ genxStatus status;
108
+ writerSequence sequence;
109
+ char xmlChars[0x10000];
110
+ void * userData;
111
+ int nextPrefix;
112
+ utf8 empty;
113
+ Boolean defaultNsDeclared;
114
+ genxAttribute xmlnsEquals;
115
+ genxElement nowStarting;
116
+ plist namespaces;
117
+ plist elements;
118
+ plist attributes;
119
+ plist prefixes;
120
+ plist stack;
121
+ struct genxAttribute_rec arec;
122
+ char * etext[100];
123
+ void * (* alloc)(void * userData, int bytes);
124
+ void (* dealloc)(void * userData, void * data);
125
+ };
126
+
127
+ /*******************************
128
+ * Forward declarations
129
+ */
130
+ static genxAttribute declareAttribute(genxWriter w, genxNamespace ns,
131
+ constUtf8 name, constUtf8 valuestr,
132
+ genxStatus * statusP);
133
+ static genxStatus addNamespace(genxNamespace ns, utf8 prefix);
134
+ static genxStatus unsetDefaultNamespace(genxWriter w);
135
+ static genxStatus addAttribute(genxAttribute a, constUtf8 valuestr);
136
+ void genxSetCharProps(char * p);
137
+
138
+ /*******************************
139
+ * End of declarations
140
+ */
141
+
142
+ /*******************************
143
+ * private memory utilities
144
+ */
145
+ static void * allocate(genxWriter w, int bytes)
146
+ {
147
+ if (w->alloc)
148
+ return (void *) (*w->alloc)(w->userData, bytes);
149
+ else
150
+ return (void *) malloc(bytes);
151
+ }
152
+
153
+ static void deallocate(genxWriter w, void * data)
154
+ {
155
+ if (w->dealloc)
156
+ (*w->dealloc)(w->userData, data);
157
+ else if (w->alloc == NULL)
158
+ free(data);
159
+ }
160
+
161
+ static utf8 copy(genxWriter w, constUtf8 from)
162
+ {
163
+ utf8 temp;
164
+
165
+ if ((temp = (utf8) allocate(w, strlen((const char *) from) + 1)) == NULL)
166
+ return NULL;
167
+ strcpy((char *) temp, (const char *) from);
168
+ return temp;
169
+ }
170
+
171
+ static genxStatus initCollector(genxWriter w, collector * c)
172
+ {
173
+ c->space = 100;
174
+ if ((c->buf = (utf8) allocate(w, c->space)) == NULL)
175
+ return GENX_ALLOC_FAILED;
176
+ c->used = 0;
177
+ return GENX_SUCCESS;
178
+ }
179
+
180
+ static genxStatus growCollector(genxWriter w, collector * c, int size)
181
+ {
182
+ utf8 newSpace;
183
+
184
+ c->space = size * 2;
185
+ if ((newSpace = (utf8) allocate(w, c->space)) == NULL)
186
+ return GENX_ALLOC_FAILED;
187
+
188
+ strncpy((char *) newSpace, (const char *) c->buf, c->used);
189
+ newSpace[c->used] = 0;
190
+ deallocate(w, c->buf);
191
+ c->buf = newSpace;
192
+ return GENX_SUCCESS;
193
+ }
194
+
195
+ static void startCollect(collector * c)
196
+ {
197
+ c->used = 0;
198
+ }
199
+ static void endCollect(collector * c)
200
+ {
201
+ c->buf[c->used] = 0;
202
+ }
203
+
204
+ static genxStatus collectString(genxWriter w, collector * c, constUtf8 string)
205
+ {
206
+ int sl = strlen((const char *) string);
207
+
208
+ if (sl >= c->space)
209
+ if ((w->status = growCollector(w, c, sl)) != GENX_SUCCESS)
210
+ return GENX_ALLOC_FAILED;
211
+
212
+ strcpy((char *) c->buf, (const char *) string);
213
+ return GENX_SUCCESS;
214
+ }
215
+
216
+ #define collectPiece(w,c,d,size) {if (((c)->used+(size))>=(c)->space){if (((w)->status=growCollector(w,c,(c)->used+(size)))!=GENX_SUCCESS) return (w)->status;}strncpy((char *)(c)->buf+(c)->used,d,size);(c)->used+=size;}
217
+
218
+ /*******************************
219
+ * private list utilities
220
+ */
221
+ static genxStatus initPlist(genxWriter w, plist * pl)
222
+ {
223
+ pl->writer = w;
224
+ pl->count = 0;
225
+ pl->space = 10;
226
+ pl->pointers = (void * *) allocate(w, pl->space * sizeof(void *));
227
+ if (pl->pointers == NULL)
228
+ return GENX_ALLOC_FAILED;
229
+
230
+ return GENX_SUCCESS;
231
+ }
232
+
233
+ /*
234
+ * make room in a plist
235
+ */
236
+ static Boolean checkExpand(plist * pl)
237
+ {
238
+ void * * newlist;
239
+ int i;
240
+
241
+ if (pl->count < pl->space)
242
+ return True;
243
+
244
+ pl->space *= 2;
245
+ newlist = (void * *) allocate(pl->writer, pl->space * sizeof(void *));
246
+ if (newlist == NULL)
247
+ return False;
248
+ for (i = 0; i < pl->count; i++)
249
+ newlist[i] = pl->pointers[i];
250
+ deallocate(pl->writer, pl->pointers);
251
+ pl->pointers = newlist;
252
+
253
+ return True;
254
+ }
255
+
256
+ /*
257
+ * stick something on the end of a plist
258
+ */
259
+ static genxStatus listAppend(plist * pl, void * pointer)
260
+ {
261
+ if (!checkExpand(pl))
262
+ return GENX_ALLOC_FAILED;
263
+
264
+ pl->pointers[pl->count++] = pointer;
265
+ return GENX_SUCCESS;
266
+ }
267
+
268
+ /*
269
+ * insert in place, shuffling up
270
+ */
271
+ static genxStatus listInsert(plist * pl, void * pointer, int at)
272
+ {
273
+ int i;
274
+
275
+ if (!checkExpand(pl))
276
+ return GENX_ALLOC_FAILED;
277
+
278
+ for (i = pl->count; i > at; i--)
279
+ pl->pointers[i] = pl->pointers[i - 1];
280
+ pl->count++;
281
+
282
+ pl->pointers[at] = pointer;
283
+ return GENX_SUCCESS;
284
+ }
285
+
286
+ /*******************************
287
+ * list lookups
288
+ */
289
+
290
+ static genxNamespace findNamespace(plist * pl, constUtf8 uri)
291
+ {
292
+ int i;
293
+ genxNamespace * nn = (genxNamespace *) pl->pointers;
294
+
295
+ for (i = 0; i < pl->count; i++)
296
+ if (strcmp((char *) uri, (const char *) nn[i]->name) == 0)
297
+ return nn[i];
298
+
299
+ return NULL;
300
+ }
301
+
302
+ static genxElement findElement(plist * pl, constUtf8 xmlns, constUtf8 type)
303
+ {
304
+ int i;
305
+ genxElement * ee = (genxElement *) pl->pointers;
306
+
307
+ for (i = 0; i < pl->count; i++)
308
+ {
309
+ if (xmlns == NULL)
310
+ {
311
+ if (ee[i]->ns == NULL && strcmp((const char *) type,
312
+ (const char *) ee[i]->type) == 0)
313
+ return ee[i];
314
+ }
315
+ else
316
+ {
317
+ if (ee[i]->ns != NULL &&
318
+ strcmp((const char *) xmlns, (const char *) ee[i]->ns->name) == 0 &&
319
+ strcmp((const char *) type, (const char *) ee[i]->type) == 0)
320
+ return ee[i];
321
+ }
322
+ }
323
+
324
+ return NULL;
325
+ }
326
+
327
+ /*
328
+ * store & intern a prefix, after giving it the
329
+ * "xmlns:" prefix. Don't allow storing the same one twice unless 'force'
330
+ * is set.
331
+ */
332
+ static utf8 storePrefix(genxWriter w, constUtf8 prefix, Boolean force)
333
+ {
334
+ int high, low;
335
+ utf8 * pp = (utf8 *) w->prefixes.pointers;
336
+ unsigned char buf[1024];
337
+
338
+ if (prefix[0] == 0)
339
+ prefix = (utf8) "xmlns";
340
+ else
341
+ {
342
+ sprintf((char *) buf, "xmlns:%s", prefix);
343
+ prefix = buf;
344
+ }
345
+
346
+ high = w->prefixes.count; low = -1;
347
+ while (high - low > 1)
348
+ {
349
+ int probe = (high + low) / 2;
350
+ if (strcmp((const char *) prefix, (const char *) pp[probe]) < 0)
351
+ high = probe;
352
+ else
353
+ low = probe;
354
+ }
355
+
356
+ /* already there? */
357
+ if (low != -1 && strcmp((const char *) prefix, (const char *) pp[low]) == 0)
358
+ {
359
+ if (force)
360
+ return pp[low];
361
+
362
+ w->status = GENX_DUPLICATE_PREFIX;
363
+ return NULL;
364
+ }
365
+
366
+ /* copy & insert */
367
+ if ((prefix = copy(w, prefix)) == NULL)
368
+ {
369
+ w->status = GENX_ALLOC_FAILED;
370
+ return NULL;
371
+ }
372
+
373
+ w->status = listInsert(&w->prefixes, (void *) prefix, high);
374
+ if (w->status != GENX_SUCCESS)
375
+ return NULL;
376
+
377
+ return (utf8) prefix;
378
+ }
379
+
380
+ /*******************************
381
+ * UTF8 bit-banging
382
+ */
383
+
384
+ /*
385
+ * Retrieve the character pointed at, and advance the pointer; return -1 on
386
+ * error
387
+ */
388
+ int genxNextUnicodeChar(constUtf8 * sp)
389
+ {
390
+ utf8 s = (utf8) *sp;
391
+ int c;
392
+
393
+ if (*s == 0)
394
+ return -1;
395
+
396
+ if (*s < 0x80)
397
+ c = *s++;
398
+
399
+ /* all this encoding sanity-checking taken from section 3.10 of Unicode 4 */
400
+ else if (*s < 0xc2)
401
+ goto malformed;
402
+
403
+ /* 2-byte encodings, first byte c2 .. df */
404
+ else if (*s < 0xe0)
405
+ {
406
+ c = (*s++ & 0x1f) << 6;
407
+
408
+ /*
409
+ * for this common idiom, if ((c & 0xc0) != 0x80) is slightly faster
410
+ * on MacOS (PPC)
411
+ */
412
+ if (*s < 0x80 || *s > 0xbf)
413
+ goto malformed;
414
+
415
+ c |= *s++ & 0x3f;
416
+ }
417
+
418
+ /* 3-byte encodings, first byte e0 .. ef */
419
+ else if (*s < 0xf0)
420
+ {
421
+ int b0 = *s;
422
+ c = (*s++ & 0x0f) << 12;
423
+
424
+ if ((b0 == 0xe0 && (*s < 0xa0 || *s > 0xbf)) ||
425
+ (b0 < 0xed && (*s < 0x80 || *s > 0xbf)) ||
426
+ (b0 == 0xed && (*s < 0x80 || *s > 0x9f)) ||
427
+ (b0 > 0xed && (*s < 0x80 || *s > 0xbf)))
428
+ goto malformed;
429
+
430
+ c |= (*s++ & 0x3f) << 6;
431
+
432
+ if (*s < 0x80 || *s > 0xbf)
433
+ goto malformed;
434
+
435
+ c |= *s++ & 0x3f;
436
+ }
437
+
438
+ /* 4-byte encodings, first byte f0 .. f4 */
439
+ else if (*s < 0xf5)
440
+ {
441
+ int b0 = *s;
442
+ c = (*s++ & 0x07) << 18;
443
+
444
+ if ((b0 == 0xf0 && (*s < 0x90 || *s > 0xbf)) ||
445
+ (b0 < 0xf4 && (*s < 0x80 || *s > 0xbf)) ||
446
+ (b0 >= 0xf4 && (*s < 0x80 || *s > 0x8f)))
447
+ goto malformed;
448
+
449
+ c |= (*s++ & 0x3f) << 12;
450
+
451
+ if (*s < 0x80 || *s > 0xbf)
452
+ goto malformed;
453
+
454
+ c |= (*s++ & 0x3f) << 6;
455
+
456
+ if (*s < 0x80 || *s > 0xbf)
457
+ goto malformed;
458
+
459
+ c |= *s++ & 0x3f;
460
+ }
461
+ else
462
+ goto malformed;
463
+
464
+ *sp = s;
465
+ return c;
466
+
467
+ /*
468
+ * this is needed by scrubText, which wants to get the pointer moved
469
+ * past the problem area.
470
+ */
471
+ malformed:
472
+ if (*s)
473
+ ++s;
474
+ *sp = s;
475
+ return -1;
476
+ }
477
+
478
+ static Boolean isXMLChar(genxWriter w, int c)
479
+ {
480
+ if (c < 0)
481
+ return False;
482
+ else if (c < 0x10000)
483
+ return (int) w->xmlChars[c];
484
+ else
485
+ return (c <= 0x10ffff);
486
+ }
487
+
488
+ static Boolean isLetter(genxWriter w, int c)
489
+ {
490
+ if (c < 0 || c > 0xffff)
491
+ return False;
492
+ else
493
+ return w->xmlChars[c] & GENX_LETTER;
494
+ }
495
+
496
+ static Boolean isNameChar(genxWriter w, int c)
497
+ {
498
+ if (c < 0 || c > 0xffff)
499
+ return False;
500
+ else
501
+ return w->xmlChars[c] & GENX_NAMECHAR;
502
+ }
503
+
504
+ /*******************************
505
+ * Constructors, setters/getters
506
+ */
507
+
508
+ /*
509
+ * Construct a new genxWriter
510
+ */
511
+ genxWriter genxNew(void * (* alloc)(void * userData, int bytes),
512
+ void (* dealloc)(void * userData, void * data),
513
+ void * userData)
514
+ {
515
+ genxWriter w;
516
+ genxNamespace xml;
517
+
518
+ if (alloc)
519
+ w = (genxWriter) (*alloc)(userData, sizeof(struct genxWriter_rec));
520
+ else
521
+ w = (genxWriter) malloc(sizeof(struct genxWriter_rec));
522
+
523
+ if (w == NULL)
524
+ return NULL;
525
+
526
+ w->status = GENX_SUCCESS;
527
+ w->alloc = alloc;
528
+ w->dealloc = dealloc;
529
+ w->userData = userData;
530
+ w->sequence = SEQUENCE_NO_DOC;
531
+
532
+ if (initPlist(w, &w->namespaces) != GENX_SUCCESS ||
533
+ initPlist(w, &w->elements) != GENX_SUCCESS ||
534
+ initPlist(w, &w->attributes) != GENX_SUCCESS ||
535
+ initPlist(w, &w->prefixes) != GENX_SUCCESS ||
536
+ initPlist(w, &w->stack) != GENX_SUCCESS)
537
+ return NULL;
538
+
539
+ if ((w->status = initCollector(w, &w->arec.value)) != GENX_SUCCESS)
540
+ return NULL;
541
+
542
+ if ((w->empty = copy(w, (utf8) "")) == NULL)
543
+ {
544
+ w->status = GENX_ALLOC_FAILED;
545
+ return NULL;
546
+ }
547
+
548
+ w->xmlnsEquals = declareAttribute(w, NULL, (utf8) "xmlns", NULL, &w->status);
549
+ if (w->xmlnsEquals == NULL || w->status != GENX_SUCCESS)
550
+ return NULL;
551
+ w->defaultNsDeclared = False;
552
+
553
+ w->nextPrefix = 1;
554
+
555
+ genxSetCharProps(w->xmlChars);
556
+
557
+ w->etext[GENX_SUCCESS] = "Success";
558
+ w->etext[GENX_BAD_UTF8] = "Bad UTF8";
559
+ w->etext[GENX_NON_XML_CHARACTER] = "Non XML Character";
560
+ w->etext[GENX_BAD_NAME] = "Bad NAME";
561
+ w->etext[GENX_ALLOC_FAILED] = "Memory allocation failed";
562
+ w->etext[GENX_BAD_NAMESPACE_NAME] = "Bad namespace name";
563
+ w->etext[GENX_INTERNAL_ERROR] = "Internal error";
564
+ w->etext[GENX_DUPLICATE_PREFIX] = "Duplicate prefix";
565
+ w->etext[GENX_SEQUENCE_ERROR] = "Call out of sequence";
566
+ w->etext[GENX_NO_START_TAG] = "No Start-tag for EndElement call";
567
+ w->etext[GENX_IO_ERROR] = "I/O error";
568
+ w->etext[GENX_MISSING_VALUE] = "Missing attribute value";
569
+ w->etext[GENX_MALFORMED_COMMENT] = "Malformed comment body";
570
+ w->etext[GENX_MALFORMED_PI] = "?> in PI";
571
+ w->etext[GENX_XML_PI_TARGET] = "Target of PI matches [xX][mM][lL]";
572
+ w->etext[GENX_DUPLICATE_ATTRIBUTE] =
573
+ "Same attribute specified more than once";
574
+ w->etext[GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE] =
575
+ "Attribute cannot be in default namespace";
576
+ w->etext[GENX_DUPLICATE_NAMESPACE] =
577
+ "Declared namespace twice with different prefixes on one element.";
578
+ w->etext[GENX_BAD_DEFAULT_DECLARATION] =
579
+ "Declared a default namespace on an element which is in no namespace";
580
+
581
+ /* the xml: namespace is pre-wired */
582
+ xml = genxDeclareNamespace(w, (utf8) "http://www.w3.org/XML/1998/namespace",
583
+ (utf8) "xml", &w->status);
584
+ if (xml == NULL)
585
+ return NULL;
586
+ xml->declCount = 1;
587
+ xml->declaration = xml->defaultDecl;
588
+
589
+ return w;
590
+ }
591
+
592
+ /*
593
+ * get/set userData
594
+ */
595
+ void genxSetUserData(genxWriter w, void * userData)
596
+ {
597
+ w->userData = userData;
598
+ }
599
+ void * genxGetUserData(genxWriter w)
600
+ {
601
+ return w->userData;
602
+ }
603
+
604
+ /*
605
+ * get/set allocator
606
+ */
607
+ void genxSetAlloc(genxWriter w, void * (* alloc)(void * userData, int bytes))
608
+ {
609
+ w->alloc = alloc;
610
+ }
611
+ void genxSetDealloc(genxWriter w,
612
+ void (* dealloc)(void * userData, void * data))
613
+ {
614
+ w->dealloc = dealloc;
615
+ }
616
+ void * (* genxGetAlloc(genxWriter w))(void * userData, int bytes)
617
+ {
618
+ return w->alloc;
619
+ }
620
+ void (* genxGetDealloc(genxWriter w))(void * userData, void * data)
621
+ {
622
+ return w->dealloc;
623
+ }
624
+
625
+ /*
626
+ * Clean up
627
+ */
628
+ void genxDispose(genxWriter w)
629
+ {
630
+ int i;
631
+ genxNamespace * nn = (genxNamespace *) w->namespaces.pointers;
632
+ genxElement * ee = (genxElement *) w->elements.pointers;
633
+ genxAttribute * aa = (genxAttribute *) w->attributes.pointers;
634
+ utf8 * pp = (utf8 *) w->prefixes.pointers;
635
+
636
+ for (i = 0; i < w->namespaces.count; i++)
637
+ {
638
+ deallocate(w, nn[i]->name);
639
+ deallocate(w, nn[i]);
640
+ }
641
+
642
+ for (i = 0; i < w->elements.count; i++)
643
+ {
644
+ deallocate(w, ee[i]->type);
645
+ deallocate(w, ee[i]);
646
+ }
647
+
648
+ for (i = 0; i < w->attributes.count; i++)
649
+ {
650
+ deallocate(w, aa[i]->name);
651
+ deallocate(w, aa[i]->value.buf);
652
+ deallocate(w, aa[i]);
653
+ }
654
+
655
+ for(i = 0; i < w->prefixes.count; i++)
656
+ deallocate(w, pp[i]);
657
+
658
+ deallocate(w, w->namespaces.pointers);
659
+ deallocate(w, w->elements.pointers);
660
+ deallocate(w, w->attributes.pointers);
661
+ deallocate(w, w->prefixes.pointers);
662
+ deallocate(w, w->stack.pointers);
663
+
664
+ deallocate(w, w->arec.value.buf);
665
+
666
+ deallocate(w, w->empty);
667
+
668
+ /* how Oscar dealt with Igli */
669
+ deallocate(w, w);
670
+ }
671
+
672
+ /*******************************
673
+ * External utility routines
674
+ */
675
+
676
+ /*
677
+ * scan a buffer and report problems with UTF-8 encoding or non-XML characters
678
+ */
679
+ genxStatus genxCheckText(genxWriter w, constUtf8 s)
680
+ {
681
+ while (*s)
682
+ {
683
+ int c = genxNextUnicodeChar(&s);
684
+ if (c == -1)
685
+ return GENX_BAD_UTF8;
686
+
687
+ if (!isXMLChar(w, c))
688
+ return GENX_NON_XML_CHARACTER;
689
+ }
690
+ return GENX_SUCCESS;
691
+ }
692
+
693
+ /*
694
+ * Purify some text
695
+ */
696
+ int genxScrubText(genxWriter w, constUtf8 in, utf8 out)
697
+ {
698
+ int problems = 0;
699
+ constUtf8 last = in;
700
+
701
+ while (*in)
702
+ {
703
+ int c = genxNextUnicodeChar(&in);
704
+ if (c == -1)
705
+ {
706
+ problems++;
707
+ last = in;
708
+ continue;
709
+ }
710
+
711
+ if (!isXMLChar(w, c))
712
+ {
713
+ problems++;
714
+ last = in;
715
+ continue;
716
+ }
717
+
718
+ while (last < in)
719
+ *out++ = *last++;
720
+ }
721
+ *out = 0;
722
+ return problems;
723
+ }
724
+
725
+ /*
726
+ * check one character
727
+ */
728
+ int genxCharClass(genxWriter w, int c)
729
+ {
730
+ int ret = 0;
731
+
732
+ if (isXMLChar(w, c))
733
+ ret |= GENX_XML_CHAR;
734
+ if (isNameChar(w, c))
735
+ ret |= GENX_NAMECHAR;
736
+ if (isLetter(w, c))
737
+ ret |= GENX_LETTER;
738
+ return ret;
739
+ }
740
+
741
+ static genxStatus checkNCName(genxWriter w, constUtf8 name)
742
+ {
743
+ int c;
744
+
745
+ if (name == NULL || *name == 0)
746
+ return GENX_BAD_NAME;
747
+
748
+ c = genxNextUnicodeChar(&name);
749
+ if (!isLetter(w, c) && c != ':' && c != '_')
750
+ return GENX_BAD_NAME;
751
+
752
+ while (*name)
753
+ {
754
+ c = genxNextUnicodeChar(&name);
755
+ if (c == -1)
756
+ return GENX_BAD_UTF8;
757
+ if (!isNameChar(w, c))
758
+ return GENX_BAD_NAME;
759
+ }
760
+ return GENX_SUCCESS;
761
+ }
762
+
763
+ char * genxGetErrorMessage(genxWriter w, genxStatus status)
764
+ {
765
+ return w->etext[status];
766
+ }
767
+ char * genxLastErrorMessage(genxWriter w)
768
+ {
769
+ return w->etext[w->status];
770
+ }
771
+
772
+ /*******************************
773
+ * Declarations: namespace/element/attribute
774
+ */
775
+
776
+ /*
777
+ * DeclareNamespace - by far the most complex routine in Genx
778
+ */
779
+ genxNamespace genxDeclareNamespace(genxWriter w, constUtf8 uri,
780
+ constUtf8 defaultPref,
781
+ genxStatus * statusP)
782
+ {
783
+ genxNamespace ns;
784
+ genxAttribute defaultDecl;
785
+ unsigned char newPrefix[100];
786
+
787
+ if (uri == NULL || uri[0] == 0)
788
+ {
789
+ w->status = GENX_BAD_NAMESPACE_NAME;
790
+ goto busted;
791
+ }
792
+
793
+ if ((w->status = genxCheckText(w, uri)) != GENX_SUCCESS)
794
+ goto busted;
795
+
796
+ /* if a prefix is provided, it has to be an NCname */
797
+ if (defaultPref != NULL && defaultPref[0] != 0 &&
798
+ (w->status = checkNCName(w, defaultPref)) != GENX_SUCCESS)
799
+ goto busted;
800
+
801
+ /* previously declared? */
802
+ if ((ns = findNamespace(&w->namespaces, uri)))
803
+ {
804
+ /* just a lookup, really */
805
+ if ((defaultPref == NULL) ||
806
+ (defaultPref[0] == 0 && ns->defaultDecl == w->xmlnsEquals) ||
807
+ (strcmp((const char *) ns->defaultDecl->name + STRLEN_XMLNS_COLON,
808
+ (const char *) defaultPref) == 0))
809
+ {
810
+ w->status = *statusP = GENX_SUCCESS;
811
+ return ns;
812
+ }
813
+ }
814
+
815
+ /* wasn't already declared */
816
+ else
817
+ {
818
+
819
+ /* make a default prefix if none provided */
820
+ if (defaultPref == NULL)
821
+ {
822
+ sprintf((char *) newPrefix, "g%d", w->nextPrefix++);
823
+ defaultPref = newPrefix;
824
+ }
825
+
826
+ ns = (genxNamespace) allocate(w, sizeof(struct genxNamespace_rec));
827
+ if (ns == NULL)
828
+ {
829
+ w->status = GENX_ALLOC_FAILED;
830
+ goto busted;
831
+ }
832
+ ns->writer = w;
833
+ ns->baroque = False;
834
+
835
+ if ((ns->name = copy(w, uri)) == NULL)
836
+ {
837
+ w->status = GENX_ALLOC_FAILED;
838
+ goto busted;
839
+ }
840
+
841
+ if ((w->status = listAppend(&w->namespaces, ns)) != GENX_SUCCESS)
842
+ goto busted;
843
+ ns->defaultDecl = ns->declaration = NULL;
844
+ ns->declCount = 0;
845
+ }
846
+
847
+ if (defaultPref[0] == 0)
848
+ {
849
+ if (w->defaultNsDeclared)
850
+ {
851
+ w->status = GENX_DUPLICATE_PREFIX;
852
+ goto busted;
853
+ }
854
+ defaultDecl = w->xmlnsEquals;
855
+ w->defaultNsDeclared = True;
856
+ }
857
+ else
858
+ {
859
+ /* this catches dupes too */
860
+ if ((defaultPref = storePrefix(w, defaultPref, False)) == NULL)
861
+ goto busted;
862
+
863
+ defaultDecl = declareAttribute(w, NULL, defaultPref, ns->name, statusP);
864
+ if (defaultDecl == NULL || *statusP != GENX_SUCCESS)
865
+ {
866
+ w->status = *statusP;
867
+ return NULL;
868
+ }
869
+ }
870
+
871
+ if (ns->defaultDecl != NULL && defaultDecl != ns->defaultDecl)
872
+ ns->baroque = True;
873
+ ns->defaultDecl = defaultDecl;
874
+
875
+ *statusP = GENX_SUCCESS;
876
+ return ns;
877
+
878
+ busted:
879
+ *statusP = w->status;
880
+ return NULL;
881
+ }
882
+
883
+ /*
884
+ * get namespace prefix
885
+ */
886
+ utf8 genxGetNamespacePrefix(genxNamespace ns)
887
+ {
888
+ if (ns->declaration == NULL)
889
+ return NULL;
890
+
891
+ if (ns->declaration == ns->writer->xmlnsEquals)
892
+ return ns->writer->empty;
893
+
894
+ return ns->declaration->name + STRLEN_XMLNS_COLON;
895
+ }
896
+
897
+ /*
898
+ * DeclareElement - see genx.h for details
899
+ */
900
+ genxElement genxDeclareElement(genxWriter w,
901
+ genxNamespace ns, constUtf8 type,
902
+ genxStatus * statusP)
903
+ {
904
+ genxElement old;
905
+ genxElement el;
906
+
907
+ if ((w->status = checkNCName(w, type)) != GENX_SUCCESS)
908
+ {
909
+ *statusP = w->status;
910
+ return NULL;
911
+ }
912
+
913
+ /* already declared? */
914
+ old = findElement(&w->elements, (ns == NULL) ? NULL : ns->name, type);
915
+ if (old)
916
+ return old;
917
+
918
+ if ((el = (genxElement) allocate(w, sizeof(struct genxElement_rec))) == NULL)
919
+ {
920
+ w->status = *statusP = GENX_ALLOC_FAILED;
921
+ return NULL;
922
+ }
923
+
924
+ el->writer = w;
925
+ el->ns = ns;
926
+ if ((el->type = copy(w, type)) == NULL)
927
+ {
928
+ w->status = *statusP = GENX_ALLOC_FAILED;
929
+ return NULL;
930
+ }
931
+
932
+ if ((w->status = listAppend(&w->elements, el)) != GENX_SUCCESS)
933
+ {
934
+ *statusP = w->status;
935
+ return NULL;
936
+ }
937
+
938
+ *statusP = GENX_SUCCESS;
939
+ return el;
940
+ }
941
+
942
+ /*
943
+ * C14n ordering for attributes:
944
+ * - first, namespace declarations by the prefix being declared
945
+ * - second, unprefixed attributes by attr name
946
+ * - third, prefixed attrs by ns uri then local part
947
+ */
948
+ static int orderAttributes(genxAttribute a1, genxAttribute a2)
949
+ {
950
+ if (a1->atype == a2->atype)
951
+ {
952
+ if (a1->atype == ATTR_PREFIXED && a1->ns != a2->ns)
953
+ return strcmp((const char *) a1->ns->name, (const char *) a2->ns->name);
954
+ else
955
+ return strcmp((const char *) a1->name, (const char *) a2->name);
956
+ }
957
+
958
+ else if (a1->atype == ATTR_NSDECL)
959
+ return -1;
960
+
961
+ else if (a1->atype == ATTR_NAKED)
962
+ {
963
+ if (a2->atype == ATTR_NSDECL)
964
+ return 1;
965
+ else
966
+ return -1;
967
+ }
968
+
969
+ else
970
+ return 1;
971
+ }
972
+
973
+ /*
974
+ * internal declare-attribute. This one allows colonized values for
975
+ * names, so that you can declare xmlns:-type attributes
976
+ */
977
+ static genxAttribute declareAttribute(genxWriter w, genxNamespace ns,
978
+ constUtf8 name, constUtf8 valuestr,
979
+ genxStatus * statusP)
980
+ {
981
+ int high, low;
982
+ genxAttribute * aa = (genxAttribute *) w->attributes.pointers;
983
+ genxAttribute a;
984
+
985
+ w->arec.ns = ns;
986
+ w->arec.name = (utf8) name;
987
+
988
+ if (ns)
989
+ w->arec.atype = ATTR_PREFIXED;
990
+ else if (strncmp((const char *) name, "xmlns", STRLEN_XMLNS_COLON - 1) == 0)
991
+ w->arec.atype = ATTR_NSDECL;
992
+ else
993
+ w->arec.atype = ATTR_NAKED;
994
+
995
+ if (ns && (ns->defaultDecl == w->xmlnsEquals))
996
+ {
997
+ w->status = GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE;
998
+ goto busted;
999
+ }
1000
+
1001
+ /* attribute list has to be kept sorted per c14n rules */
1002
+ high = w->attributes.count; low = -1;
1003
+ while (high - low > 1)
1004
+ {
1005
+ int probe = (high + low) / 2;
1006
+ if (orderAttributes(&w->arec, aa[probe]) < 0)
1007
+ high = probe;
1008
+ else
1009
+ low = probe;
1010
+ }
1011
+
1012
+ /* if it was already there */
1013
+ if (low != -1 && orderAttributes(&w->arec, aa[low]) == 0)
1014
+ return aa[low];
1015
+
1016
+ /* not there, build it */
1017
+ a = (genxAttribute) allocate(w, sizeof(struct genxAttribute_rec));
1018
+ if (a == NULL)
1019
+ {
1020
+ w->status = GENX_ALLOC_FAILED;
1021
+ goto busted;
1022
+ }
1023
+
1024
+ a->writer = w;
1025
+ a->ns = ns;
1026
+ a->provided = False;
1027
+ a->atype = w->arec.atype;
1028
+
1029
+ if ((a->name = copy(w, name)) == NULL)
1030
+ {
1031
+ w->status = GENX_ALLOC_FAILED;
1032
+ goto busted;
1033
+ }
1034
+
1035
+ if ((w->status = initCollector(w, &a->value)) != GENX_SUCCESS)
1036
+ goto busted;
1037
+
1038
+ if (valuestr)
1039
+ if ((w->status = collectString(w, &a->value, valuestr)) != GENX_SUCCESS)
1040
+ goto busted;
1041
+
1042
+ w->status = listInsert(&w->attributes, a, high);
1043
+ if (w->status != GENX_SUCCESS)
1044
+ goto busted;
1045
+
1046
+ *statusP = GENX_SUCCESS;
1047
+ return a;
1048
+
1049
+ busted:
1050
+ *statusP = w->status;
1051
+ return NULL;
1052
+ }
1053
+
1054
+ /*
1055
+ * genxDeclareAttribute - see genx.h for details
1056
+ */
1057
+ genxAttribute genxDeclareAttribute(genxWriter w,
1058
+ genxNamespace ns, constUtf8 name,
1059
+ genxStatus * statusP)
1060
+ {
1061
+ if ((w->status = checkNCName(w, name)) != GENX_SUCCESS)
1062
+ {
1063
+ *statusP = w->status;
1064
+ return NULL;
1065
+ }
1066
+
1067
+ return declareAttribute(w, ns, name, NULL, statusP);
1068
+ }
1069
+
1070
+ /*******************************
1071
+ * I/O
1072
+ */
1073
+ static genxStatus sendx(genxWriter w, constUtf8 s)
1074
+ {
1075
+ if (w->sender)
1076
+ return (*w->sender->send)(w->userData, s);
1077
+ else
1078
+ {
1079
+ if (fputs((const char *) s, w->file) == -1)
1080
+ return GENX_IO_ERROR;
1081
+ else
1082
+ return GENX_SUCCESS;
1083
+ }
1084
+ }
1085
+
1086
+ static genxStatus sendxBounded(genxWriter w, constUtf8 start, constUtf8 end)
1087
+ {
1088
+ if (w->sender)
1089
+ return (*w->sender->sendBounded)(w->userData, start, end);
1090
+ else
1091
+ if (fwrite(start, 1, end - start, w->file) != (unsigned) (end - start))
1092
+ return GENX_IO_ERROR;
1093
+ else
1094
+ return GENX_SUCCESS;
1095
+ }
1096
+
1097
+ #define SendCheck(w,s) if ((w->status=sendx(w,(utf8)s))!=GENX_SUCCESS) return w->status;
1098
+
1099
+ /*******************************
1100
+ * XML writing routines. The semantics of the externally-facing ones are
1101
+ * written up in genx.h. Commentary here is implementation notes and
1102
+ * for internal routines.
1103
+ */
1104
+
1105
+ /*
1106
+ * Start a document
1107
+ */
1108
+ genxStatus genxStartDocFile(genxWriter w, FILE * file)
1109
+ {
1110
+ if (w->sequence != SEQUENCE_NO_DOC)
1111
+ return w->status = GENX_SEQUENCE_ERROR;
1112
+
1113
+ w->sequence = SEQUENCE_PRE_DOC;
1114
+ w->file = file;
1115
+ w->sender = NULL;
1116
+ return GENX_SUCCESS;
1117
+ }
1118
+
1119
+ genxStatus genxStartDocSender(genxWriter w, genxSender * sender)
1120
+ {
1121
+ if (w->sequence != SEQUENCE_NO_DOC)
1122
+ return w->status = GENX_SEQUENCE_ERROR;
1123
+
1124
+ w->sequence = SEQUENCE_PRE_DOC;
1125
+ w->file = NULL;
1126
+ w->sender = sender;
1127
+ return GENX_SUCCESS;
1128
+ }
1129
+
1130
+ /*
1131
+ * Write out the attributes we've been gathering up for an element. We save
1132
+ * them until we've gathered them all so they can be writen in canonical
1133
+ * order.
1134
+ * Also, we end the start-tag.
1135
+ * The trick here is that we keep the attribute list properly sorted as
1136
+ * we build it, then as each attribute is added, we fill in its value and
1137
+ * mark the fact that it's been added, in the "provided" field.
1138
+ */
1139
+ static genxStatus writeStartTag(genxWriter w)
1140
+ {
1141
+ int i;
1142
+ genxAttribute * aa = (genxAttribute *) w->attributes.pointers;
1143
+ genxElement e = w->nowStarting;
1144
+
1145
+ /*
1146
+ * make sure the right namespace decls are in effect;
1147
+ * if they are these might create an error, so ignore it
1148
+ */
1149
+ if (e->ns)
1150
+ addNamespace(e->ns, NULL);
1151
+ else
1152
+ unsetDefaultNamespace(w);
1153
+ w->status = GENX_SUCCESS;
1154
+
1155
+ SendCheck(w, "<");
1156
+ if (e->ns && (e->ns->declaration != w->xmlnsEquals))
1157
+ {
1158
+ SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON);
1159
+ SendCheck(w, ":");
1160
+ }
1161
+ SendCheck(w, e->type);
1162
+
1163
+ for (i = 0; i < w->attributes.count; i++)
1164
+ {
1165
+ if (aa[i]->provided)
1166
+ {
1167
+ if (aa[i]->ns && aa[i]->ns->baroque &&
1168
+ aa[i]->ns->declaration == w->xmlnsEquals)
1169
+ return w->status = GENX_ATTRIBUTE_IN_DEFAULT_NAMESPACE;
1170
+
1171
+ SendCheck(w, " ");
1172
+
1173
+ if (aa[i]->ns)
1174
+ {
1175
+ SendCheck(w, aa[i]->ns->declaration->name + STRLEN_XMLNS_COLON)
1176
+ SendCheck(w, ":");
1177
+ }
1178
+ SendCheck(w, aa[i]->name);
1179
+ SendCheck(w, "=\"");
1180
+ SendCheck(w, aa[i]->value.buf);
1181
+ SendCheck(w, "\"");
1182
+ }
1183
+ }
1184
+ SendCheck(w, ">");
1185
+ return GENX_SUCCESS;
1186
+ }
1187
+
1188
+ /*
1189
+ * internal clear-er; no sequence checking
1190
+ */
1191
+ static genxStatus unsetDefaultNamespace(genxWriter w)
1192
+ {
1193
+ int i;
1194
+ Boolean found = False;
1195
+
1196
+ /* don't put it in if not needed */
1197
+ i = w->stack.count - 1;
1198
+ while (found == False && i > 0)
1199
+ {
1200
+ while (w->stack.pointers[i] != NULL)
1201
+ {
1202
+ genxAttribute decl = (genxAttribute) w->stack.pointers[i--];
1203
+ genxNamespace ns = (genxNamespace) w->stack.pointers[i--];
1204
+
1205
+ /* if already unset */
1206
+ if (ns == NULL)
1207
+ return w->status = GENX_SUCCESS;
1208
+
1209
+ /*
1210
+ * the default namespace was declared. This namespace now
1211
+ * becomes baroque
1212
+ */
1213
+ if (decl == w->xmlnsEquals)
1214
+ {
1215
+ ns->baroque = True;
1216
+ found = True;
1217
+ break;
1218
+ }
1219
+ }
1220
+ i -= 2;
1221
+ }
1222
+
1223
+ if (!found)
1224
+ return GENX_SUCCESS;
1225
+
1226
+ /*
1227
+ * push a signal on the stack
1228
+ */
1229
+ if ((w->status = listAppend(&w->stack, NULL)) != GENX_SUCCESS)
1230
+ return w->status;
1231
+ w->status = listAppend(&w->stack, w->xmlnsEquals);
1232
+ if (w->status != GENX_SUCCESS)
1233
+ return w->status;
1234
+
1235
+ /* add the xmlns= attribute, it must be the first one */
1236
+ return addAttribute(w->xmlnsEquals, w->empty);
1237
+ }
1238
+
1239
+ /*
1240
+ * clear the default namespace declaration
1241
+ */
1242
+ genxStatus genxUnsetDefaultNamespace(genxWriter w)
1243
+ {
1244
+
1245
+ /* can only do this while in start-tag mode */
1246
+ if (w->sequence != SEQUENCE_START_TAG)
1247
+ return w->status = GENX_SEQUENCE_ERROR;
1248
+
1249
+ return unsetDefaultNamespace(w);
1250
+ }
1251
+
1252
+ genxStatus genxStartElement(genxElement e)
1253
+ {
1254
+ genxWriter w = e->writer;
1255
+ int i;
1256
+
1257
+ switch (w->sequence)
1258
+ {
1259
+ case SEQUENCE_NO_DOC:
1260
+ case SEQUENCE_POST_DOC:
1261
+ return w->status = GENX_SEQUENCE_ERROR;
1262
+ case SEQUENCE_START_TAG:
1263
+ case SEQUENCE_ATTRIBUTES:
1264
+ if ((w->status = writeStartTag(w)) != GENX_SUCCESS)
1265
+ return w->status;
1266
+ break;
1267
+ case SEQUENCE_PRE_DOC:
1268
+ case SEQUENCE_CONTENT:
1269
+ break;
1270
+ }
1271
+
1272
+ w->sequence = SEQUENCE_START_TAG;
1273
+
1274
+ /* clear provided attributes */
1275
+ for (i = 0; i < w->attributes.count; i++)
1276
+ ((genxAttribute) w->attributes.pointers[i])->provided = 0;
1277
+
1278
+ /*
1279
+ * push the stack. We push a NULL after a pointer to this element
1280
+ * because the stack will also contain pointers to the namespace
1281
+ * attributes that got declared here, so we can keep track of what's
1282
+ * in effect. I.e. a single stack entry consists logically of a pointer
1283
+ * to an element object, a NULL, then zero or more pairs of pointers to
1284
+ * namespace objects/declarations
1285
+ */
1286
+ if ((w->status = listAppend(&w->stack, e)) != GENX_SUCCESS)
1287
+ return w->status;
1288
+ if ((w->status = listAppend(&w->stack, NULL)) != GENX_SUCCESS)
1289
+ return w->status;
1290
+
1291
+ w->nowStarting = e;
1292
+
1293
+ return GENX_SUCCESS;
1294
+ }
1295
+
1296
+ /*
1297
+ * internal namespace adder; no sequence checking
1298
+ */
1299
+ static genxStatus addNamespace(genxNamespace ns, utf8 prefix)
1300
+ {
1301
+ genxWriter w = ns->writer;
1302
+ genxAttribute decl;
1303
+ int i;
1304
+ genxElement e;
1305
+
1306
+ /*
1307
+ * first, we'll find the declaring attribute
1308
+ */
1309
+ if (prefix == NULL)
1310
+ decl = ns->defaultDecl;
1311
+ else
1312
+ {
1313
+ if (prefix[0] == 0)
1314
+ decl = w->xmlnsEquals;
1315
+ else
1316
+ {
1317
+ if ((prefix = storePrefix(w, prefix, True)) == NULL)
1318
+ return w->status;
1319
+ decl = declareAttribute(w, NULL, prefix, ns->name, &w->status);
1320
+ if (decl == NULL || w->status != GENX_SUCCESS)
1321
+ return w->status;
1322
+ }
1323
+ }
1324
+
1325
+ if (decl != ns->defaultDecl)
1326
+ ns->baroque = True;
1327
+
1328
+ /*
1329
+ * avoid doing anything if this namespace is already declared. If
1330
+ * they've shown good taste we can do this cheaply
1331
+ */
1332
+ if (!ns->baroque)
1333
+ {
1334
+ if (ns->declCount > 0)
1335
+ return w->status = GENX_SUCCESS;
1336
+ }
1337
+ else
1338
+ {
1339
+
1340
+ /*
1341
+ * First, we'll run all the way up the stack to see if there is
1342
+ * another declaration for this namespace/prefix in scope, in which
1343
+ * case it's a no-op; or, if there's another declaration for this
1344
+ * prefix on another namespace, in which case we have to over-ride
1345
+ */
1346
+ i = w->stack.count - 1;
1347
+ while (i > 0)
1348
+ {
1349
+ while (w->stack.pointers[i] != NULL)
1350
+ {
1351
+ genxAttribute otherDecl = (genxAttribute) w->stack.pointers[i--];
1352
+ genxNamespace otherNs = (genxNamespace) w->stack.pointers[i--];
1353
+
1354
+ if (ns == otherNs)
1355
+ {
1356
+ if (decl == otherDecl)
1357
+ return w->status = GENX_SUCCESS;
1358
+ else
1359
+ {
1360
+ i = 0;
1361
+ break;
1362
+ }
1363
+ }
1364
+ else
1365
+ {
1366
+ /* different namespace, same prefix? */
1367
+ if (decl == otherDecl)
1368
+ {
1369
+ i = 0;
1370
+ break;
1371
+ }
1372
+ }
1373
+ }
1374
+ i -= 2;
1375
+ }
1376
+ }
1377
+
1378
+ /*
1379
+ * If this namespace is already declared on
1380
+ * this element (with different prefix/decl) which is an error.
1381
+ */
1382
+ i = w->stack.count - 1;
1383
+ while (w->stack.pointers[i] != NULL)
1384
+ {
1385
+ genxNamespace otherNs;
1386
+ i--; /* don't need declaration */
1387
+ otherNs = (genxNamespace) w->stack.pointers[i--];
1388
+
1389
+ if (ns == otherNs)
1390
+ return w->status = GENX_DUPLICATE_NAMESPACE;
1391
+ }
1392
+
1393
+ /* move pointer from NULL to element */
1394
+ --i;
1395
+
1396
+ /*
1397
+ * It's also an error if this is a default-namespace declaration and the
1398
+ * element is in no namespace.
1399
+ */
1400
+ e = (genxElement) w->stack.pointers[i];
1401
+ if (e->ns == NULL && decl == w->xmlnsEquals)
1402
+ return w->status = GENX_BAD_DEFAULT_DECLARATION;
1403
+
1404
+ if ((w->status = listAppend(&w->stack, ns)) != GENX_SUCCESS)
1405
+ return w->status;
1406
+ if ((w->status = listAppend(&w->stack, decl)) != GENX_SUCCESS)
1407
+ return w->status;
1408
+
1409
+ ns->declaration = decl;
1410
+ ns->declCount++;
1411
+ return addAttribute(decl, ns->name);
1412
+ }
1413
+
1414
+ /*
1415
+ * Add a namespace declaration
1416
+ */
1417
+ genxStatus genxAddNamespace(genxNamespace ns, utf8 prefix)
1418
+ {
1419
+ if (ns->writer->sequence != SEQUENCE_START_TAG)
1420
+ return ns->writer->status = GENX_SEQUENCE_ERROR;
1421
+
1422
+ return addNamespace(ns, prefix);
1423
+ }
1424
+
1425
+ /*
1426
+ * Private attribute-adding code
1427
+ * most of the work here is normalizing the value, which is the same
1428
+ * as regular normalization except for " is replaced by "&quot;"
1429
+ */
1430
+ static genxStatus addAttribute(genxAttribute a, constUtf8 valuestr)
1431
+ {
1432
+ utf8 lastv = (utf8) valuestr;
1433
+ genxWriter w = a->writer;
1434
+
1435
+ /* if valuestr not provided, this is an xmlns with a pre-cooked value */
1436
+ if (valuestr)
1437
+ {
1438
+ startCollect(&a->value);
1439
+ while (*valuestr)
1440
+ {
1441
+ int c = genxNextUnicodeChar(&valuestr);
1442
+
1443
+ if (c == -1)
1444
+ return w->status = GENX_BAD_UTF8;
1445
+
1446
+ if (!isXMLChar(w, c))
1447
+ return w->status = GENX_NON_XML_CHARACTER;
1448
+
1449
+ switch(c)
1450
+ {
1451
+ case 9:
1452
+ collectPiece(w, &a->value, "&#x9;", 5);
1453
+ break;
1454
+ case 0xa:
1455
+ collectPiece(w, &a->value, "&#xA;", 5);
1456
+ break;
1457
+ case 0xd:
1458
+ collectPiece(w, &a->value, "&#xD;", 5);
1459
+ break;
1460
+ case '"':
1461
+ collectPiece(w, &a->value, "&quot;", 6);
1462
+ break;
1463
+ case '<':
1464
+ collectPiece(w, &a->value, "&lt;", 4);
1465
+ break;
1466
+ case '&':
1467
+ collectPiece(w, &a->value, "&amp;", 5);
1468
+ break;
1469
+ /*
1470
+ case '>':
1471
+ collectPiece(w, &a->value, "&gt;", 4);
1472
+ break;
1473
+ */
1474
+ default:
1475
+ collectPiece(w, &a->value, (const char *) lastv, valuestr - lastv);
1476
+ break;
1477
+ }
1478
+ lastv = (utf8) valuestr;
1479
+ }
1480
+ endCollect(&a->value);
1481
+ }
1482
+
1483
+ /* now add the namespace attribute; might fail if it's bee hand-declared */
1484
+ if (a->ns)
1485
+ addNamespace(a->ns, NULL);
1486
+
1487
+ if (valuestr && a->provided)
1488
+ return w->status = GENX_DUPLICATE_ATTRIBUTE;
1489
+ a->provided = 1;
1490
+
1491
+ return GENX_SUCCESS;
1492
+ }
1493
+
1494
+ /*
1495
+ * public attribute adder.
1496
+ * The only difference is that it doesn't allow a NULL value
1497
+ */
1498
+ genxStatus genxAddAttribute(genxAttribute a, constUtf8 valuestr)
1499
+ {
1500
+ if (a->writer->sequence != SEQUENCE_START_TAG &&
1501
+ a->writer->sequence != SEQUENCE_ATTRIBUTES)
1502
+ return a->writer->status = GENX_SEQUENCE_ERROR;
1503
+ a->writer->sequence = SEQUENCE_ATTRIBUTES;
1504
+
1505
+ if (valuestr == NULL)
1506
+ return a->writer->status = GENX_MISSING_VALUE;
1507
+
1508
+ return addAttribute(a, valuestr);
1509
+ }
1510
+
1511
+ genxStatus genxEndElement(genxWriter w)
1512
+ {
1513
+ genxElement e;
1514
+ int i;
1515
+
1516
+ switch (w->sequence)
1517
+ {
1518
+ case SEQUENCE_NO_DOC:
1519
+ case SEQUENCE_PRE_DOC:
1520
+ case SEQUENCE_POST_DOC:
1521
+ return w->status = GENX_SEQUENCE_ERROR;
1522
+ case SEQUENCE_START_TAG:
1523
+ case SEQUENCE_ATTRIBUTES:
1524
+ if ((w->status = writeStartTag(w)) != GENX_SUCCESS)
1525
+ return w->status;
1526
+ break;
1527
+ case SEQUENCE_CONTENT:
1528
+ break;
1529
+ }
1530
+
1531
+ /*
1532
+ * first peek into the stack to find the right namespace declaration
1533
+ * (if any) so we can properly prefix the end-tag. Have to do this
1534
+ * before unwinding the stack because that might reset some xmlns
1535
+ * prefixes to the context in the parent element
1536
+ */
1537
+ for (i = w->stack.count - 1; w->stack.pointers[i] != NULL; i -= 2)
1538
+ ;
1539
+ e = (genxElement) w->stack.pointers[--i];
1540
+
1541
+ SendCheck(w, "</");
1542
+ if (e->ns && e->ns->declaration != w->xmlnsEquals)
1543
+ {
1544
+ SendCheck(w, e->ns->declaration->name + STRLEN_XMLNS_COLON);
1545
+ SendCheck(w, ":");
1546
+ }
1547
+ SendCheck(w, e->type);
1548
+ SendCheck(w, ">");
1549
+
1550
+ /*
1551
+ * pop zero or more namespace declarations, then a null, then the
1552
+ * start-element declaration off the stack
1553
+ */
1554
+ w->stack.count--;
1555
+ while (w->stack.pointers[w->stack.count] != NULL)
1556
+ {
1557
+ genxNamespace ns = (genxNamespace) w->stack.pointers[--w->stack.count];
1558
+ w->stack.count--; /* don't need decl */
1559
+
1560
+ /* if not a fake unset-default namespace */
1561
+ if (ns)
1562
+ {
1563
+ /*
1564
+ * if they've stupidly jammed in their own namespace-prefix
1565
+ * declarations, we have to go looking to see if there's another
1566
+ * one in effect
1567
+ */
1568
+ if (ns->baroque)
1569
+ {
1570
+ i = w->stack.count;
1571
+ while (i > 0)
1572
+ {
1573
+ while (w->stack.pointers[i] != NULL)
1574
+ {
1575
+ genxAttribute otherDecl = (genxAttribute) w->stack.pointers[i--];
1576
+ genxNamespace otherNs = (genxNamespace) w->stack.pointers[i--];
1577
+
1578
+ if (otherNs == ns)
1579
+ {
1580
+ ns->declaration = otherDecl;
1581
+ i = 0;
1582
+ break;
1583
+ }
1584
+ }
1585
+
1586
+ /* skip NULL & element */
1587
+ i -= 2;
1588
+ }
1589
+ }
1590
+ ns->declCount--;
1591
+ if (ns->declCount == 0)
1592
+ ns->baroque = False;
1593
+ }
1594
+ }
1595
+
1596
+ /* pop the NULL */
1597
+ --w->stack.count;
1598
+ if (w->stack.count < 0)
1599
+ return w->status = GENX_NO_START_TAG;
1600
+
1601
+ if (w->stack.count == 0)
1602
+ w->sequence = SEQUENCE_POST_DOC;
1603
+ else
1604
+ w->sequence = SEQUENCE_CONTENT;
1605
+
1606
+ return GENX_SUCCESS;
1607
+ }
1608
+
1609
+ /*
1610
+ * Internal character-adder. It tries to keep the number of sendx()
1611
+ * calls down by looking at each character but only doing the output
1612
+ * when it has to escape something; ordinary text gets saved up in
1613
+ * chunks the start of which is indicated by *breaker.
1614
+ * c is the character, next points to the UTF8 representing the next
1615
+ * lastsP indirectly points to the UTF8 representing the
1616
+ * character, breakerP* indirectly points to the last place genx
1617
+ * changed the UTF8, e.g. by escaping a '<'
1618
+ */
1619
+ static genxStatus addChar(genxWriter w, int c, constUtf8 next,
1620
+ constUtf8 * lastsP, constUtf8 * breakerP)
1621
+ {
1622
+ if (c == -1)
1623
+ return GENX_BAD_UTF8;
1624
+
1625
+ if (!isXMLChar(w, c))
1626
+ return GENX_NON_XML_CHARACTER;
1627
+
1628
+ switch(c)
1629
+ {
1630
+ case 0xd:
1631
+ if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS)
1632
+ return w->status;
1633
+ *breakerP = next;
1634
+ sendx(w, (utf8) "&#xD;");
1635
+ break;
1636
+ case '<':
1637
+ if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS)
1638
+ return w->status;
1639
+ *breakerP = next;
1640
+ sendx(w, (utf8) "&lt;");
1641
+ break;
1642
+ case '&':
1643
+ if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS)
1644
+ return w->status;
1645
+ *breakerP = next;
1646
+ sendx(w, (utf8) "&amp;");
1647
+ break;
1648
+ case '>':
1649
+ if ((w->status = sendxBounded(w, *breakerP, *lastsP)) != GENX_SUCCESS)
1650
+ return w->status;
1651
+ *breakerP = next;
1652
+ sendx(w, (utf8) "&gt;");
1653
+ break;
1654
+ default:
1655
+ break;
1656
+ }
1657
+ *lastsP = next;
1658
+ return GENX_SUCCESS;
1659
+ }
1660
+
1661
+ genxStatus genxAddText(genxWriter w, constUtf8 start)
1662
+ {
1663
+ constUtf8 lasts = start;
1664
+ constUtf8 breaker = start;
1665
+
1666
+ if (w->sequence == SEQUENCE_START_TAG ||
1667
+ w->sequence == SEQUENCE_ATTRIBUTES)
1668
+ {
1669
+ if ((w->status = writeStartTag(w)) != GENX_SUCCESS)
1670
+ return w->status;
1671
+ w->sequence = SEQUENCE_CONTENT;
1672
+ }
1673
+
1674
+ if (w->sequence != SEQUENCE_CONTENT)
1675
+ return w->status = GENX_SEQUENCE_ERROR;
1676
+
1677
+ while (*start)
1678
+ {
1679
+ int c = genxNextUnicodeChar(&start);
1680
+
1681
+ w->status = addChar(w, c, start, &lasts, &breaker);
1682
+ if (w->status != GENX_SUCCESS)
1683
+ return w->status;
1684
+ }
1685
+ return sendxBounded(w, breaker, (utf8) start);
1686
+ }
1687
+
1688
+ genxStatus genxAddBoundedText(genxWriter w, constUtf8 start, constUtf8 end)
1689
+ {
1690
+ constUtf8 lasts = start;
1691
+ constUtf8 breaker = start;
1692
+
1693
+ if (w->sequence == SEQUENCE_START_TAG ||
1694
+ w->sequence == SEQUENCE_ATTRIBUTES)
1695
+ {
1696
+ if ((w->status = writeStartTag(w)) != GENX_SUCCESS)
1697
+ return w->status;
1698
+ w->sequence = SEQUENCE_CONTENT;
1699
+ }
1700
+
1701
+ if (w->sequence != SEQUENCE_CONTENT)
1702
+ return w->status = GENX_SEQUENCE_ERROR;
1703
+
1704
+ while (start < end)
1705
+ {
1706
+ int c = genxNextUnicodeChar(&start);
1707
+
1708
+ w->status = addChar(w, c, (utf8) start, &lasts, &breaker);
1709
+ if (w->status != GENX_SUCCESS)
1710
+ return w->status;
1711
+ }
1712
+ return sendxBounded(w, breaker, (utf8) start);
1713
+ }
1714
+
1715
+ genxStatus genxAddCountedText(genxWriter w, constUtf8 start, int byteCount)
1716
+ {
1717
+ utf8 end = (utf8) (start + byteCount);
1718
+
1719
+ return genxAddBoundedText(w, start, end);
1720
+ }
1721
+
1722
+ genxStatus genxAddCharacter(genxWriter w, int c)
1723
+ {
1724
+ unsigned char cUTF8[10];
1725
+ utf8 lasts, breaker, next;
1726
+
1727
+ if (w->sequence == SEQUENCE_START_TAG ||
1728
+ w->sequence == SEQUENCE_ATTRIBUTES)
1729
+ {
1730
+ if ((w->status = writeStartTag(w)) != GENX_SUCCESS)
1731
+ return w->status;
1732
+ w->sequence = SEQUENCE_CONTENT;
1733
+ }
1734
+
1735
+ if (w->sequence != SEQUENCE_CONTENT)
1736
+ return w->status = GENX_SEQUENCE_ERROR;
1737
+
1738
+ if (!isXMLChar(w, c))
1739
+ return w->status = GENX_NON_XML_CHARACTER;
1740
+
1741
+ /* make UTF8 representation of character */
1742
+ lasts = breaker = next = cUTF8;
1743
+
1744
+ if (c < 0x80)
1745
+ *next++ = c;
1746
+ else if (c < 0x800)
1747
+ {
1748
+ *next++ = 0xc0 | (c >> 6);
1749
+ *next++ = 0x80 | (c & 0x3f);
1750
+ }
1751
+ else if (c < 0x10000)
1752
+ {
1753
+ *next++ = 0xe0 | (c >> 12);
1754
+ *next++ = 0x80 | ((c & 0xfc0) >> 6);
1755
+ *next++ = 0x80 | (c & 0x3f);
1756
+ }
1757
+ else
1758
+ {
1759
+ *next++ = 0xf0 | (c >> 18);
1760
+ *next++ = 0x80 | ((c & 0x3f000) >> 12);
1761
+ *next++ = 0x80 | ((c & 0xfc0) >> 6);
1762
+ *next++ = 0x80 | (c & 0x3f);
1763
+ }
1764
+ *next = 0;
1765
+
1766
+ w->status =
1767
+ addChar(w, c, next, (constUtf8 *) &lasts, (constUtf8 *) &breaker);
1768
+ if (w->status != GENX_SUCCESS)
1769
+ return w->status;
1770
+
1771
+ return sendxBounded(w, breaker, next);
1772
+ }
1773
+
1774
+ genxStatus genxEndDocument(genxWriter w)
1775
+ {
1776
+ if (w->sequence != SEQUENCE_POST_DOC)
1777
+ return w->status = GENX_SEQUENCE_ERROR;
1778
+
1779
+ if (w->file)
1780
+ fflush(w->file);
1781
+ else
1782
+ if ((w->status = (*w->sender->flush)(w->userData)) != GENX_SUCCESS)
1783
+ return w->status;
1784
+
1785
+ w->sequence = SEQUENCE_NO_DOC;
1786
+ return GENX_SUCCESS;
1787
+ }
1788
+
1789
+ genxStatus genxComment(genxWriter w, constUtf8 text)
1790
+ {
1791
+ int i;
1792
+
1793
+ if (w->sequence == SEQUENCE_NO_DOC)
1794
+ return w->status = GENX_SEQUENCE_ERROR;
1795
+
1796
+ if ((w->status = genxCheckText(w, text)) != GENX_SUCCESS)
1797
+ return w->status;
1798
+
1799
+ /* no leading '-', no trailing '-', no '--' */
1800
+ if (text[0] == '-')
1801
+ return w->status = GENX_MALFORMED_COMMENT;
1802
+ for (i = 0; text[i]; i++)
1803
+ if (text[i] == '-' && (text[i + 1] == '-' || text[i + 1] == 0))
1804
+ return w->status = GENX_MALFORMED_COMMENT;
1805
+
1806
+ if (w->sequence == SEQUENCE_START_TAG ||
1807
+ w->sequence == SEQUENCE_ATTRIBUTES)
1808
+ {
1809
+ if ((w->status = writeStartTag(w)) != GENX_SUCCESS)
1810
+ return w->status;
1811
+ w->sequence = SEQUENCE_CONTENT;
1812
+ }
1813
+
1814
+ else if (w->sequence == SEQUENCE_POST_DOC)
1815
+ if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS)
1816
+ return w->status;
1817
+
1818
+ if ((w->status = sendx(w, (utf8) "<!--")) != GENX_SUCCESS)
1819
+ return w->status;
1820
+ if ((w->status = sendx(w, (utf8) text)) != GENX_SUCCESS)
1821
+ return w->status;
1822
+ if ((w->status = sendx(w, (utf8) "-->")) != GENX_SUCCESS)
1823
+ return w->status;
1824
+
1825
+ if (w->sequence == SEQUENCE_PRE_DOC)
1826
+ if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS)
1827
+ return w->status;
1828
+
1829
+ return GENX_SUCCESS;
1830
+ }
1831
+
1832
+ genxStatus genxPI(genxWriter w, constUtf8 target, constUtf8 text)
1833
+ {
1834
+ int i;
1835
+
1836
+ if (w->sequence == SEQUENCE_NO_DOC)
1837
+ return w->status = GENX_SEQUENCE_ERROR;
1838
+
1839
+ if ((w->status = genxCheckText(w, target)) != GENX_SUCCESS)
1840
+ return w->status;
1841
+ if ((w->status = checkNCName(w, target)) != GENX_SUCCESS)
1842
+ return w->status;
1843
+ if ((strlen((const char *) target) >= 3) &&
1844
+ (target[0] == 'x' || target[0] == 'X') &&
1845
+ (target[1] == 'm' || target[1] == 'M') &&
1846
+ (target[2] == 'l' || target[2] == 'L') &&
1847
+ (target[3] == 0))
1848
+ return w->status = GENX_XML_PI_TARGET;
1849
+
1850
+ if ((w->status = genxCheckText(w, text)) != GENX_SUCCESS)
1851
+ return w->status;
1852
+
1853
+ /* no ?> within */
1854
+ for (i = 1; text[i]; i++)
1855
+ if (text[i] == '>' && text[i - 1] == '?')
1856
+ return w->status = GENX_MALFORMED_PI;
1857
+
1858
+ if (w->sequence == SEQUENCE_START_TAG ||
1859
+ w->sequence == SEQUENCE_ATTRIBUTES)
1860
+ {
1861
+ if ((w->status = writeStartTag(w)) != GENX_SUCCESS)
1862
+ return w->status;
1863
+ w->sequence = SEQUENCE_CONTENT;
1864
+ }
1865
+
1866
+ else if (w->sequence == SEQUENCE_POST_DOC)
1867
+ if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS)
1868
+ return w->status;
1869
+
1870
+ if ((w->status = sendx(w, (utf8) "<?")) != GENX_SUCCESS)
1871
+ return w->status;
1872
+ if ((w->status = sendx(w, target)) != GENX_SUCCESS)
1873
+ return w->status;
1874
+ if (text[0])
1875
+ {
1876
+ if ((w->status = sendx(w, (utf8) " ")) != GENX_SUCCESS)
1877
+ return w->status;
1878
+ if ((w->status = sendx(w, text)) != GENX_SUCCESS)
1879
+ return w->status;
1880
+ }
1881
+ if ((w->status = sendx(w, (utf8) "?>")) != GENX_SUCCESS)
1882
+ return w->status;
1883
+
1884
+ if (w->sequence == SEQUENCE_PRE_DOC)
1885
+ if ((w->status = sendx(w, (utf8) "\n")) != GENX_SUCCESS)
1886
+ return w->status;
1887
+
1888
+ return GENX_SUCCESS;
1889
+ }
1890
+
1891
+ /*******************************
1892
+ * Literal versions of the writing routines
1893
+ */
1894
+ genxStatus genxStartElementLiteral(genxWriter w,
1895
+ constUtf8 xmlns, constUtf8 type)
1896
+ {
1897
+ genxNamespace ns = NULL;
1898
+ genxElement e;
1899
+
1900
+ if (xmlns)
1901
+ {
1902
+ ns = genxDeclareNamespace(w, xmlns, NULL, &w->status);
1903
+ if (ns == NULL || w->status != GENX_SUCCESS)
1904
+ return w->status;
1905
+ }
1906
+ e = genxDeclareElement(w, ns, type, &w->status);
1907
+ if (e == NULL || w->status != GENX_SUCCESS)
1908
+ return w->status;
1909
+
1910
+ return genxStartElement(e);
1911
+ }
1912
+
1913
+ genxStatus genxAddAttributeLiteral(genxWriter w, constUtf8 xmlns,
1914
+ constUtf8 name, constUtf8 value)
1915
+ {
1916
+ genxNamespace ns = NULL;
1917
+ genxAttribute a;
1918
+
1919
+ if (xmlns)
1920
+ {
1921
+ ns = genxDeclareNamespace(w, xmlns, NULL, &w->status);
1922
+ if (ns == NULL && w->status != GENX_SUCCESS)
1923
+ return w->status;
1924
+ }
1925
+
1926
+ a = genxDeclareAttribute(w, ns, name, &w->status);
1927
+ if (a == NULL || w->status != GENX_SUCCESS)
1928
+ return w->status;
1929
+
1930
+ return genxAddAttribute(a, value);
1931
+ }
1932
+
1933
+ /*
1934
+ * return version
1935
+ */
1936
+ char * genxGetVersion()
1937
+ {
1938
+ return GENX_VERSION;
1939
+ }
1940
+