1104349Sphk/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
2104349Sphk   See the file COPYING for copying permission.
3104349Sphk*/
4104349Sphk
5104349Sphk#include <stdio.h>
6104349Sphk#include <stdlib.h>
7104349Sphk#include <stddef.h>
8104349Sphk#include <string.h>
9104349Sphk
10104349Sphk#include "expat.h"
11104349Sphk#include "codepage.h"
12104349Sphk#include "xmlfile.h"
13104349Sphk#include "xmltchar.h"
14104349Sphk
15104349Sphk#ifdef _MSC_VER
16104349Sphk#include <crtdbg.h>
17104349Sphk#endif
18104349Sphk
19178848Scokane#if defined(__amigaos__) && defined(__USE_INLINE__)
20178848Scokane#include <proto/expat.h>
21178848Scokane#endif
22178848Scokane
23104349Sphk/* This ensures proper sorting. */
24104349Sphk
25104349Sphk#define NSSEP T('\001')
26104349Sphk
27178848Scokanestatic void XMLCALL
28104349SphkcharacterData(void *userData, const XML_Char *s, int len)
29104349Sphk{
30178848Scokane  FILE *fp = (FILE *)userData;
31104349Sphk  for (; len > 0; --len, ++s) {
32104349Sphk    switch (*s) {
33104349Sphk    case T('&'):
34104349Sphk      fputts(T("&amp;"), fp);
35104349Sphk      break;
36104349Sphk    case T('<'):
37104349Sphk      fputts(T("&lt;"), fp);
38104349Sphk      break;
39104349Sphk    case T('>'):
40104349Sphk      fputts(T("&gt;"), fp);
41104349Sphk      break;
42104349Sphk#ifdef W3C14N
43104349Sphk    case 13:
44104349Sphk      fputts(T("&#xD;"), fp);
45104349Sphk      break;
46104349Sphk#else
47104349Sphk    case T('"'):
48104349Sphk      fputts(T("&quot;"), fp);
49104349Sphk      break;
50104349Sphk    case 9:
51104349Sphk    case 10:
52104349Sphk    case 13:
53104349Sphk      ftprintf(fp, T("&#%d;"), *s);
54104349Sphk      break;
55104349Sphk#endif
56104349Sphk    default:
57104349Sphk      puttc(*s, fp);
58104349Sphk      break;
59104349Sphk    }
60104349Sphk  }
61104349Sphk}
62104349Sphk
63104349Sphkstatic void
64104349SphkattributeValue(FILE *fp, const XML_Char *s)
65104349Sphk{
66104349Sphk  puttc(T('='), fp);
67104349Sphk  puttc(T('"'), fp);
68104349Sphk  for (;;) {
69104349Sphk    switch (*s) {
70104349Sphk    case 0:
71104349Sphk    case NSSEP:
72104349Sphk      puttc(T('"'), fp);
73104349Sphk      return;
74104349Sphk    case T('&'):
75104349Sphk      fputts(T("&amp;"), fp);
76104349Sphk      break;
77104349Sphk    case T('<'):
78104349Sphk      fputts(T("&lt;"), fp);
79104349Sphk      break;
80104349Sphk    case T('"'):
81104349Sphk      fputts(T("&quot;"), fp);
82104349Sphk      break;
83104349Sphk#ifdef W3C14N
84104349Sphk    case 9:
85104349Sphk      fputts(T("&#x9;"), fp);
86104349Sphk      break;
87104349Sphk    case 10:
88104349Sphk      fputts(T("&#xA;"), fp);
89104349Sphk      break;
90104349Sphk    case 13:
91104349Sphk      fputts(T("&#xD;"), fp);
92104349Sphk      break;
93104349Sphk#else
94104349Sphk    case T('>'):
95104349Sphk      fputts(T("&gt;"), fp);
96104349Sphk      break;
97104349Sphk    case 9:
98104349Sphk    case 10:
99104349Sphk    case 13:
100104349Sphk      ftprintf(fp, T("&#%d;"), *s);
101104349Sphk      break;
102104349Sphk#endif
103104349Sphk    default:
104104349Sphk      puttc(*s, fp);
105104349Sphk      break;
106104349Sphk    }
107104349Sphk    s++;
108104349Sphk  }
109104349Sphk}
110104349Sphk
111104349Sphk/* Lexicographically comparing UTF-8 encoded attribute values,
112104349Sphkis equivalent to lexicographically comparing based on the character number. */
113104349Sphk
114104349Sphkstatic int
115104349Sphkattcmp(const void *att1, const void *att2)
116104349Sphk{
117104349Sphk  return tcscmp(*(const XML_Char **)att1, *(const XML_Char **)att2);
118104349Sphk}
119104349Sphk
120178848Scokanestatic void XMLCALL
121104349SphkstartElement(void *userData, const XML_Char *name, const XML_Char **atts)
122104349Sphk{
123104349Sphk  int nAtts;
124104349Sphk  const XML_Char **p;
125178848Scokane  FILE *fp = (FILE *)userData;
126104349Sphk  puttc(T('<'), fp);
127104349Sphk  fputts(name, fp);
128104349Sphk
129104349Sphk  p = atts;
130104349Sphk  while (*p)
131104349Sphk    ++p;
132178848Scokane  nAtts = (int)((p - atts) >> 1);
133104349Sphk  if (nAtts > 1)
134104349Sphk    qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, attcmp);
135104349Sphk  while (*atts) {
136104349Sphk    puttc(T(' '), fp);
137104349Sphk    fputts(*atts++, fp);
138104349Sphk    attributeValue(fp, *atts);
139104349Sphk    atts++;
140104349Sphk  }
141104349Sphk  puttc(T('>'), fp);
142104349Sphk}
143104349Sphk
144178848Scokanestatic void XMLCALL
145104349SphkendElement(void *userData, const XML_Char *name)
146104349Sphk{
147178848Scokane  FILE *fp = (FILE *)userData;
148104349Sphk  puttc(T('<'), fp);
149104349Sphk  puttc(T('/'), fp);
150104349Sphk  fputts(name, fp);
151104349Sphk  puttc(T('>'), fp);
152104349Sphk}
153104349Sphk
154104349Sphkstatic int
155104349Sphknsattcmp(const void *p1, const void *p2)
156104349Sphk{
157104349Sphk  const XML_Char *att1 = *(const XML_Char **)p1;
158104349Sphk  const XML_Char *att2 = *(const XML_Char **)p2;
159104349Sphk  int sep1 = (tcsrchr(att1, NSSEP) != 0);
160104349Sphk  int sep2 = (tcsrchr(att1, NSSEP) != 0);
161104349Sphk  if (sep1 != sep2)
162104349Sphk    return sep1 - sep2;
163104349Sphk  return tcscmp(att1, att2);
164104349Sphk}
165104349Sphk
166178848Scokanestatic void XMLCALL
167104349SphkstartElementNS(void *userData, const XML_Char *name, const XML_Char **atts)
168104349Sphk{
169104349Sphk  int nAtts;
170104349Sphk  int nsi;
171104349Sphk  const XML_Char **p;
172178848Scokane  FILE *fp = (FILE *)userData;
173104349Sphk  const XML_Char *sep;
174104349Sphk  puttc(T('<'), fp);
175104349Sphk
176104349Sphk  sep = tcsrchr(name, NSSEP);
177104349Sphk  if (sep) {
178104349Sphk    fputts(T("n1:"), fp);
179104349Sphk    fputts(sep + 1, fp);
180104349Sphk    fputts(T(" xmlns:n1"), fp);
181104349Sphk    attributeValue(fp, name);
182104349Sphk    nsi = 2;
183104349Sphk  }
184104349Sphk  else {
185104349Sphk    fputts(name, fp);
186104349Sphk    nsi = 1;
187104349Sphk  }
188104349Sphk
189104349Sphk  p = atts;
190104349Sphk  while (*p)
191104349Sphk    ++p;
192178848Scokane  nAtts = (int)((p - atts) >> 1);
193104349Sphk  if (nAtts > 1)
194104349Sphk    qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, nsattcmp);
195104349Sphk  while (*atts) {
196104349Sphk    name = *atts++;
197104349Sphk    sep = tcsrchr(name, NSSEP);
198104349Sphk    puttc(T(' '), fp);
199104349Sphk    if (sep) {
200104349Sphk      ftprintf(fp, T("n%d:"), nsi);
201104349Sphk      fputts(sep + 1, fp);
202104349Sphk    }
203104349Sphk    else
204104349Sphk      fputts(name, fp);
205104349Sphk    attributeValue(fp, *atts);
206104349Sphk    if (sep) {
207104349Sphk      ftprintf(fp, T(" xmlns:n%d"), nsi++);
208104349Sphk      attributeValue(fp, name);
209104349Sphk    }
210104349Sphk    atts++;
211104349Sphk  }
212104349Sphk  puttc(T('>'), fp);
213104349Sphk}
214104349Sphk
215178848Scokanestatic void XMLCALL
216104349SphkendElementNS(void *userData, const XML_Char *name)
217104349Sphk{
218178848Scokane  FILE *fp = (FILE *)userData;
219104349Sphk  const XML_Char *sep;
220104349Sphk  puttc(T('<'), fp);
221104349Sphk  puttc(T('/'), fp);
222104349Sphk  sep = tcsrchr(name, NSSEP);
223104349Sphk  if (sep) {
224104349Sphk    fputts(T("n1:"), fp);
225104349Sphk    fputts(sep + 1, fp);
226104349Sphk  }
227104349Sphk  else
228104349Sphk    fputts(name, fp);
229104349Sphk  puttc(T('>'), fp);
230104349Sphk}
231104349Sphk
232104349Sphk#ifndef W3C14N
233104349Sphk
234178848Scokanestatic void XMLCALL
235104349SphkprocessingInstruction(void *userData, const XML_Char *target,
236104349Sphk                      const XML_Char *data)
237104349Sphk{
238178848Scokane  FILE *fp = (FILE *)userData;
239104349Sphk  puttc(T('<'), fp);
240104349Sphk  puttc(T('?'), fp);
241104349Sphk  fputts(target, fp);
242104349Sphk  puttc(T(' '), fp);
243104349Sphk  fputts(data, fp);
244104349Sphk  puttc(T('?'), fp);
245104349Sphk  puttc(T('>'), fp);
246104349Sphk}
247104349Sphk
248104349Sphk#endif /* not W3C14N */
249104349Sphk
250178848Scokanestatic void XMLCALL
251104349SphkdefaultCharacterData(void *userData, const XML_Char *s, int len)
252104349Sphk{
253104349Sphk  XML_DefaultCurrent((XML_Parser) userData);
254104349Sphk}
255104349Sphk
256178848Scokanestatic void XMLCALL
257104349SphkdefaultStartElement(void *userData, const XML_Char *name,
258104349Sphk                    const XML_Char **atts)
259104349Sphk{
260104349Sphk  XML_DefaultCurrent((XML_Parser) userData);
261104349Sphk}
262104349Sphk
263178848Scokanestatic void XMLCALL
264104349SphkdefaultEndElement(void *userData, const XML_Char *name)
265104349Sphk{
266104349Sphk  XML_DefaultCurrent((XML_Parser) userData);
267104349Sphk}
268104349Sphk
269178848Scokanestatic void XMLCALL
270104349SphkdefaultProcessingInstruction(void *userData, const XML_Char *target,
271104349Sphk                             const XML_Char *data)
272104349Sphk{
273104349Sphk  XML_DefaultCurrent((XML_Parser) userData);
274104349Sphk}
275104349Sphk
276178848Scokanestatic void XMLCALL
277104349SphknopCharacterData(void *userData, const XML_Char *s, int len)
278104349Sphk{
279104349Sphk}
280104349Sphk
281178848Scokanestatic void XMLCALL
282104349SphknopStartElement(void *userData, const XML_Char *name, const XML_Char **atts)
283104349Sphk{
284104349Sphk}
285104349Sphk
286178848Scokanestatic void XMLCALL
287104349SphknopEndElement(void *userData, const XML_Char *name)
288104349Sphk{
289104349Sphk}
290104349Sphk
291178848Scokanestatic void XMLCALL
292104349SphknopProcessingInstruction(void *userData, const XML_Char *target,
293104349Sphk                         const XML_Char *data)
294104349Sphk{
295104349Sphk}
296104349Sphk
297178848Scokanestatic void XMLCALL
298104349Sphkmarkup(void *userData, const XML_Char *s, int len)
299104349Sphk{
300178848Scokane  FILE *fp = (FILE *)XML_GetUserData((XML_Parser) userData);
301104349Sphk  for (; len > 0; --len, ++s)
302104349Sphk    puttc(*s, fp);
303104349Sphk}
304104349Sphk
305104349Sphkstatic void
306104349SphkmetaLocation(XML_Parser parser)
307104349Sphk{
308104349Sphk  const XML_Char *uri = XML_GetBase(parser);
309104349Sphk  if (uri)
310178848Scokane    ftprintf((FILE *)XML_GetUserData(parser), T(" uri=\"%s\""), uri);
311178848Scokane  ftprintf((FILE *)XML_GetUserData(parser),
312178848Scokane           T(" byte=\"%" XML_FMT_INT_MOD "d\" nbytes=\"%d\" \
313178848Scokane			 line=\"%" XML_FMT_INT_MOD "u\" col=\"%" XML_FMT_INT_MOD "u\""),
314104349Sphk           XML_GetCurrentByteIndex(parser),
315104349Sphk           XML_GetCurrentByteCount(parser),
316104349Sphk           XML_GetCurrentLineNumber(parser),
317104349Sphk           XML_GetCurrentColumnNumber(parser));
318104349Sphk}
319104349Sphk
320104349Sphkstatic void
321104349SphkmetaStartDocument(void *userData)
322104349Sphk{
323178848Scokane  fputts(T("<document>\n"), (FILE *)XML_GetUserData((XML_Parser) userData));
324104349Sphk}
325104349Sphk
326104349Sphkstatic void
327104349SphkmetaEndDocument(void *userData)
328104349Sphk{
329178848Scokane  fputts(T("</document>\n"), (FILE *)XML_GetUserData((XML_Parser) userData));
330104349Sphk}
331104349Sphk
332178848Scokanestatic void XMLCALL
333104349SphkmetaStartElement(void *userData, const XML_Char *name,
334104349Sphk                 const XML_Char **atts)
335104349Sphk{
336104349Sphk  XML_Parser parser = (XML_Parser) userData;
337178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
338104349Sphk  const XML_Char **specifiedAttsEnd
339104349Sphk    = atts + XML_GetSpecifiedAttributeCount(parser);
340104349Sphk  const XML_Char **idAttPtr;
341104349Sphk  int idAttIndex = XML_GetIdAttributeIndex(parser);
342104349Sphk  if (idAttIndex < 0)
343104349Sphk    idAttPtr = 0;
344104349Sphk  else
345104349Sphk    idAttPtr = atts + idAttIndex;
346104349Sphk
347104349Sphk  ftprintf(fp, T("<starttag name=\"%s\""), name);
348104349Sphk  metaLocation(parser);
349104349Sphk  if (*atts) {
350104349Sphk    fputts(T(">\n"), fp);
351104349Sphk    do {
352104349Sphk      ftprintf(fp, T("<attribute name=\"%s\" value=\""), atts[0]);
353178848Scokane      characterData(fp, atts[1], (int)tcslen(atts[1]));
354104349Sphk      if (atts >= specifiedAttsEnd)
355104349Sphk        fputts(T("\" defaulted=\"yes\"/>\n"), fp);
356104349Sphk      else if (atts == idAttPtr)
357104349Sphk        fputts(T("\" id=\"yes\"/>\n"), fp);
358104349Sphk      else
359104349Sphk        fputts(T("\"/>\n"), fp);
360104349Sphk    } while (*(atts += 2));
361104349Sphk    fputts(T("</starttag>\n"), fp);
362104349Sphk  }
363104349Sphk  else
364104349Sphk    fputts(T("/>\n"), fp);
365104349Sphk}
366104349Sphk
367178848Scokanestatic void XMLCALL
368104349SphkmetaEndElement(void *userData, const XML_Char *name)
369104349Sphk{
370104349Sphk  XML_Parser parser = (XML_Parser) userData;
371178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
372104349Sphk  ftprintf(fp, T("<endtag name=\"%s\""), name);
373104349Sphk  metaLocation(parser);
374104349Sphk  fputts(T("/>\n"), fp);
375104349Sphk}
376104349Sphk
377178848Scokanestatic void XMLCALL
378104349SphkmetaProcessingInstruction(void *userData, const XML_Char *target,
379104349Sphk                          const XML_Char *data)
380104349Sphk{
381104349Sphk  XML_Parser parser = (XML_Parser) userData;
382178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
383104349Sphk  ftprintf(fp, T("<pi target=\"%s\" data=\""), target);
384178848Scokane  characterData(fp, data, (int)tcslen(data));
385104349Sphk  puttc(T('"'), fp);
386104349Sphk  metaLocation(parser);
387104349Sphk  fputts(T("/>\n"), fp);
388104349Sphk}
389104349Sphk
390178848Scokanestatic void XMLCALL
391104349SphkmetaComment(void *userData, const XML_Char *data)
392104349Sphk{
393104349Sphk  XML_Parser parser = (XML_Parser) userData;
394178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
395104349Sphk  fputts(T("<comment data=\""), fp);
396178848Scokane  characterData(fp, data, (int)tcslen(data));
397104349Sphk  puttc(T('"'), fp);
398104349Sphk  metaLocation(parser);
399104349Sphk  fputts(T("/>\n"), fp);
400104349Sphk}
401104349Sphk
402178848Scokanestatic void XMLCALL
403104349SphkmetaStartCdataSection(void *userData)
404104349Sphk{
405104349Sphk  XML_Parser parser = (XML_Parser) userData;
406178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
407104349Sphk  fputts(T("<startcdata"), fp);
408104349Sphk  metaLocation(parser);
409104349Sphk  fputts(T("/>\n"), fp);
410104349Sphk}
411104349Sphk
412178848Scokanestatic void XMLCALL
413104349SphkmetaEndCdataSection(void *userData)
414104349Sphk{
415104349Sphk  XML_Parser parser = (XML_Parser) userData;
416178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
417104349Sphk  fputts(T("<endcdata"), fp);
418104349Sphk  metaLocation(parser);
419104349Sphk  fputts(T("/>\n"), fp);
420104349Sphk}
421104349Sphk
422178848Scokanestatic void XMLCALL
423104349SphkmetaCharacterData(void *userData, const XML_Char *s, int len)
424104349Sphk{
425104349Sphk  XML_Parser parser = (XML_Parser) userData;
426178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
427104349Sphk  fputts(T("<chars str=\""), fp);
428104349Sphk  characterData(fp, s, len);
429104349Sphk  puttc(T('"'), fp);
430104349Sphk  metaLocation(parser);
431104349Sphk  fputts(T("/>\n"), fp);
432104349Sphk}
433104349Sphk
434178848Scokanestatic void XMLCALL
435104349SphkmetaStartDoctypeDecl(void *userData,
436104349Sphk                     const XML_Char *doctypeName,
437104349Sphk                     const XML_Char *sysid,
438104349Sphk                     const XML_Char *pubid,
439104349Sphk                     int has_internal_subset)
440104349Sphk{
441104349Sphk  XML_Parser parser = (XML_Parser) userData;
442178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
443104349Sphk  ftprintf(fp, T("<startdoctype name=\"%s\""), doctypeName);
444104349Sphk  metaLocation(parser);
445104349Sphk  fputts(T("/>\n"), fp);
446104349Sphk}
447104349Sphk
448178848Scokanestatic void XMLCALL
449104349SphkmetaEndDoctypeDecl(void *userData)
450104349Sphk{
451104349Sphk  XML_Parser parser = (XML_Parser) userData;
452178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
453104349Sphk  fputts(T("<enddoctype"), fp);
454104349Sphk  metaLocation(parser);
455104349Sphk  fputts(T("/>\n"), fp);
456104349Sphk}
457104349Sphk
458178848Scokanestatic void XMLCALL
459104349SphkmetaNotationDecl(void *userData,
460104349Sphk                 const XML_Char *notationName,
461104349Sphk                 const XML_Char *base,
462104349Sphk                 const XML_Char *systemId,
463104349Sphk                 const XML_Char *publicId)
464104349Sphk{
465104349Sphk  XML_Parser parser = (XML_Parser) userData;
466178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
467104349Sphk  ftprintf(fp, T("<notation name=\"%s\""), notationName);
468104349Sphk  if (publicId)
469104349Sphk    ftprintf(fp, T(" public=\"%s\""), publicId);
470104349Sphk  if (systemId) {
471104349Sphk    fputts(T(" system=\""), fp);
472178848Scokane    characterData(fp, systemId, (int)tcslen(systemId));
473104349Sphk    puttc(T('"'), fp);
474104349Sphk  }
475104349Sphk  metaLocation(parser);
476104349Sphk  fputts(T("/>\n"), fp);
477104349Sphk}
478104349Sphk
479104349Sphk
480178848Scokanestatic void XMLCALL
481104349SphkmetaEntityDecl(void *userData,
482104349Sphk               const XML_Char *entityName,
483104349Sphk               int  is_param,
484104349Sphk               const XML_Char *value,
485104349Sphk               int  value_length,
486104349Sphk               const XML_Char *base,
487104349Sphk               const XML_Char *systemId,
488104349Sphk               const XML_Char *publicId,
489104349Sphk               const XML_Char *notationName)
490104349Sphk{
491104349Sphk  XML_Parser parser = (XML_Parser) userData;
492178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
493104349Sphk
494104349Sphk  if (value) {
495104349Sphk    ftprintf(fp, T("<entity name=\"%s\""), entityName);
496104349Sphk    metaLocation(parser);
497104349Sphk    puttc(T('>'), fp);
498104349Sphk    characterData(fp, value, value_length);
499104349Sphk    fputts(T("</entity/>\n"), fp);
500104349Sphk  }
501104349Sphk  else if (notationName) {
502104349Sphk    ftprintf(fp, T("<entity name=\"%s\""), entityName);
503104349Sphk    if (publicId)
504104349Sphk      ftprintf(fp, T(" public=\"%s\""), publicId);
505104349Sphk    fputts(T(" system=\""), fp);
506178848Scokane    characterData(fp, systemId, (int)tcslen(systemId));
507104349Sphk    puttc(T('"'), fp);
508104349Sphk    ftprintf(fp, T(" notation=\"%s\""), notationName);
509104349Sphk    metaLocation(parser);
510104349Sphk    fputts(T("/>\n"), fp);
511104349Sphk  }
512104349Sphk  else {
513104349Sphk    ftprintf(fp, T("<entity name=\"%s\""), entityName);
514104349Sphk    if (publicId)
515104349Sphk      ftprintf(fp, T(" public=\"%s\""), publicId);
516104349Sphk    fputts(T(" system=\""), fp);
517178848Scokane    characterData(fp, systemId, (int)tcslen(systemId));
518104349Sphk    puttc(T('"'), fp);
519104349Sphk    metaLocation(parser);
520104349Sphk    fputts(T("/>\n"), fp);
521104349Sphk  }
522104349Sphk}
523104349Sphk
524178848Scokanestatic void XMLCALL
525104349SphkmetaStartNamespaceDecl(void *userData,
526104349Sphk                       const XML_Char *prefix,
527104349Sphk                       const XML_Char *uri)
528104349Sphk{
529104349Sphk  XML_Parser parser = (XML_Parser) userData;
530178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
531104349Sphk  fputts(T("<startns"), fp);
532104349Sphk  if (prefix)
533104349Sphk    ftprintf(fp, T(" prefix=\"%s\""), prefix);
534104349Sphk  if (uri) {
535104349Sphk    fputts(T(" ns=\""), fp);
536178848Scokane    characterData(fp, uri, (int)tcslen(uri));
537104349Sphk    fputts(T("\"/>\n"), fp);
538104349Sphk  }
539104349Sphk  else
540104349Sphk    fputts(T("/>\n"), fp);
541104349Sphk}
542104349Sphk
543178848Scokanestatic void XMLCALL
544104349SphkmetaEndNamespaceDecl(void *userData, const XML_Char *prefix)
545104349Sphk{
546104349Sphk  XML_Parser parser = (XML_Parser) userData;
547178848Scokane  FILE *fp = (FILE *)XML_GetUserData(parser);
548104349Sphk  if (!prefix)
549104349Sphk    fputts(T("<endns/>\n"), fp);
550104349Sphk  else
551104349Sphk    ftprintf(fp, T("<endns prefix=\"%s\"/>\n"), prefix);
552104349Sphk}
553104349Sphk
554178848Scokanestatic int XMLCALL
555104349SphkunknownEncodingConvert(void *data, const char *p)
556104349Sphk{
557104349Sphk  return codepageConvert(*(int *)data, p);
558104349Sphk}
559104349Sphk
560178848Scokanestatic int XMLCALL
561104349SphkunknownEncoding(void *userData, const XML_Char *name, XML_Encoding *info)
562104349Sphk{
563104349Sphk  int cp;
564104349Sphk  static const XML_Char prefixL[] = T("windows-");
565104349Sphk  static const XML_Char prefixU[] = T("WINDOWS-");
566104349Sphk  int i;
567104349Sphk
568104349Sphk  for (i = 0; prefixU[i]; i++)
569104349Sphk    if (name[i] != prefixU[i] && name[i] != prefixL[i])
570104349Sphk      return 0;
571104349Sphk
572104349Sphk  cp = 0;
573104349Sphk  for (; name[i]; i++) {
574104349Sphk    static const XML_Char digits[] = T("0123456789");
575104349Sphk    const XML_Char *s = tcschr(digits, name[i]);
576104349Sphk    if (!s)
577104349Sphk      return 0;
578104349Sphk    cp *= 10;
579178848Scokane    cp += (int)(s - digits);
580104349Sphk    if (cp >= 0x10000)
581104349Sphk      return 0;
582104349Sphk  }
583104349Sphk  if (!codepageMap(cp, info->map))
584104349Sphk    return 0;
585104349Sphk  info->convert = unknownEncodingConvert;
586104349Sphk  /* We could just cast the code page integer to a void *,
587104349Sphk  and avoid the use of release. */
588104349Sphk  info->release = free;
589104349Sphk  info->data = malloc(sizeof(int));
590104349Sphk  if (!info->data)
591104349Sphk    return 0;
592104349Sphk  *(int *)info->data = cp;
593104349Sphk  return 1;
594104349Sphk}
595104349Sphk
596178848Scokanestatic int XMLCALL
597104349SphknotStandalone(void *userData)
598104349Sphk{
599104349Sphk  return 0;
600104349Sphk}
601104349Sphk
602104349Sphkstatic void
603104349SphkshowVersion(XML_Char *prog)
604104349Sphk{
605104349Sphk  XML_Char *s = prog;
606104349Sphk  XML_Char ch;
607104349Sphk  const XML_Feature *features = XML_GetFeatureList();
608104349Sphk  while ((ch = *s) != 0) {
609104349Sphk    if (ch == '/'
610178848Scokane#if (defined(WIN32) || defined(__WATCOMC__))
611104349Sphk        || ch == '\\'
612104349Sphk#endif
613104349Sphk        )
614104349Sphk      prog = s + 1;
615104349Sphk    ++s;
616104349Sphk  }
617104349Sphk  ftprintf(stdout, T("%s using %s\n"), prog, XML_ExpatVersion());
618104349Sphk  if (features != NULL && features[0].feature != XML_FEATURE_END) {
619104349Sphk    int i = 1;
620104349Sphk    ftprintf(stdout, T("%s"), features[0].name);
621104349Sphk    if (features[0].value)
622104349Sphk      ftprintf(stdout, T("=%ld"), features[0].value);
623104349Sphk    while (features[i].feature != XML_FEATURE_END) {
624104349Sphk      ftprintf(stdout, T(", %s"), features[i].name);
625104349Sphk      if (features[i].value)
626104349Sphk        ftprintf(stdout, T("=%ld"), features[i].value);
627104349Sphk      ++i;
628104349Sphk    }
629104349Sphk    ftprintf(stdout, T("\n"));
630104349Sphk  }
631104349Sphk}
632104349Sphk
633104349Sphkstatic void
634104349Sphkusage(const XML_Char *prog, int rc)
635104349Sphk{
636104349Sphk  ftprintf(stderr,
637104349Sphk           T("usage: %s [-n] [-p] [-r] [-s] [-w] [-x] [-d output-dir] "
638104349Sphk             "[-e encoding] file ...\n"), prog);
639104349Sphk  exit(rc);
640104349Sphk}
641104349Sphk
642104349Sphkint
643104349Sphktmain(int argc, XML_Char **argv)
644104349Sphk{
645104349Sphk  int i, j;
646104349Sphk  const XML_Char *outputDir = NULL;
647104349Sphk  const XML_Char *encoding = NULL;
648104349Sphk  unsigned processFlags = XML_MAP_FILE;
649104349Sphk  int windowsCodePages = 0;
650104349Sphk  int outputType = 0;
651104349Sphk  int useNamespaces = 0;
652104349Sphk  int requireStandalone = 0;
653178848Scokane  enum XML_ParamEntityParsing paramEntityParsing =
654178848Scokane    XML_PARAM_ENTITY_PARSING_NEVER;
655104349Sphk  int useStdin = 0;
656104349Sphk
657104349Sphk#ifdef _MSC_VER
658104349Sphk  _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
659104349Sphk#endif
660104349Sphk
661104349Sphk  i = 1;
662104349Sphk  j = 0;
663104349Sphk  while (i < argc) {
664104349Sphk    if (j == 0) {
665104349Sphk      if (argv[i][0] != T('-'))
666104349Sphk        break;
667104349Sphk      if (argv[i][1] == T('-') && argv[i][2] == T('\0')) {
668104349Sphk        i++;
669104349Sphk        break;
670104349Sphk      }
671104349Sphk      j++;
672104349Sphk    }
673104349Sphk    switch (argv[i][j]) {
674104349Sphk    case T('r'):
675104349Sphk      processFlags &= ~XML_MAP_FILE;
676104349Sphk      j++;
677104349Sphk      break;
678104349Sphk    case T('s'):
679104349Sphk      requireStandalone = 1;
680104349Sphk      j++;
681104349Sphk      break;
682104349Sphk    case T('n'):
683104349Sphk      useNamespaces = 1;
684104349Sphk      j++;
685104349Sphk      break;
686104349Sphk    case T('p'):
687104349Sphk      paramEntityParsing = XML_PARAM_ENTITY_PARSING_ALWAYS;
688104349Sphk      /* fall through */
689104349Sphk    case T('x'):
690104349Sphk      processFlags |= XML_EXTERNAL_ENTITIES;
691104349Sphk      j++;
692104349Sphk      break;
693104349Sphk    case T('w'):
694104349Sphk      windowsCodePages = 1;
695104349Sphk      j++;
696104349Sphk      break;
697104349Sphk    case T('m'):
698104349Sphk      outputType = 'm';
699104349Sphk      j++;
700104349Sphk      break;
701104349Sphk    case T('c'):
702104349Sphk      outputType = 'c';
703104349Sphk      useNamespaces = 0;
704104349Sphk      j++;
705104349Sphk      break;
706104349Sphk    case T('t'):
707104349Sphk      outputType = 't';
708104349Sphk      j++;
709104349Sphk      break;
710104349Sphk    case T('d'):
711104349Sphk      if (argv[i][j + 1] == T('\0')) {
712104349Sphk        if (++i == argc)
713104349Sphk          usage(argv[0], 2);
714104349Sphk        outputDir = argv[i];
715104349Sphk      }
716104349Sphk      else
717104349Sphk        outputDir = argv[i] + j + 1;
718104349Sphk      i++;
719104349Sphk      j = 0;
720104349Sphk      break;
721104349Sphk    case T('e'):
722104349Sphk      if (argv[i][j + 1] == T('\0')) {
723104349Sphk        if (++i == argc)
724104349Sphk          usage(argv[0], 2);
725104349Sphk        encoding = argv[i];
726104349Sphk      }
727104349Sphk      else
728104349Sphk        encoding = argv[i] + j + 1;
729104349Sphk      i++;
730104349Sphk      j = 0;
731104349Sphk      break;
732104349Sphk    case T('h'):
733104349Sphk      usage(argv[0], 0);
734104349Sphk      return 0;
735104349Sphk    case T('v'):
736104349Sphk      showVersion(argv[0]);
737104349Sphk      return 0;
738104349Sphk    case T('\0'):
739104349Sphk      if (j > 1) {
740104349Sphk        i++;
741104349Sphk        j = 0;
742104349Sphk        break;
743104349Sphk      }
744104349Sphk      /* fall through */
745104349Sphk    default:
746104349Sphk      usage(argv[0], 2);
747104349Sphk    }
748104349Sphk  }
749104349Sphk  if (i == argc) {
750104349Sphk    useStdin = 1;
751104349Sphk    processFlags &= ~XML_MAP_FILE;
752104349Sphk    i--;
753104349Sphk  }
754104349Sphk  for (; i < argc; i++) {
755104349Sphk    FILE *fp = 0;
756104349Sphk    XML_Char *outName = 0;
757104349Sphk    int result;
758104349Sphk    XML_Parser parser;
759104349Sphk    if (useNamespaces)
760104349Sphk      parser = XML_ParserCreateNS(encoding, NSSEP);
761104349Sphk    else
762104349Sphk      parser = XML_ParserCreate(encoding);
763104349Sphk    if (requireStandalone)
764104349Sphk      XML_SetNotStandaloneHandler(parser, notStandalone);
765104349Sphk    XML_SetParamEntityParsing(parser, paramEntityParsing);
766104349Sphk    if (outputType == 't') {
767104349Sphk      /* This is for doing timings; this gives a more realistic estimate of
768104349Sphk         the parsing time. */
769104349Sphk      outputDir = 0;
770104349Sphk      XML_SetElementHandler(parser, nopStartElement, nopEndElement);
771104349Sphk      XML_SetCharacterDataHandler(parser, nopCharacterData);
772104349Sphk      XML_SetProcessingInstructionHandler(parser, nopProcessingInstruction);
773104349Sphk    }
774104349Sphk    else if (outputDir) {
775178848Scokane      const XML_Char * delim = T("/");
776104349Sphk      const XML_Char *file = useStdin ? T("STDIN") : argv[i];
777178848Scokane      if (!useStdin) {
778178848Scokane        /* Jump after last (back)slash */
779178848Scokane        const XML_Char * lastDelim = tcsrchr(file, delim[0]);
780178848Scokane        if (lastDelim)
781178848Scokane          file = lastDelim + 1;
782178848Scokane#if (defined(WIN32) || defined(__WATCOMC__))
783178848Scokane        else {
784178848Scokane          const XML_Char * winDelim = T("\\");
785178848Scokane          lastDelim = tcsrchr(file, winDelim[0]);
786178848Scokane          if (lastDelim) {
787178848Scokane            file = lastDelim + 1;
788178848Scokane            delim = winDelim;
789178848Scokane          }
790178848Scokane        }
791104349Sphk#endif
792178848Scokane      }
793178848Scokane      outName = (XML_Char *)malloc((tcslen(outputDir) + tcslen(file) + 2)
794104349Sphk                       * sizeof(XML_Char));
795104349Sphk      tcscpy(outName, outputDir);
796178848Scokane      tcscat(outName, delim);
797104349Sphk      tcscat(outName, file);
798104349Sphk      fp = tfopen(outName, T("wb"));
799104349Sphk      if (!fp) {
800104349Sphk        tperror(outName);
801104349Sphk        exit(1);
802104349Sphk      }
803104349Sphk      setvbuf(fp, NULL, _IOFBF, 16384);
804104349Sphk#ifdef XML_UNICODE
805104349Sphk      puttc(0xFEFF, fp);
806104349Sphk#endif
807104349Sphk      XML_SetUserData(parser, fp);
808104349Sphk      switch (outputType) {
809104349Sphk      case 'm':
810104349Sphk        XML_UseParserAsHandlerArg(parser);
811104349Sphk        XML_SetElementHandler(parser, metaStartElement, metaEndElement);
812104349Sphk        XML_SetProcessingInstructionHandler(parser, metaProcessingInstruction);
813104349Sphk        XML_SetCommentHandler(parser, metaComment);
814104349Sphk        XML_SetCdataSectionHandler(parser, metaStartCdataSection,
815104349Sphk                                   metaEndCdataSection);
816104349Sphk        XML_SetCharacterDataHandler(parser, metaCharacterData);
817104349Sphk        XML_SetDoctypeDeclHandler(parser, metaStartDoctypeDecl,
818104349Sphk                                  metaEndDoctypeDecl);
819104349Sphk        XML_SetEntityDeclHandler(parser, metaEntityDecl);
820104349Sphk        XML_SetNotationDeclHandler(parser, metaNotationDecl);
821104349Sphk        XML_SetNamespaceDeclHandler(parser, metaStartNamespaceDecl,
822104349Sphk                                    metaEndNamespaceDecl);
823104349Sphk        metaStartDocument(parser);
824104349Sphk        break;
825104349Sphk      case 'c':
826104349Sphk        XML_UseParserAsHandlerArg(parser);
827104349Sphk        XML_SetDefaultHandler(parser, markup);
828104349Sphk        XML_SetElementHandler(parser, defaultStartElement, defaultEndElement);
829104349Sphk        XML_SetCharacterDataHandler(parser, defaultCharacterData);
830104349Sphk        XML_SetProcessingInstructionHandler(parser,
831104349Sphk                                            defaultProcessingInstruction);
832104349Sphk        break;
833104349Sphk      default:
834104349Sphk        if (useNamespaces)
835104349Sphk          XML_SetElementHandler(parser, startElementNS, endElementNS);
836104349Sphk        else
837104349Sphk          XML_SetElementHandler(parser, startElement, endElement);
838104349Sphk        XML_SetCharacterDataHandler(parser, characterData);
839104349Sphk#ifndef W3C14N
840104349Sphk        XML_SetProcessingInstructionHandler(parser, processingInstruction);
841104349Sphk#endif /* not W3C14N */
842104349Sphk        break;
843104349Sphk      }
844104349Sphk    }
845104349Sphk    if (windowsCodePages)
846104349Sphk      XML_SetUnknownEncodingHandler(parser, unknownEncoding, 0);
847104349Sphk    result = XML_ProcessFile(parser, useStdin ? NULL : argv[i], processFlags);
848104349Sphk    if (outputDir) {
849104349Sphk      if (outputType == 'm')
850104349Sphk        metaEndDocument(parser);
851104349Sphk      fclose(fp);
852247513Sdelphij      if (!result) {
853104349Sphk        tremove(outName);
854247513Sdelphij        exit(2);
855247513Sdelphij      }
856104349Sphk      free(outName);
857104349Sphk    }
858104349Sphk    XML_ParserFree(parser);
859104349Sphk  }
860104349Sphk  return 0;
861104349Sphk}
862