initial load of upstream version 1.06.32
[xmlrpc-c] / lib / expat / xmlwf / xmlwf.c
1 /*
2 Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
3 See the file copying.txt for copying permission.
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stddef.h>
9 #include <string.h>
10
11 #include "xmlparse.h"
12 #include "codepage.h"
13 #include "xmlfile.h"
14 #include "xmltchar.h"
15
16 #ifdef _MSC_VER
17 #include <crtdbg.h>
18 #endif
19
20 /* This ensures proper sorting. */
21
22 #define NSSEP T('\001')
23
24 static void characterData(void *userData, const XML_Char *s, int len)
25 {
26   FILE *fp = userData;
27   for (; len > 0; --len, ++s) {
28     switch (*s) {
29     case T('&'):
30       fputts(T("&amp;"), fp);
31       break;
32     case T('<'):
33       fputts(T("&lt;"), fp);
34       break;
35     case T('>'):
36       fputts(T("&gt;"), fp);
37       break;
38 #ifdef W3C14N
39     case 13:
40       fputts(T("&#xD;"), fp);
41       break;
42 #else
43     case T('"'):
44       fputts(T("&quot;"), fp);
45       break;
46     case 9:
47     case 10:
48     case 13:
49       ftprintf(fp, T("&#%d;"), *s);
50       break;
51 #endif
52     default:
53       puttc(*s, fp);
54       break;
55     }
56   }
57 }
58
59 static void attributeValue(FILE *fp, const XML_Char *s)
60 {
61   puttc(T('='), fp);
62   puttc(T('"'), fp);
63   for (;;) {
64     switch (*s) {
65     case 0:
66     case NSSEP:
67       puttc(T('"'), fp);
68       return;
69     case T('&'):
70       fputts(T("&amp;"), fp);
71       break;
72     case T('<'):
73       fputts(T("&lt;"), fp);
74       break;
75     case T('"'):
76       fputts(T("&quot;"), fp);
77       break;
78 #ifdef W3C14N
79     case 9:
80       fputts(T("&#x9;"), fp);
81       break;
82     case 10:
83       fputts(T("&#xA;"), fp);
84       break;
85     case 13:
86       fputts(T("&#xD;"), fp);
87       break;
88 #else
89     case T('>'):
90       fputts(T("&gt;"), fp);
91       break;
92     case 9:
93     case 10:
94     case 13:
95       ftprintf(fp, T("&#%d;"), *s);
96       break;
97 #endif
98     default:
99       puttc(*s, fp);
100       break;
101     }
102     s++;
103   }
104 }
105
106 /* Lexicographically comparing UTF-8 encoded attribute values,
107 is equivalent to lexicographically comparing based on the character number. */
108
109 static int attcmp(const void *att1, const void *att2)
110 {
111   return tcscmp(*(const XML_Char **)att1, *(const XML_Char **)att2);
112 }
113
114 static void startElement(void *userData, const XML_Char *name, const XML_Char **atts)
115 {
116   int nAtts;
117   const XML_Char **p;
118   FILE *fp = userData;
119   puttc(T('<'), fp);
120   fputts(name, fp);
121
122   p = atts;
123   while (*p)
124     ++p;
125   nAtts = (p - atts) >> 1;
126   if (nAtts > 1)
127     qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, attcmp);
128   while (*atts) {
129     puttc(T(' '), fp);
130     fputts(*atts++, fp);
131     attributeValue(fp, *atts);
132     atts++;
133   }
134   puttc(T('>'), fp);
135 }
136
137 static void endElement(void *userData, const XML_Char *name)
138 {
139   FILE *fp = userData;
140   puttc(T('<'), fp);
141   puttc(T('/'), fp);
142   fputts(name, fp);
143   puttc(T('>'), fp);
144 }
145
146 static int nsattcmp(const void *p1, const void *p2)
147 {
148   const XML_Char *att1 = *(const XML_Char **)p1;
149   const XML_Char *att2 = *(const XML_Char **)p2;
150   int sep1 = (tcsrchr(att1, NSSEP) != 0);
151   int sep2 = (tcsrchr(att1, NSSEP) != 0);
152   if (sep1 != sep2)
153     return sep1 - sep2;
154   return tcscmp(att1, att2);
155 }
156
157 static void startElementNS(void *userData, const XML_Char *name, const XML_Char **atts)
158 {
159   int nAtts;
160   int nsi;
161   const XML_Char **p;
162   FILE *fp = userData;
163   const XML_Char *sep;
164   puttc(T('<'), fp);
165
166   sep = tcsrchr(name, NSSEP);
167   if (sep) {
168     fputts(T("n1:"), fp);
169     fputts(sep + 1, fp);
170     fputts(T(" xmlns:n1"), fp);
171     attributeValue(fp, name);
172     nsi = 2;
173   }
174   else {
175     fputts(name, fp);
176     nsi = 1;
177   }
178
179   p = atts;
180   while (*p)
181     ++p;
182   nAtts = (p - atts) >> 1;
183   if (nAtts > 1)
184     qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, nsattcmp);
185   while (*atts) {
186     name = *atts++;
187     sep = tcsrchr(name, NSSEP);
188     puttc(T(' '), fp);
189     if (sep) {
190       ftprintf(fp, T("n%d:"), nsi);
191       fputts(sep + 1, fp);
192     }
193     else
194       fputts(name, fp);
195     attributeValue(fp, *atts);
196     if (sep) {
197       ftprintf(fp, T(" xmlns:n%d"), nsi++);
198       attributeValue(fp, name);
199     }
200     atts++;
201   }
202   puttc(T('>'), fp);
203 }
204
205 static void endElementNS(void *userData, const XML_Char *name)
206 {
207   FILE *fp = userData;
208   const XML_Char *sep;
209   puttc(T('<'), fp);
210   puttc(T('/'), fp);
211   sep = tcsrchr(name, NSSEP);
212   if (sep) {
213     fputts(T("n1:"), fp);
214     fputts(sep + 1, fp);
215   }
216   else
217     fputts(name, fp);
218   puttc(T('>'), fp);
219 }
220
221 #ifndef W3C14N
222
223 static void processingInstruction(void *userData, const XML_Char *target, const XML_Char *data)
224 {
225   FILE *fp = userData;
226   puttc(T('<'), fp);
227   puttc(T('?'), fp);
228   fputts(target, fp);
229   puttc(T(' '), fp);
230   fputts(data, fp);
231   puttc(T('?'), fp);
232   puttc(T('>'), fp);
233 }
234
235 #endif /* not W3C14N */
236
237 static void defaultCharacterData(XML_Parser parser, const XML_Char *s, int len)
238 {
239   XML_DefaultCurrent(parser);
240 }
241
242 static void defaultStartElement(XML_Parser parser, const XML_Char *name, const XML_Char **atts)
243 {
244   XML_DefaultCurrent(parser);
245 }
246
247 static void defaultEndElement(XML_Parser parser, const XML_Char *name)
248 {
249   XML_DefaultCurrent(parser);
250 }
251
252 static void defaultProcessingInstruction(XML_Parser parser, const XML_Char *target, const XML_Char *data)
253 {
254   XML_DefaultCurrent(parser);
255 }
256
257 static void nopCharacterData(XML_Parser parser, const XML_Char *s, int len)
258 {
259 }
260
261 static void nopStartElement(XML_Parser parser, const XML_Char *name, const XML_Char **atts)
262 {
263 }
264
265 static void nopEndElement(XML_Parser parser, const XML_Char *name)
266 {
267 }
268
269 static void nopProcessingInstruction(XML_Parser parser, const XML_Char *target, const XML_Char *data)
270 {
271 }
272
273 static void markup(XML_Parser parser, const XML_Char *s, int len)
274 {
275   FILE *fp = XML_GetUserData(parser);
276   for (; len > 0; --len, ++s)
277     puttc(*s, fp);
278 }
279
280 static
281 void metaLocation(XML_Parser parser)
282 {
283   const XML_Char *uri = XML_GetBase(parser);
284   if (uri)
285     ftprintf(XML_GetUserData(parser), T(" uri=\"%s\""), uri);
286   ftprintf(XML_GetUserData(parser),
287            T(" byte=\"%ld\" nbytes=\"%d\" line=\"%d\" col=\"%d\""),
288            XML_GetCurrentByteIndex(parser),
289            XML_GetCurrentByteCount(parser),
290            XML_GetCurrentLineNumber(parser),
291            XML_GetCurrentColumnNumber(parser));
292 }
293
294 static
295 void metaStartDocument(XML_Parser parser)
296 {
297   fputts(T("<document>\n"), XML_GetUserData(parser));
298 }
299
300 static
301 void metaEndDocument(XML_Parser parser)
302 {
303   fputts(T("</document>\n"), XML_GetUserData(parser));
304 }
305
306 static
307 void metaStartElement(XML_Parser parser, const XML_Char *name, const XML_Char **atts)
308 {
309   FILE *fp = XML_GetUserData(parser);
310   const XML_Char **specifiedAttsEnd
311     = atts + XML_GetSpecifiedAttributeCount(parser);
312   const XML_Char **idAttPtr;
313   int idAttIndex = XML_GetIdAttributeIndex(parser);
314   if (idAttIndex < 0)
315     idAttPtr = 0;
316   else
317     idAttPtr = atts + idAttIndex;
318     
319   ftprintf(fp, T("<starttag name=\"%s\""), name);
320   metaLocation(parser);
321   if (*atts) {
322     fputts(T(">\n"), fp);
323     do {
324       ftprintf(fp, T("<attribute name=\"%s\" value=\""), atts[0]);
325       characterData(fp, atts[1], tcslen(atts[1]));
326       if (atts >= specifiedAttsEnd)
327         fputts(T("\" defaulted=\"yes\"/>\n"), fp);
328       else if (atts == idAttPtr)
329         fputts(T("\" id=\"yes\"/>\n"), fp);
330       else
331         fputts(T("\"/>\n"), fp);
332     } while (*(atts += 2));
333     fputts(T("</starttag>\n"), fp);
334   }
335   else
336     fputts(T("/>\n"), fp);
337 }
338
339 static
340 void metaEndElement(XML_Parser parser, const XML_Char *name)
341 {
342   FILE *fp = XML_GetUserData(parser);
343   ftprintf(fp, T("<endtag name=\"%s\""), name);
344   metaLocation(parser);
345   fputts(T("/>\n"), fp);
346 }
347
348 static
349 void metaProcessingInstruction(XML_Parser parser, const XML_Char *target, const XML_Char *data)
350 {
351   FILE *fp = XML_GetUserData(parser);
352   ftprintf(fp, T("<pi target=\"%s\" data=\""), target);
353   characterData(fp, data, tcslen(data));
354   puttc(T('"'), fp);
355   metaLocation(parser);
356   fputts(T("/>\n"), fp);
357 }
358
359 static
360 void metaComment(XML_Parser parser, const XML_Char *data)
361 {
362   FILE *fp = XML_GetUserData(parser);
363   fputts(T("<comment data=\""), fp);
364   characterData(fp, data, tcslen(data));
365   puttc(T('"'), fp);
366   metaLocation(parser);
367   fputts(T("/>\n"), fp);
368 }
369
370 static
371 void metaStartCdataSection(XML_Parser parser)
372 {
373   FILE *fp = XML_GetUserData(parser);
374   fputts(T("<startcdata"), fp);
375   metaLocation(parser);
376   fputts(T("/>\n"), fp);
377 }
378
379 static
380 void metaEndCdataSection(XML_Parser parser)
381 {
382   FILE *fp = XML_GetUserData(parser);
383   fputts(T("<endcdata"), fp);
384   metaLocation(parser);
385   fputts(T("/>\n"), fp);
386 }
387
388 static
389 void metaCharacterData(XML_Parser parser, const XML_Char *s, int len)
390 {
391   FILE *fp = XML_GetUserData(parser);
392   fputts(T("<chars str=\""), fp);
393   characterData(fp, s, len);
394   puttc(T('"'), fp);
395   metaLocation(parser);
396   fputts(T("/>\n"), fp);
397 }
398
399 static
400 void metaStartDoctypeDecl(XML_Parser parser, const XML_Char *doctypeName)
401 {
402   FILE *fp = XML_GetUserData(parser);
403   ftprintf(fp, T("<startdoctype name=\"%s\""), doctypeName);
404   metaLocation(parser);
405   fputts(T("/>\n"), fp);
406 }
407
408 static
409 void metaEndDoctypeDecl(XML_Parser parser)
410 {
411   FILE *fp = XML_GetUserData(parser);
412   fputts(T("<enddoctype"), fp);
413   metaLocation(parser);
414   fputts(T("/>\n"), fp);
415 }
416
417 static
418 void metaUnparsedEntityDecl(XML_Parser parser,
419                             const XML_Char *entityName,
420                             const XML_Char *base,
421                             const XML_Char *systemId,
422                             const XML_Char *publicId,
423                             const XML_Char *notationName)
424 {
425   FILE *fp = XML_GetUserData(parser);
426   ftprintf(fp, T("<entity name=\"%s\""), entityName);
427   if (publicId)
428     ftprintf(fp, T(" public=\"%s\""), publicId);
429   fputts(T(" system=\""), fp);
430   characterData(fp, systemId, tcslen(systemId));
431   puttc(T('"'), fp);
432   ftprintf(fp, T(" notation=\"%s\""), notationName);
433   metaLocation(parser);
434   fputts(T("/>\n"), fp);
435 }
436
437 static
438 void metaNotationDecl(XML_Parser parser,
439                       const XML_Char *notationName,
440                       const XML_Char *base,
441                       const XML_Char *systemId,
442                       const XML_Char *publicId)
443 {
444   FILE *fp = XML_GetUserData(parser);
445   ftprintf(fp, T("<notation name=\"%s\""), notationName);
446   if (publicId)
447     ftprintf(fp, T(" public=\"%s\""), publicId);
448   if (systemId) {
449     fputts(T(" system=\""), fp);
450     characterData(fp, systemId, tcslen(systemId));
451     puttc(T('"'), fp);
452   }
453   metaLocation(parser);
454   fputts(T("/>\n"), fp);
455 }
456
457
458 static
459 void metaExternalParsedEntityDecl(XML_Parser parser,
460                                   const XML_Char *entityName,
461                                   const XML_Char *base,
462                                   const XML_Char *systemId,
463                                   const XML_Char *publicId)
464 {
465   FILE *fp = XML_GetUserData(parser);
466   ftprintf(fp, T("<entity name=\"%s\""), entityName);
467   if (publicId)
468     ftprintf(fp, T(" public=\"%s\""), publicId);
469   fputts(T(" system=\""), fp);
470   characterData(fp, systemId, tcslen(systemId));
471   puttc(T('"'), fp);
472   metaLocation(parser);
473   fputts(T("/>\n"), fp);
474 }
475
476 static
477 void metaInternalParsedEntityDecl(XML_Parser parser,
478                                   const XML_Char *entityName,
479                                   const XML_Char *text,
480                                   int textLen)
481 {
482   FILE *fp = XML_GetUserData(parser);
483   ftprintf(fp, T("<entity name=\"%s\""), entityName);
484   metaLocation(parser);
485   puttc(T('>'), fp);
486   characterData(fp, text, textLen);
487   fputts(T("</entity/>\n"), fp);
488 }
489
490 static
491 void metaStartNamespaceDecl(XML_Parser parser,
492                             const XML_Char *prefix,
493                             const XML_Char *uri)
494 {
495   FILE *fp = XML_GetUserData(parser);
496   fputts(T("<startns"), fp);
497   if (prefix)
498     ftprintf(fp, T(" prefix=\"%s\""), prefix);
499   if (uri) {
500     fputts(T(" ns=\""), fp);
501     characterData(fp, uri, tcslen(uri));
502     fputts(T("\"/>\n"), fp);
503   }
504   else
505     fputts(T("/>\n"), fp);
506 }
507
508 static
509 void metaEndNamespaceDecl(XML_Parser parser, const XML_Char *prefix)
510 {
511   FILE *fp = XML_GetUserData(parser);
512   if (!prefix)
513     fputts(T("<endns/>\n"), fp);
514   else
515     ftprintf(fp, T("<endns prefix=\"%s\"/>\n"), prefix);
516 }
517
518 static
519 int unknownEncodingConvert(void *data, const char *p)
520 {
521   return codepageConvert(*(int *)data, p);
522 }
523
524 static
525 int unknownEncoding(void *userData,
526                     const XML_Char *name,
527                     XML_Encoding *info)
528 {
529   int cp;
530   static const XML_Char prefixL[] = T("windows-");
531   static const XML_Char prefixU[] = T("WINDOWS-");
532   int i;
533
534   for (i = 0; prefixU[i]; i++)
535     if (name[i] != prefixU[i] && name[i] != prefixL[i])
536       return 0;
537   
538   cp = 0;
539   for (; name[i]; i++) {
540     static const XML_Char digits[] = T("0123456789");
541     const XML_Char *s = tcschr(digits, name[i]);
542     if (!s)
543       return 0;
544     cp *= 10;
545     cp += s - digits;
546     if (cp >= 0x10000)
547       return 0;
548   }
549   if (!codepageMap(cp, info->map))
550     return 0;
551   info->convert = unknownEncodingConvert;
552   /* We could just cast the code page integer to a void *,
553   and avoid the use of release. */
554   info->release = free;
555   info->data = malloc(sizeof(int));
556   if (!info->data)
557     return 0;
558   *(int *)info->data = cp;
559   return 1;
560 }
561
562 static
563 int notStandalone(void *userData)
564 {
565   return 0;
566 }
567
568 static
569 void usage(const XML_Char *prog)
570 {
571   ftprintf(stderr, T("usage: %s [-n] [-p] [-r] [-s] [-w] [-x] [-d output-dir] [-e encoding] file ...\n"), prog);
572   exit(1);
573 }
574
575 int tmain(int argc, XML_Char **argv)
576 {
577   int i, j;
578   const XML_Char *outputDir = 0;
579   const XML_Char *encoding = 0;
580   unsigned processFlags = XML_MAP_FILE;
581   int windowsCodePages = 0;
582   int outputType = 0;
583   int useNamespaces = 0;
584   int requireStandalone = 0;
585   int paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
586
587 #ifdef _MSC_VER
588   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
589 #endif
590
591   i = 1;
592   j = 0;
593   while (i < argc) {
594     if (j == 0) {
595       if (argv[i][0] != T('-'))
596         break;
597       if (argv[i][1] == T('-') && argv[i][2] == T('\0')) {
598         i++;
599         break;
600       }
601       j++;
602     }
603     switch (argv[i][j]) {
604     case T('r'):
605       processFlags &= ~XML_MAP_FILE;
606       j++;
607       break;
608     case T('s'):
609       requireStandalone = 1;
610       j++;
611       break;
612     case T('n'):
613       useNamespaces = 1;
614       j++;
615       break;
616     case T('p'):
617       paramEntityParsing = XML_PARAM_ENTITY_PARSING_ALWAYS;
618       /* fall through */
619     case T('x'):
620       processFlags |= XML_EXTERNAL_ENTITIES;
621       j++;
622       break;
623     case T('w'):
624       windowsCodePages = 1;
625       j++;
626       break;
627     case T('m'):
628       outputType = 'm';
629       j++;
630       break;
631     case T('c'):
632       outputType = 'c';
633       useNamespaces = 0;
634       j++;
635       break;
636     case T('t'):
637       outputType = 't';
638       j++;
639       break;
640     case T('d'):
641       if (argv[i][j + 1] == T('\0')) {
642         if (++i == argc)
643           usage(argv[0]);
644         outputDir = argv[i];
645       }
646       else
647         outputDir = argv[i] + j + 1;
648       i++;
649       j = 0;
650       break;
651     case T('e'):
652       if (argv[i][j + 1] == T('\0')) {
653         if (++i == argc)
654           usage(argv[0]);
655         encoding = argv[i];
656       }
657       else
658         encoding = argv[i] + j + 1;
659       i++;
660       j = 0;
661       break;
662     case T('\0'):
663       if (j > 1) {
664         i++;
665         j = 0;
666         break;
667       }
668       /* fall through */
669     default:
670       usage(argv[0]);
671     }
672   }
673   if (i == argc)
674     usage(argv[0]);
675   for (; i < argc; i++) {
676     FILE *fp = 0;
677     XML_Char *outName = 0;
678     int result;
679     XML_Parser parser;
680     if (useNamespaces)
681       parser = XML_ParserCreateNS(encoding, NSSEP);
682     else
683       parser = XML_ParserCreate(encoding);
684     if (requireStandalone)
685       XML_SetNotStandaloneHandler(parser, notStandalone);
686     XML_SetParamEntityParsing(parser, paramEntityParsing);
687     if (outputType == 't') {
688       /* This is for doing timings; this gives a more realistic estimate of
689          the parsing time. */
690       outputDir = 0;
691       XML_SetElementHandler(parser, nopStartElement, nopEndElement);
692       XML_SetCharacterDataHandler(parser, nopCharacterData);
693       XML_SetProcessingInstructionHandler(parser, nopProcessingInstruction);
694     }
695     else if (outputDir) {
696       const XML_Char *file = argv[i];
697       if (tcsrchr(file, T('/')))
698         file = tcsrchr(file, T('/')) + 1;
699 #ifdef WIN32
700       if (tcsrchr(file, T('\\')))
701         file = tcsrchr(file, T('\\')) + 1;
702 #endif
703       outName = malloc((tcslen(outputDir) + tcslen(file) + 2) * sizeof(XML_Char));
704       tcscpy(outName, outputDir);
705       tcscat(outName, T("/"));
706       tcscat(outName, file);
707       fp = tfopen(outName, T("wb"));
708       if (!fp) {
709         tperror(outName);
710         exit(1);
711       }
712       setvbuf(fp, NULL, _IOFBF, 16384);
713 #ifdef XML_UNICODE
714       puttc(0xFEFF, fp);
715 #endif
716       XML_SetUserData(parser, fp);
717       switch (outputType) {
718       case 'm':
719         XML_UseParserAsHandlerArg(parser);
720         XML_SetElementHandler(parser, metaStartElement, metaEndElement);
721         XML_SetProcessingInstructionHandler(parser, metaProcessingInstruction);
722         XML_SetCommentHandler(parser, metaComment);
723         XML_SetCdataSectionHandler(parser, metaStartCdataSection, metaEndCdataSection);
724         XML_SetCharacterDataHandler(parser, metaCharacterData);
725         XML_SetDoctypeDeclHandler(parser, metaStartDoctypeDecl, metaEndDoctypeDecl);
726         XML_SetUnparsedEntityDeclHandler(parser, metaUnparsedEntityDecl);
727         XML_SetNotationDeclHandler(parser, metaNotationDecl);
728         XML_SetExternalParsedEntityDeclHandler(parser, metaExternalParsedEntityDecl);
729         XML_SetInternalParsedEntityDeclHandler(parser, metaInternalParsedEntityDecl);
730         XML_SetNamespaceDeclHandler(parser, metaStartNamespaceDecl, metaEndNamespaceDecl);
731         metaStartDocument(parser);
732         break;
733       case 'c':
734         XML_UseParserAsHandlerArg(parser);
735         XML_SetDefaultHandler(parser, markup);
736         XML_SetElementHandler(parser, defaultStartElement, defaultEndElement);
737         XML_SetCharacterDataHandler(parser, defaultCharacterData);
738         XML_SetProcessingInstructionHandler(parser, defaultProcessingInstruction);
739         break;
740       default:
741         if (useNamespaces)
742           XML_SetElementHandler(parser, startElementNS, endElementNS);
743         else
744           XML_SetElementHandler(parser, startElement, endElement);
745         XML_SetCharacterDataHandler(parser, characterData);
746 #ifndef W3C14N
747         XML_SetProcessingInstructionHandler(parser, processingInstruction);
748 #endif /* not W3C14N */
749         break;
750       }
751     }
752     if (windowsCodePages)
753       XML_SetUnknownEncodingHandler(parser, unknownEncoding, 0);
754     result = XML_ProcessFile(parser, argv[i], processFlags);
755     if (outputDir) {
756       if (outputType == 'm')
757         metaEndDocument(parser);
758       fclose(fp);
759       if (!result)
760         tremove(outName);
761       free(outName);
762     }
763     XML_ParserFree(parser);
764   }
765   return 0;
766 }