genx4r-fotopedia 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("genx4r");
4
+
5
+ create_makefile("genx4r");
data/ext/genx4r/genx.c ADDED
@@ -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
+