1355604Sdelphij/*
2355604Sdelphij                            __  __            _
3355604Sdelphij                         ___\ \/ /_ __   __ _| |_
4355604Sdelphij                        / _ \\  /| '_ \ / _` | __|
5355604Sdelphij                       |  __//  \| |_) | (_| | |_
6355604Sdelphij                        \___/_/\_\ .__/ \__,_|\__|
7355604Sdelphij                                 |_| XML parser
8355604Sdelphij
9355604Sdelphij   Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
10355604Sdelphij   Copyright (c) 2000-2017 Expat development team
11355604Sdelphij   Licensed under the MIT license:
12355604Sdelphij
13355604Sdelphij   Permission is  hereby granted,  free of charge,  to any  person obtaining
14355604Sdelphij   a  copy  of  this  software   and  associated  documentation  files  (the
15355604Sdelphij   "Software"),  to  deal in  the  Software  without restriction,  including
16355604Sdelphij   without  limitation the  rights  to use,  copy,  modify, merge,  publish,
17355604Sdelphij   distribute, sublicense, and/or sell copies of the Software, and to permit
18355604Sdelphij   persons  to whom  the Software  is  furnished to  do so,  subject to  the
19355604Sdelphij   following conditions:
20355604Sdelphij
21355604Sdelphij   The above copyright  notice and this permission notice  shall be included
22355604Sdelphij   in all copies or substantial portions of the Software.
23355604Sdelphij
24355604Sdelphij   THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
25355604Sdelphij   EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
26355604Sdelphij   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
27355604Sdelphij   NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
28355604Sdelphij   DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
29355604Sdelphij   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
30355604Sdelphij   USE OR OTHER DEALINGS IN THE SOFTWARE.
31104349Sphk*/
32104349Sphk
33355604Sdelphij#include <assert.h>
34104349Sphk#include <stdio.h>
35104349Sphk#include <stdlib.h>
36104349Sphk#include <stddef.h>
37104349Sphk#include <string.h>
38104349Sphk
39104349Sphk#include "expat.h"
40104349Sphk#include "codepage.h"
41355604Sdelphij#include "internal.h" /* for UNUSED_P only */
42104349Sphk#include "xmlfile.h"
43104349Sphk#include "xmltchar.h"
44104349Sphk
45104349Sphk#ifdef _MSC_VER
46355604Sdelphij#  include <crtdbg.h>
47104349Sphk#endif
48104349Sphk
49355604Sdelphij#ifdef XML_UNICODE
50355604Sdelphij#  include <wchar.h>
51178848Scokane#endif
52178848Scokane
53355604Sdelphij/* Structures for handler user data */
54355604Sdelphijtypedef struct NotationList {
55355604Sdelphij  struct NotationList *next;
56355604Sdelphij  const XML_Char *notationName;
57355604Sdelphij  const XML_Char *systemId;
58355604Sdelphij  const XML_Char *publicId;
59355604Sdelphij} NotationList;
60355604Sdelphij
61355604Sdelphijtypedef struct xmlwfUserData {
62355604Sdelphij  FILE *fp;
63355604Sdelphij  NotationList *notationListHead;
64355604Sdelphij  const XML_Char *currentDoctypeName;
65355604Sdelphij} XmlwfUserData;
66355604Sdelphij
67104349Sphk/* This ensures proper sorting. */
68104349Sphk
69104349Sphk#define NSSEP T('\001')
70104349Sphk
71178848Scokanestatic void XMLCALL
72355604SdelphijcharacterData(void *userData, const XML_Char *s, int len) {
73355604Sdelphij  FILE *fp = ((XmlwfUserData *)userData)->fp;
74104349Sphk  for (; len > 0; --len, ++s) {
75104349Sphk    switch (*s) {
76104349Sphk    case T('&'):
77104349Sphk      fputts(T("&amp;"), fp);
78104349Sphk      break;
79104349Sphk    case T('<'):
80104349Sphk      fputts(T("&lt;"), fp);
81104349Sphk      break;
82104349Sphk    case T('>'):
83104349Sphk      fputts(T("&gt;"), fp);
84104349Sphk      break;
85104349Sphk#ifdef W3C14N
86104349Sphk    case 13:
87104349Sphk      fputts(T("&#xD;"), fp);
88104349Sphk      break;
89104349Sphk#else
90104349Sphk    case T('"'):
91104349Sphk      fputts(T("&quot;"), fp);
92104349Sphk      break;
93104349Sphk    case 9:
94104349Sphk    case 10:
95104349Sphk    case 13:
96104349Sphk      ftprintf(fp, T("&#%d;"), *s);
97104349Sphk      break;
98104349Sphk#endif
99104349Sphk    default:
100104349Sphk      puttc(*s, fp);
101104349Sphk      break;
102104349Sphk    }
103104349Sphk  }
104104349Sphk}
105104349Sphk
106104349Sphkstatic void
107355604SdelphijattributeValue(FILE *fp, const XML_Char *s) {
108104349Sphk  puttc(T('='), fp);
109104349Sphk  puttc(T('"'), fp);
110355604Sdelphij  assert(s);
111104349Sphk  for (;;) {
112104349Sphk    switch (*s) {
113104349Sphk    case 0:
114104349Sphk    case NSSEP:
115104349Sphk      puttc(T('"'), fp);
116104349Sphk      return;
117104349Sphk    case T('&'):
118104349Sphk      fputts(T("&amp;"), fp);
119104349Sphk      break;
120104349Sphk    case T('<'):
121104349Sphk      fputts(T("&lt;"), fp);
122104349Sphk      break;
123104349Sphk    case T('"'):
124104349Sphk      fputts(T("&quot;"), fp);
125104349Sphk      break;
126104349Sphk#ifdef W3C14N
127104349Sphk    case 9:
128104349Sphk      fputts(T("&#x9;"), fp);
129104349Sphk      break;
130104349Sphk    case 10:
131104349Sphk      fputts(T("&#xA;"), fp);
132104349Sphk      break;
133104349Sphk    case 13:
134104349Sphk      fputts(T("&#xD;"), fp);
135104349Sphk      break;
136104349Sphk#else
137104349Sphk    case T('>'):
138104349Sphk      fputts(T("&gt;"), fp);
139104349Sphk      break;
140104349Sphk    case 9:
141104349Sphk    case 10:
142104349Sphk    case 13:
143104349Sphk      ftprintf(fp, T("&#%d;"), *s);
144104349Sphk      break;
145104349Sphk#endif
146104349Sphk    default:
147104349Sphk      puttc(*s, fp);
148104349Sphk      break;
149104349Sphk    }
150104349Sphk    s++;
151104349Sphk  }
152104349Sphk}
153104349Sphk
154104349Sphk/* Lexicographically comparing UTF-8 encoded attribute values,
155104349Sphkis equivalent to lexicographically comparing based on the character number. */
156104349Sphk
157104349Sphkstatic int
158355604Sdelphijattcmp(const void *att1, const void *att2) {
159104349Sphk  return tcscmp(*(const XML_Char **)att1, *(const XML_Char **)att2);
160104349Sphk}
161104349Sphk
162178848Scokanestatic void XMLCALL
163355604SdelphijstartElement(void *userData, const XML_Char *name, const XML_Char **atts) {
164104349Sphk  int nAtts;
165104349Sphk  const XML_Char **p;
166355604Sdelphij  FILE *fp = ((XmlwfUserData *)userData)->fp;
167104349Sphk  puttc(T('<'), fp);
168104349Sphk  fputts(name, fp);
169104349Sphk
170104349Sphk  p = atts;
171104349Sphk  while (*p)
172104349Sphk    ++p;
173178848Scokane  nAtts = (int)((p - atts) >> 1);
174104349Sphk  if (nAtts > 1)
175104349Sphk    qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, attcmp);
176104349Sphk  while (*atts) {
177104349Sphk    puttc(T(' '), fp);
178104349Sphk    fputts(*atts++, fp);
179104349Sphk    attributeValue(fp, *atts);
180104349Sphk    atts++;
181104349Sphk  }
182104349Sphk  puttc(T('>'), fp);
183104349Sphk}
184104349Sphk
185178848Scokanestatic void XMLCALL
186355604SdelphijendElement(void *userData, const XML_Char *name) {
187355604Sdelphij  FILE *fp = ((XmlwfUserData *)userData)->fp;
188104349Sphk  puttc(T('<'), fp);
189104349Sphk  puttc(T('/'), fp);
190104349Sphk  fputts(name, fp);
191104349Sphk  puttc(T('>'), fp);
192104349Sphk}
193104349Sphk
194104349Sphkstatic int
195355604Sdelphijnsattcmp(const void *p1, const void *p2) {
196104349Sphk  const XML_Char *att1 = *(const XML_Char **)p1;
197104349Sphk  const XML_Char *att2 = *(const XML_Char **)p2;
198104349Sphk  int sep1 = (tcsrchr(att1, NSSEP) != 0);
199104349Sphk  int sep2 = (tcsrchr(att1, NSSEP) != 0);
200104349Sphk  if (sep1 != sep2)
201104349Sphk    return sep1 - sep2;
202104349Sphk  return tcscmp(att1, att2);
203104349Sphk}
204104349Sphk
205178848Scokanestatic void XMLCALL
206355604SdelphijstartElementNS(void *userData, const XML_Char *name, const XML_Char **atts) {
207104349Sphk  int nAtts;
208104349Sphk  int nsi;
209104349Sphk  const XML_Char **p;
210355604Sdelphij  FILE *fp = ((XmlwfUserData *)userData)->fp;
211104349Sphk  const XML_Char *sep;
212104349Sphk  puttc(T('<'), fp);
213104349Sphk
214104349Sphk  sep = tcsrchr(name, NSSEP);
215104349Sphk  if (sep) {
216104349Sphk    fputts(T("n1:"), fp);
217104349Sphk    fputts(sep + 1, fp);
218104349Sphk    fputts(T(" xmlns:n1"), fp);
219104349Sphk    attributeValue(fp, name);
220104349Sphk    nsi = 2;
221355604Sdelphij  } else {
222104349Sphk    fputts(name, fp);
223104349Sphk    nsi = 1;
224104349Sphk  }
225104349Sphk
226104349Sphk  p = atts;
227104349Sphk  while (*p)
228104349Sphk    ++p;
229178848Scokane  nAtts = (int)((p - atts) >> 1);
230104349Sphk  if (nAtts > 1)
231104349Sphk    qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, nsattcmp);
232104349Sphk  while (*atts) {
233104349Sphk    name = *atts++;
234104349Sphk    sep = tcsrchr(name, NSSEP);
235104349Sphk    puttc(T(' '), fp);
236104349Sphk    if (sep) {
237104349Sphk      ftprintf(fp, T("n%d:"), nsi);
238104349Sphk      fputts(sep + 1, fp);
239355604Sdelphij    } else
240104349Sphk      fputts(name, fp);
241104349Sphk    attributeValue(fp, *atts);
242104349Sphk    if (sep) {
243104349Sphk      ftprintf(fp, T(" xmlns:n%d"), nsi++);
244104349Sphk      attributeValue(fp, name);
245104349Sphk    }
246104349Sphk    atts++;
247104349Sphk  }
248104349Sphk  puttc(T('>'), fp);
249104349Sphk}
250104349Sphk
251178848Scokanestatic void XMLCALL
252355604SdelphijendElementNS(void *userData, const XML_Char *name) {
253355604Sdelphij  FILE *fp = ((XmlwfUserData *)userData)->fp;
254104349Sphk  const XML_Char *sep;
255104349Sphk  puttc(T('<'), fp);
256104349Sphk  puttc(T('/'), fp);
257104349Sphk  sep = tcsrchr(name, NSSEP);
258104349Sphk  if (sep) {
259104349Sphk    fputts(T("n1:"), fp);
260104349Sphk    fputts(sep + 1, fp);
261355604Sdelphij  } else
262104349Sphk    fputts(name, fp);
263104349Sphk  puttc(T('>'), fp);
264104349Sphk}
265104349Sphk
266104349Sphk#ifndef W3C14N
267104349Sphk
268178848Scokanestatic void XMLCALL
269104349SphkprocessingInstruction(void *userData, const XML_Char *target,
270355604Sdelphij                      const XML_Char *data) {
271355604Sdelphij  FILE *fp = ((XmlwfUserData *)userData)->fp;
272104349Sphk  puttc(T('<'), fp);
273104349Sphk  puttc(T('?'), fp);
274104349Sphk  fputts(target, fp);
275104349Sphk  puttc(T(' '), fp);
276104349Sphk  fputts(data, fp);
277104349Sphk  puttc(T('?'), fp);
278104349Sphk  puttc(T('>'), fp);
279104349Sphk}
280104349Sphk
281355604Sdelphijstatic XML_Char *
282355604Sdelphijxcsdup(const XML_Char *s) {
283355604Sdelphij  XML_Char *result;
284355604Sdelphij  int count = 0;
285355604Sdelphij  int numBytes;
286355604Sdelphij
287355604Sdelphij  /* Get the length of the string, including terminator */
288355604Sdelphij  while (s[count++] != 0) {
289355604Sdelphij    /* Do nothing */
290355604Sdelphij  }
291355604Sdelphij  numBytes = count * sizeof(XML_Char);
292355604Sdelphij  result = malloc(numBytes);
293355604Sdelphij  if (result == NULL)
294355604Sdelphij    return NULL;
295355604Sdelphij  memcpy(result, s, numBytes);
296355604Sdelphij  return result;
297355604Sdelphij}
298355604Sdelphij
299355604Sdelphijstatic void XMLCALL
300355604SdelphijstartDoctypeDecl(void *userData, const XML_Char *doctypeName,
301355604Sdelphij                 const XML_Char *sysid, const XML_Char *publid,
302355604Sdelphij                 int has_internal_subset) {
303355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)userData;
304355604Sdelphij  UNUSED_P(sysid);
305355604Sdelphij  UNUSED_P(publid);
306355604Sdelphij  UNUSED_P(has_internal_subset);
307355604Sdelphij  data->currentDoctypeName = xcsdup(doctypeName);
308355604Sdelphij}
309355604Sdelphij
310355604Sdelphijstatic void
311355604SdelphijfreeNotations(XmlwfUserData *data) {
312355604Sdelphij  NotationList *notationListHead = data->notationListHead;
313355604Sdelphij
314355604Sdelphij  while (notationListHead != NULL) {
315355604Sdelphij    NotationList *next = notationListHead->next;
316355604Sdelphij    free((void *)notationListHead->notationName);
317355604Sdelphij    free((void *)notationListHead->systemId);
318355604Sdelphij    free((void *)notationListHead->publicId);
319355604Sdelphij    free(notationListHead);
320355604Sdelphij    notationListHead = next;
321355604Sdelphij  }
322355604Sdelphij  data->notationListHead = NULL;
323355604Sdelphij}
324355604Sdelphij
325355604Sdelphijstatic int
326355604Sdelphijxcscmp(const XML_Char *xs, const XML_Char *xt) {
327355604Sdelphij  while (*xs != 0 && *xt != 0) {
328355604Sdelphij    if (*xs < *xt)
329355604Sdelphij      return -1;
330355604Sdelphij    if (*xs > *xt)
331355604Sdelphij      return 1;
332355604Sdelphij    xs++;
333355604Sdelphij    xt++;
334355604Sdelphij  }
335355604Sdelphij  if (*xs < *xt)
336355604Sdelphij    return -1;
337355604Sdelphij  if (*xs > *xt)
338355604Sdelphij    return 1;
339355604Sdelphij  return 0;
340355604Sdelphij}
341355604Sdelphij
342355604Sdelphijstatic int
343355604SdelphijnotationCmp(const void *a, const void *b) {
344355604Sdelphij  const NotationList *const n1 = *(NotationList **)a;
345355604Sdelphij  const NotationList *const n2 = *(NotationList **)b;
346355604Sdelphij
347355604Sdelphij  return xcscmp(n1->notationName, n2->notationName);
348355604Sdelphij}
349355604Sdelphij
350355604Sdelphijstatic void XMLCALL
351355604SdelphijendDoctypeDecl(void *userData) {
352355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)userData;
353355604Sdelphij  NotationList **notations;
354355604Sdelphij  int notationCount = 0;
355355604Sdelphij  NotationList *p;
356355604Sdelphij  int i;
357355604Sdelphij
358355604Sdelphij  /* How many notations do we have? */
359355604Sdelphij  for (p = data->notationListHead; p != NULL; p = p->next)
360355604Sdelphij    notationCount++;
361355604Sdelphij  if (notationCount == 0) {
362355604Sdelphij    /* Nothing to report */
363355604Sdelphij    free((void *)data->currentDoctypeName);
364355604Sdelphij    data->currentDoctypeName = NULL;
365355604Sdelphij    return;
366355604Sdelphij  }
367355604Sdelphij
368355604Sdelphij  notations = malloc(notationCount * sizeof(NotationList *));
369355604Sdelphij  if (notations == NULL) {
370355604Sdelphij    fprintf(stderr, "Unable to sort notations");
371355604Sdelphij    freeNotations(data);
372355604Sdelphij    return;
373355604Sdelphij  }
374355604Sdelphij
375355604Sdelphij  for (p = data->notationListHead, i = 0; i < notationCount; p = p->next, i++) {
376355604Sdelphij    notations[i] = p;
377355604Sdelphij  }
378355604Sdelphij  qsort(notations, notationCount, sizeof(NotationList *), notationCmp);
379355604Sdelphij
380355604Sdelphij  /* Output the DOCTYPE header */
381355604Sdelphij  fputts(T("<!DOCTYPE "), data->fp);
382355604Sdelphij  fputts(data->currentDoctypeName, data->fp);
383355604Sdelphij  fputts(T(" [\n"), data->fp);
384355604Sdelphij
385355604Sdelphij  /* Now the NOTATIONs */
386355604Sdelphij  for (i = 0; i < notationCount; i++) {
387355604Sdelphij    fputts(T("<!NOTATION "), data->fp);
388355604Sdelphij    fputts(notations[i]->notationName, data->fp);
389355604Sdelphij    if (notations[i]->publicId != NULL) {
390355604Sdelphij      fputts(T(" PUBLIC '"), data->fp);
391355604Sdelphij      fputts(notations[i]->publicId, data->fp);
392355604Sdelphij      puttc(T('\''), data->fp);
393355604Sdelphij      if (notations[i]->systemId != NULL) {
394355604Sdelphij        puttc(T(' '), data->fp);
395355604Sdelphij        puttc(T('\''), data->fp);
396355604Sdelphij        fputts(notations[i]->systemId, data->fp);
397355604Sdelphij        puttc(T('\''), data->fp);
398355604Sdelphij      }
399355604Sdelphij    } else if (notations[i]->systemId != NULL) {
400355604Sdelphij      fputts(T(" SYSTEM '"), data->fp);
401355604Sdelphij      fputts(notations[i]->systemId, data->fp);
402355604Sdelphij      puttc(T('\''), data->fp);
403355604Sdelphij    }
404355604Sdelphij    puttc(T('>'), data->fp);
405355604Sdelphij    puttc(T('\n'), data->fp);
406355604Sdelphij  }
407355604Sdelphij
408355604Sdelphij  /* Finally end the DOCTYPE */
409355604Sdelphij  fputts(T("]>\n"), data->fp);
410355604Sdelphij
411355604Sdelphij  free(notations);
412355604Sdelphij  freeNotations(data);
413355604Sdelphij  free((void *)data->currentDoctypeName);
414355604Sdelphij  data->currentDoctypeName = NULL;
415355604Sdelphij}
416355604Sdelphij
417355604Sdelphijstatic void XMLCALL
418355604SdelphijnotationDecl(void *userData, const XML_Char *notationName, const XML_Char *base,
419355604Sdelphij             const XML_Char *systemId, const XML_Char *publicId) {
420355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)userData;
421355604Sdelphij  NotationList *entry = malloc(sizeof(NotationList));
422355604Sdelphij  const char *errorMessage = "Unable to store NOTATION for output\n";
423355604Sdelphij
424355604Sdelphij  UNUSED_P(base);
425355604Sdelphij  if (entry == NULL) {
426355604Sdelphij    fputs(errorMessage, stderr);
427355604Sdelphij    return; /* Nothing we can really do about this */
428355604Sdelphij  }
429355604Sdelphij  entry->notationName = xcsdup(notationName);
430355604Sdelphij  if (entry->notationName == NULL) {
431355604Sdelphij    fputs(errorMessage, stderr);
432355604Sdelphij    free(entry);
433355604Sdelphij    return;
434355604Sdelphij  }
435355604Sdelphij  if (systemId != NULL) {
436355604Sdelphij    entry->systemId = xcsdup(systemId);
437355604Sdelphij    if (entry->systemId == NULL) {
438355604Sdelphij      fputs(errorMessage, stderr);
439355604Sdelphij      free((void *)entry->notationName);
440355604Sdelphij      free(entry);
441355604Sdelphij      return;
442355604Sdelphij    }
443355604Sdelphij  } else {
444355604Sdelphij    entry->systemId = NULL;
445355604Sdelphij  }
446355604Sdelphij  if (publicId != NULL) {
447355604Sdelphij    entry->publicId = xcsdup(publicId);
448355604Sdelphij    if (entry->publicId == NULL) {
449355604Sdelphij      fputs(errorMessage, stderr);
450355604Sdelphij      free((void *)entry->systemId); /* Safe if it's NULL */
451355604Sdelphij      free((void *)entry->notationName);
452355604Sdelphij      free(entry);
453355604Sdelphij      return;
454355604Sdelphij    }
455355604Sdelphij  } else {
456355604Sdelphij    entry->publicId = NULL;
457355604Sdelphij  }
458355604Sdelphij
459355604Sdelphij  entry->next = data->notationListHead;
460355604Sdelphij  data->notationListHead = entry;
461355604Sdelphij}
462355604Sdelphij
463104349Sphk#endif /* not W3C14N */
464104349Sphk
465178848Scokanestatic void XMLCALL
466355604SdelphijdefaultCharacterData(void *userData, const XML_Char *s, int len) {
467355604Sdelphij  UNUSED_P(s);
468355604Sdelphij  UNUSED_P(len);
469355604Sdelphij  XML_DefaultCurrent((XML_Parser)userData);
470104349Sphk}
471104349Sphk
472178848Scokanestatic void XMLCALL
473355604SdelphijdefaultStartElement(void *userData, const XML_Char *name,
474355604Sdelphij                    const XML_Char **atts) {
475355604Sdelphij  UNUSED_P(name);
476355604Sdelphij  UNUSED_P(atts);
477355604Sdelphij  XML_DefaultCurrent((XML_Parser)userData);
478104349Sphk}
479104349Sphk
480178848Scokanestatic void XMLCALL
481355604SdelphijdefaultEndElement(void *userData, const XML_Char *name) {
482355604Sdelphij  UNUSED_P(name);
483355604Sdelphij  XML_DefaultCurrent((XML_Parser)userData);
484104349Sphk}
485104349Sphk
486178848Scokanestatic void XMLCALL
487355604SdelphijdefaultProcessingInstruction(void *userData, const XML_Char *target,
488355604Sdelphij                             const XML_Char *data) {
489355604Sdelphij  UNUSED_P(target);
490355604Sdelphij  UNUSED_P(data);
491355604Sdelphij  XML_DefaultCurrent((XML_Parser)userData);
492104349Sphk}
493104349Sphk
494178848Scokanestatic void XMLCALL
495355604SdelphijnopCharacterData(void *userData, const XML_Char *s, int len) {
496355604Sdelphij  UNUSED_P(userData);
497355604Sdelphij  UNUSED_P(s);
498355604Sdelphij  UNUSED_P(len);
499104349Sphk}
500104349Sphk
501178848Scokanestatic void XMLCALL
502355604SdelphijnopStartElement(void *userData, const XML_Char *name, const XML_Char **atts) {
503355604Sdelphij  UNUSED_P(userData);
504355604Sdelphij  UNUSED_P(name);
505355604Sdelphij  UNUSED_P(atts);
506104349Sphk}
507104349Sphk
508178848Scokanestatic void XMLCALL
509355604SdelphijnopEndElement(void *userData, const XML_Char *name) {
510355604Sdelphij  UNUSED_P(userData);
511355604Sdelphij  UNUSED_P(name);
512104349Sphk}
513104349Sphk
514178848Scokanestatic void XMLCALL
515355604SdelphijnopProcessingInstruction(void *userData, const XML_Char *target,
516355604Sdelphij                         const XML_Char *data) {
517355604Sdelphij  UNUSED_P(userData);
518355604Sdelphij  UNUSED_P(target);
519355604Sdelphij  UNUSED_P(data);
520104349Sphk}
521104349Sphk
522178848Scokanestatic void XMLCALL
523355604Sdelphijmarkup(void *userData, const XML_Char *s, int len) {
524355604Sdelphij  FILE *fp = ((XmlwfUserData *)XML_GetUserData((XML_Parser)userData))->fp;
525104349Sphk  for (; len > 0; --len, ++s)
526104349Sphk    puttc(*s, fp);
527104349Sphk}
528104349Sphk
529104349Sphkstatic void
530355604SdelphijmetaLocation(XML_Parser parser) {
531104349Sphk  const XML_Char *uri = XML_GetBase(parser);
532355604Sdelphij  FILE *fp = ((XmlwfUserData *)XML_GetUserData(parser))->fp;
533104349Sphk  if (uri)
534355604Sdelphij    ftprintf(fp, T(" uri=\"%s\""), uri);
535355604Sdelphij  ftprintf(fp,
536355604Sdelphij           T(" byte=\"%") T(XML_FMT_INT_MOD) T("d\"") T(" nbytes=\"%d\"")
537355604Sdelphij               T(" line=\"%") T(XML_FMT_INT_MOD) T("u\"") T(" col=\"%")
538355604Sdelphij                   T(XML_FMT_INT_MOD) T("u\""),
539355604Sdelphij           XML_GetCurrentByteIndex(parser), XML_GetCurrentByteCount(parser),
540104349Sphk           XML_GetCurrentLineNumber(parser),
541104349Sphk           XML_GetCurrentColumnNumber(parser));
542104349Sphk}
543104349Sphk
544104349Sphkstatic void
545355604SdelphijmetaStartDocument(void *userData) {
546355604Sdelphij  fputts(T("<document>\n"),
547355604Sdelphij         ((XmlwfUserData *)XML_GetUserData((XML_Parser)userData))->fp);
548104349Sphk}
549104349Sphk
550104349Sphkstatic void
551355604SdelphijmetaEndDocument(void *userData) {
552355604Sdelphij  fputts(T("</document>\n"),
553355604Sdelphij         ((XmlwfUserData *)XML_GetUserData((XML_Parser)userData))->fp);
554104349Sphk}
555104349Sphk
556178848Scokanestatic void XMLCALL
557355604SdelphijmetaStartElement(void *userData, const XML_Char *name, const XML_Char **atts) {
558355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
559355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
560355604Sdelphij  FILE *fp = data->fp;
561104349Sphk  const XML_Char **specifiedAttsEnd
562355604Sdelphij      = atts + XML_GetSpecifiedAttributeCount(parser);
563104349Sphk  const XML_Char **idAttPtr;
564104349Sphk  int idAttIndex = XML_GetIdAttributeIndex(parser);
565104349Sphk  if (idAttIndex < 0)
566104349Sphk    idAttPtr = 0;
567104349Sphk  else
568104349Sphk    idAttPtr = atts + idAttIndex;
569355604Sdelphij
570104349Sphk  ftprintf(fp, T("<starttag name=\"%s\""), name);
571104349Sphk  metaLocation(parser);
572104349Sphk  if (*atts) {
573104349Sphk    fputts(T(">\n"), fp);
574104349Sphk    do {
575104349Sphk      ftprintf(fp, T("<attribute name=\"%s\" value=\""), atts[0]);
576355604Sdelphij      characterData(data, atts[1], (int)tcslen(atts[1]));
577104349Sphk      if (atts >= specifiedAttsEnd)
578104349Sphk        fputts(T("\" defaulted=\"yes\"/>\n"), fp);
579104349Sphk      else if (atts == idAttPtr)
580104349Sphk        fputts(T("\" id=\"yes\"/>\n"), fp);
581104349Sphk      else
582104349Sphk        fputts(T("\"/>\n"), fp);
583104349Sphk    } while (*(atts += 2));
584104349Sphk    fputts(T("</starttag>\n"), fp);
585355604Sdelphij  } else
586104349Sphk    fputts(T("/>\n"), fp);
587104349Sphk}
588104349Sphk
589178848Scokanestatic void XMLCALL
590355604SdelphijmetaEndElement(void *userData, const XML_Char *name) {
591355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
592355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
593355604Sdelphij  FILE *fp = data->fp;
594104349Sphk  ftprintf(fp, T("<endtag name=\"%s\""), name);
595104349Sphk  metaLocation(parser);
596104349Sphk  fputts(T("/>\n"), fp);
597104349Sphk}
598104349Sphk
599178848Scokanestatic void XMLCALL
600104349SphkmetaProcessingInstruction(void *userData, const XML_Char *target,
601355604Sdelphij                          const XML_Char *data) {
602355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
603355604Sdelphij  XmlwfUserData *usrData = (XmlwfUserData *)XML_GetUserData(parser);
604355604Sdelphij  FILE *fp = usrData->fp;
605104349Sphk  ftprintf(fp, T("<pi target=\"%s\" data=\""), target);
606355604Sdelphij  characterData(usrData, data, (int)tcslen(data));
607104349Sphk  puttc(T('"'), fp);
608104349Sphk  metaLocation(parser);
609104349Sphk  fputts(T("/>\n"), fp);
610104349Sphk}
611104349Sphk
612178848Scokanestatic void XMLCALL
613355604SdelphijmetaComment(void *userData, const XML_Char *data) {
614355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
615355604Sdelphij  XmlwfUserData *usrData = (XmlwfUserData *)XML_GetUserData(parser);
616355604Sdelphij  FILE *fp = usrData->fp;
617104349Sphk  fputts(T("<comment data=\""), fp);
618355604Sdelphij  characterData(usrData, data, (int)tcslen(data));
619104349Sphk  puttc(T('"'), fp);
620104349Sphk  metaLocation(parser);
621104349Sphk  fputts(T("/>\n"), fp);
622104349Sphk}
623104349Sphk
624178848Scokanestatic void XMLCALL
625355604SdelphijmetaStartCdataSection(void *userData) {
626355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
627355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
628355604Sdelphij  FILE *fp = data->fp;
629104349Sphk  fputts(T("<startcdata"), fp);
630104349Sphk  metaLocation(parser);
631104349Sphk  fputts(T("/>\n"), fp);
632104349Sphk}
633104349Sphk
634178848Scokanestatic void XMLCALL
635355604SdelphijmetaEndCdataSection(void *userData) {
636355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
637355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
638355604Sdelphij  FILE *fp = data->fp;
639104349Sphk  fputts(T("<endcdata"), fp);
640104349Sphk  metaLocation(parser);
641104349Sphk  fputts(T("/>\n"), fp);
642104349Sphk}
643104349Sphk
644178848Scokanestatic void XMLCALL
645355604SdelphijmetaCharacterData(void *userData, const XML_Char *s, int len) {
646355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
647355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
648355604Sdelphij  FILE *fp = data->fp;
649104349Sphk  fputts(T("<chars str=\""), fp);
650355604Sdelphij  characterData(data, s, len);
651104349Sphk  puttc(T('"'), fp);
652104349Sphk  metaLocation(parser);
653104349Sphk  fputts(T("/>\n"), fp);
654104349Sphk}
655104349Sphk
656178848Scokanestatic void XMLCALL
657355604SdelphijmetaStartDoctypeDecl(void *userData, const XML_Char *doctypeName,
658355604Sdelphij                     const XML_Char *sysid, const XML_Char *pubid,
659355604Sdelphij                     int has_internal_subset) {
660355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
661355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
662355604Sdelphij  FILE *fp = data->fp;
663355604Sdelphij  UNUSED_P(sysid);
664355604Sdelphij  UNUSED_P(pubid);
665355604Sdelphij  UNUSED_P(has_internal_subset);
666104349Sphk  ftprintf(fp, T("<startdoctype name=\"%s\""), doctypeName);
667104349Sphk  metaLocation(parser);
668104349Sphk  fputts(T("/>\n"), fp);
669104349Sphk}
670104349Sphk
671178848Scokanestatic void XMLCALL
672355604SdelphijmetaEndDoctypeDecl(void *userData) {
673355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
674355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
675355604Sdelphij  FILE *fp = data->fp;
676104349Sphk  fputts(T("<enddoctype"), fp);
677104349Sphk  metaLocation(parser);
678104349Sphk  fputts(T("/>\n"), fp);
679104349Sphk}
680104349Sphk
681178848Scokanestatic void XMLCALL
682355604SdelphijmetaNotationDecl(void *userData, const XML_Char *notationName,
683355604Sdelphij                 const XML_Char *base, const XML_Char *systemId,
684355604Sdelphij                 const XML_Char *publicId) {
685355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
686355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
687355604Sdelphij  FILE *fp = data->fp;
688355604Sdelphij  UNUSED_P(base);
689104349Sphk  ftprintf(fp, T("<notation name=\"%s\""), notationName);
690104349Sphk  if (publicId)
691104349Sphk    ftprintf(fp, T(" public=\"%s\""), publicId);
692104349Sphk  if (systemId) {
693104349Sphk    fputts(T(" system=\""), fp);
694355604Sdelphij    characterData(data, systemId, (int)tcslen(systemId));
695104349Sphk    puttc(T('"'), fp);
696104349Sphk  }
697104349Sphk  metaLocation(parser);
698104349Sphk  fputts(T("/>\n"), fp);
699104349Sphk}
700104349Sphk
701178848Scokanestatic void XMLCALL
702355604SdelphijmetaEntityDecl(void *userData, const XML_Char *entityName, int is_param,
703355604Sdelphij               const XML_Char *value, int value_length, const XML_Char *base,
704355604Sdelphij               const XML_Char *systemId, const XML_Char *publicId,
705355604Sdelphij               const XML_Char *notationName) {
706355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
707355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
708355604Sdelphij  FILE *fp = data->fp;
709104349Sphk
710355604Sdelphij  UNUSED_P(is_param);
711355604Sdelphij  UNUSED_P(base);
712104349Sphk  if (value) {
713104349Sphk    ftprintf(fp, T("<entity name=\"%s\""), entityName);
714104349Sphk    metaLocation(parser);
715104349Sphk    puttc(T('>'), fp);
716355604Sdelphij    characterData(data, value, value_length);
717104349Sphk    fputts(T("</entity/>\n"), fp);
718355604Sdelphij  } else if (notationName) {
719104349Sphk    ftprintf(fp, T("<entity name=\"%s\""), entityName);
720104349Sphk    if (publicId)
721104349Sphk      ftprintf(fp, T(" public=\"%s\""), publicId);
722104349Sphk    fputts(T(" system=\""), fp);
723355604Sdelphij    characterData(data, systemId, (int)tcslen(systemId));
724104349Sphk    puttc(T('"'), fp);
725104349Sphk    ftprintf(fp, T(" notation=\"%s\""), notationName);
726104349Sphk    metaLocation(parser);
727104349Sphk    fputts(T("/>\n"), fp);
728355604Sdelphij  } else {
729104349Sphk    ftprintf(fp, T("<entity name=\"%s\""), entityName);
730104349Sphk    if (publicId)
731104349Sphk      ftprintf(fp, T(" public=\"%s\""), publicId);
732104349Sphk    fputts(T(" system=\""), fp);
733355604Sdelphij    characterData(data, systemId, (int)tcslen(systemId));
734104349Sphk    puttc(T('"'), fp);
735104349Sphk    metaLocation(parser);
736104349Sphk    fputts(T("/>\n"), fp);
737104349Sphk  }
738104349Sphk}
739104349Sphk
740178848Scokanestatic void XMLCALL
741355604SdelphijmetaStartNamespaceDecl(void *userData, const XML_Char *prefix,
742355604Sdelphij                       const XML_Char *uri) {
743355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
744355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
745355604Sdelphij  FILE *fp = data->fp;
746104349Sphk  fputts(T("<startns"), fp);
747104349Sphk  if (prefix)
748104349Sphk    ftprintf(fp, T(" prefix=\"%s\""), prefix);
749104349Sphk  if (uri) {
750104349Sphk    fputts(T(" ns=\""), fp);
751355604Sdelphij    characterData(data, uri, (int)tcslen(uri));
752104349Sphk    fputts(T("\"/>\n"), fp);
753355604Sdelphij  } else
754104349Sphk    fputts(T("/>\n"), fp);
755104349Sphk}
756104349Sphk
757178848Scokanestatic void XMLCALL
758355604SdelphijmetaEndNamespaceDecl(void *userData, const XML_Char *prefix) {
759355604Sdelphij  XML_Parser parser = (XML_Parser)userData;
760355604Sdelphij  XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
761355604Sdelphij  FILE *fp = data->fp;
762355604Sdelphij  if (! prefix)
763104349Sphk    fputts(T("<endns/>\n"), fp);
764104349Sphk  else
765104349Sphk    ftprintf(fp, T("<endns prefix=\"%s\"/>\n"), prefix);
766104349Sphk}
767104349Sphk
768178848Scokanestatic int XMLCALL
769355604SdelphijunknownEncodingConvert(void *data, const char *p) {
770104349Sphk  return codepageConvert(*(int *)data, p);
771104349Sphk}
772104349Sphk
773178848Scokanestatic int XMLCALL
774355604SdelphijunknownEncoding(void *userData, const XML_Char *name, XML_Encoding *info) {
775104349Sphk  int cp;
776104349Sphk  static const XML_Char prefixL[] = T("windows-");
777104349Sphk  static const XML_Char prefixU[] = T("WINDOWS-");
778104349Sphk  int i;
779104349Sphk
780355604Sdelphij  UNUSED_P(userData);
781104349Sphk  for (i = 0; prefixU[i]; i++)
782104349Sphk    if (name[i] != prefixU[i] && name[i] != prefixL[i])
783104349Sphk      return 0;
784355604Sdelphij
785104349Sphk  cp = 0;
786104349Sphk  for (; name[i]; i++) {
787104349Sphk    static const XML_Char digits[] = T("0123456789");
788104349Sphk    const XML_Char *s = tcschr(digits, name[i]);
789355604Sdelphij    if (! s)
790104349Sphk      return 0;
791104349Sphk    cp *= 10;
792178848Scokane    cp += (int)(s - digits);
793104349Sphk    if (cp >= 0x10000)
794104349Sphk      return 0;
795104349Sphk  }
796355604Sdelphij  if (! codepageMap(cp, info->map))
797104349Sphk    return 0;
798104349Sphk  info->convert = unknownEncodingConvert;
799104349Sphk  /* We could just cast the code page integer to a void *,
800104349Sphk  and avoid the use of release. */
801104349Sphk  info->release = free;
802104349Sphk  info->data = malloc(sizeof(int));
803355604Sdelphij  if (! info->data)
804104349Sphk    return 0;
805104349Sphk  *(int *)info->data = cp;
806104349Sphk  return 1;
807104349Sphk}
808104349Sphk
809178848Scokanestatic int XMLCALL
810355604SdelphijnotStandalone(void *userData) {
811355604Sdelphij  UNUSED_P(userData);
812104349Sphk  return 0;
813104349Sphk}
814104349Sphk
815104349Sphkstatic void
816355604SdelphijshowVersion(XML_Char *prog) {
817104349Sphk  XML_Char *s = prog;
818104349Sphk  XML_Char ch;
819104349Sphk  const XML_Feature *features = XML_GetFeatureList();
820104349Sphk  while ((ch = *s) != 0) {
821104349Sphk    if (ch == '/'
822355604Sdelphij#if defined(_WIN32)
823104349Sphk        || ch == '\\'
824104349Sphk#endif
825355604Sdelphij    )
826104349Sphk      prog = s + 1;
827104349Sphk    ++s;
828104349Sphk  }
829104349Sphk  ftprintf(stdout, T("%s using %s\n"), prog, XML_ExpatVersion());
830104349Sphk  if (features != NULL && features[0].feature != XML_FEATURE_END) {
831104349Sphk    int i = 1;
832104349Sphk    ftprintf(stdout, T("%s"), features[0].name);
833104349Sphk    if (features[0].value)
834104349Sphk      ftprintf(stdout, T("=%ld"), features[0].value);
835104349Sphk    while (features[i].feature != XML_FEATURE_END) {
836104349Sphk      ftprintf(stdout, T(", %s"), features[i].name);
837104349Sphk      if (features[i].value)
838104349Sphk        ftprintf(stdout, T("=%ld"), features[i].value);
839104349Sphk      ++i;
840104349Sphk    }
841104349Sphk    ftprintf(stdout, T("\n"));
842104349Sphk  }
843104349Sphk}
844104349Sphk
845104349Sphkstatic void
846355604Sdelphijusage(const XML_Char *prog, int rc) {
847355604Sdelphij  ftprintf(
848355604Sdelphij      stderr,
849355604Sdelphij      /* Generated with:
850355604Sdelphij       * $ xmlwf/xmlwf_helpgen.sh
851355604Sdelphij       */
852355604Sdelphij      /* clang-format off */
853355604Sdelphij      T("usage: %s [-s] [-n] [-p] [-x] [-e ENCODING] [-w] [-r] [-d DIRECTORY]\n")
854355604Sdelphij      T("             [-c | -m | -t] [-N]\n")
855355604Sdelphij      T("             [FILE [FILE ...]]\n")
856355604Sdelphij      T("\n")
857355604Sdelphij      T("xmlwf - Determines if an XML document is well-formed\n")
858355604Sdelphij      T("\n")
859355604Sdelphij      T("positional arguments:\n")
860355604Sdelphij      T("  FILE          files to process (default: STDIN)\n")
861355604Sdelphij      T("\n")
862355604Sdelphij      T("input control arguments:\n")
863355604Sdelphij      T("  -s            print an error if the document is not [s]tandalone\n")
864355604Sdelphij      T("  -n            enable [n]amespace processing\n")
865355604Sdelphij      T("  -p            enable processing external DTDs and [p]arameter entities\n")
866355604Sdelphij      T("  -x            enable processing of e[x]ternal entities\n")
867355604Sdelphij      T("  -e ENCODING   override any in-document [e]ncoding declaration\n")
868355604Sdelphij      T("  -w            enable support for [W]indows code pages\n")
869355604Sdelphij      T("  -r            disable memory-mapping and use normal file [r]ead IO calls instead\n")
870355604Sdelphij      T("\n")
871355604Sdelphij      T("output control arguments:\n")
872355604Sdelphij      T("  -d DIRECTORY  output [d]estination directory\n")
873355604Sdelphij      T("  -c            write a [c]opy of input XML, not canonical XML\n")
874355604Sdelphij      T("  -m            write [m]eta XML, not canonical XML\n")
875355604Sdelphij      T("  -t            write no XML output for [t]iming of plain parsing\n")
876355604Sdelphij      T("  -N            enable adding doctype and [n]otation declarations\n")
877355604Sdelphij      T("\n")
878355604Sdelphij      T("info arguments:\n")
879355604Sdelphij      T("  -h            show this [h]elp message and exit\n")
880355604Sdelphij      T("  -v            show program's [v]ersion number and exit\n")
881355604Sdelphij      T("\n")
882355604Sdelphij      T("libexpat is software libre, licensed under the MIT license.\n")
883355604Sdelphij      T("Please report bugs at https://github.com/libexpat/libexpat/issues.  Thank you!\n")
884355604Sdelphij      , /* clang-format on */
885355604Sdelphij      prog);
886104349Sphk  exit(rc);
887104349Sphk}
888104349Sphk
889355604Sdelphij#if defined(__MINGW32__) && defined(XML_UNICODE)
890355604Sdelphij/* Silence warning about missing prototype */
891355604Sdelphijint wmain(int argc, XML_Char **argv);
892355604Sdelphij#endif
893355604Sdelphij
894104349Sphkint
895355604Sdelphijtmain(int argc, XML_Char **argv) {
896104349Sphk  int i, j;
897104349Sphk  const XML_Char *outputDir = NULL;
898104349Sphk  const XML_Char *encoding = NULL;
899104349Sphk  unsigned processFlags = XML_MAP_FILE;
900104349Sphk  int windowsCodePages = 0;
901104349Sphk  int outputType = 0;
902104349Sphk  int useNamespaces = 0;
903104349Sphk  int requireStandalone = 0;
904355604Sdelphij  int requiresNotations = 0;
905355604Sdelphij  enum XML_ParamEntityParsing paramEntityParsing
906355604Sdelphij      = XML_PARAM_ENTITY_PARSING_NEVER;
907104349Sphk  int useStdin = 0;
908355604Sdelphij  XmlwfUserData userData = {NULL, NULL, NULL};
909104349Sphk
910104349Sphk#ifdef _MSC_VER
911355604Sdelphij  _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
912104349Sphk#endif
913104349Sphk
914104349Sphk  i = 1;
915104349Sphk  j = 0;
916104349Sphk  while (i < argc) {
917104349Sphk    if (j == 0) {
918104349Sphk      if (argv[i][0] != T('-'))
919104349Sphk        break;
920104349Sphk      if (argv[i][1] == T('-') && argv[i][2] == T('\0')) {
921104349Sphk        i++;
922104349Sphk        break;
923104349Sphk      }
924104349Sphk      j++;
925104349Sphk    }
926104349Sphk    switch (argv[i][j]) {
927104349Sphk    case T('r'):
928104349Sphk      processFlags &= ~XML_MAP_FILE;
929104349Sphk      j++;
930104349Sphk      break;
931104349Sphk    case T('s'):
932104349Sphk      requireStandalone = 1;
933104349Sphk      j++;
934104349Sphk      break;
935104349Sphk    case T('n'):
936104349Sphk      useNamespaces = 1;
937104349Sphk      j++;
938104349Sphk      break;
939104349Sphk    case T('p'):
940104349Sphk      paramEntityParsing = XML_PARAM_ENTITY_PARSING_ALWAYS;
941104349Sphk      /* fall through */
942104349Sphk    case T('x'):
943104349Sphk      processFlags |= XML_EXTERNAL_ENTITIES;
944104349Sphk      j++;
945104349Sphk      break;
946104349Sphk    case T('w'):
947104349Sphk      windowsCodePages = 1;
948104349Sphk      j++;
949104349Sphk      break;
950104349Sphk    case T('m'):
951104349Sphk      outputType = 'm';
952104349Sphk      j++;
953104349Sphk      break;
954104349Sphk    case T('c'):
955104349Sphk      outputType = 'c';
956104349Sphk      useNamespaces = 0;
957104349Sphk      j++;
958104349Sphk      break;
959104349Sphk    case T('t'):
960104349Sphk      outputType = 't';
961104349Sphk      j++;
962104349Sphk      break;
963355604Sdelphij    case T('N'):
964355604Sdelphij      requiresNotations = 1;
965355604Sdelphij      j++;
966355604Sdelphij      break;
967104349Sphk    case T('d'):
968104349Sphk      if (argv[i][j + 1] == T('\0')) {
969104349Sphk        if (++i == argc)
970104349Sphk          usage(argv[0], 2);
971104349Sphk        outputDir = argv[i];
972355604Sdelphij      } else
973104349Sphk        outputDir = argv[i] + j + 1;
974104349Sphk      i++;
975104349Sphk      j = 0;
976104349Sphk      break;
977104349Sphk    case T('e'):
978104349Sphk      if (argv[i][j + 1] == T('\0')) {
979104349Sphk        if (++i == argc)
980104349Sphk          usage(argv[0], 2);
981104349Sphk        encoding = argv[i];
982355604Sdelphij      } else
983104349Sphk        encoding = argv[i] + j + 1;
984104349Sphk      i++;
985104349Sphk      j = 0;
986104349Sphk      break;
987104349Sphk    case T('h'):
988104349Sphk      usage(argv[0], 0);
989104349Sphk      return 0;
990104349Sphk    case T('v'):
991104349Sphk      showVersion(argv[0]);
992104349Sphk      return 0;
993104349Sphk    case T('\0'):
994104349Sphk      if (j > 1) {
995104349Sphk        i++;
996104349Sphk        j = 0;
997104349Sphk        break;
998104349Sphk      }
999104349Sphk      /* fall through */
1000104349Sphk    default:
1001104349Sphk      usage(argv[0], 2);
1002104349Sphk    }
1003104349Sphk  }
1004104349Sphk  if (i == argc) {
1005104349Sphk    useStdin = 1;
1006104349Sphk    processFlags &= ~XML_MAP_FILE;
1007104349Sphk    i--;
1008104349Sphk  }
1009104349Sphk  for (; i < argc; i++) {
1010104349Sphk    XML_Char *outName = 0;
1011104349Sphk    int result;
1012104349Sphk    XML_Parser parser;
1013104349Sphk    if (useNamespaces)
1014104349Sphk      parser = XML_ParserCreateNS(encoding, NSSEP);
1015104349Sphk    else
1016104349Sphk      parser = XML_ParserCreate(encoding);
1017302305Sdelphij
1018302305Sdelphij    if (! parser) {
1019355604Sdelphij      tperror(T("Could not instantiate parser"));
1020302305Sdelphij      exit(1);
1021302305Sdelphij    }
1022302305Sdelphij
1023104349Sphk    if (requireStandalone)
1024104349Sphk      XML_SetNotStandaloneHandler(parser, notStandalone);
1025104349Sphk    XML_SetParamEntityParsing(parser, paramEntityParsing);
1026104349Sphk    if (outputType == 't') {
1027104349Sphk      /* This is for doing timings; this gives a more realistic estimate of
1028104349Sphk         the parsing time. */
1029104349Sphk      outputDir = 0;
1030104349Sphk      XML_SetElementHandler(parser, nopStartElement, nopEndElement);
1031104349Sphk      XML_SetCharacterDataHandler(parser, nopCharacterData);
1032104349Sphk      XML_SetProcessingInstructionHandler(parser, nopProcessingInstruction);
1033355604Sdelphij    } else if (outputDir) {
1034355604Sdelphij      const XML_Char *delim = T("/");
1035104349Sphk      const XML_Char *file = useStdin ? T("STDIN") : argv[i];
1036355604Sdelphij      if (! useStdin) {
1037178848Scokane        /* Jump after last (back)slash */
1038355604Sdelphij        const XML_Char *lastDelim = tcsrchr(file, delim[0]);
1039178848Scokane        if (lastDelim)
1040178848Scokane          file = lastDelim + 1;
1041355604Sdelphij#if defined(_WIN32)
1042178848Scokane        else {
1043355604Sdelphij          const XML_Char *winDelim = T("\\");
1044178848Scokane          lastDelim = tcsrchr(file, winDelim[0]);
1045178848Scokane          if (lastDelim) {
1046178848Scokane            file = lastDelim + 1;
1047178848Scokane            delim = winDelim;
1048178848Scokane          }
1049178848Scokane        }
1050104349Sphk#endif
1051178848Scokane      }
1052178848Scokane      outName = (XML_Char *)malloc((tcslen(outputDir) + tcslen(file) + 2)
1053355604Sdelphij                                   * sizeof(XML_Char));
1054104349Sphk      tcscpy(outName, outputDir);
1055178848Scokane      tcscat(outName, delim);
1056104349Sphk      tcscat(outName, file);
1057355604Sdelphij      userData.fp = tfopen(outName, T("wb"));
1058355604Sdelphij      if (! userData.fp) {
1059104349Sphk        tperror(outName);
1060104349Sphk        exit(1);
1061104349Sphk      }
1062355604Sdelphij      setvbuf(userData.fp, NULL, _IOFBF, 16384);
1063104349Sphk#ifdef XML_UNICODE
1064355604Sdelphij      puttc(0xFEFF, userData.fp);
1065104349Sphk#endif
1066355604Sdelphij      XML_SetUserData(parser, &userData);
1067104349Sphk      switch (outputType) {
1068104349Sphk      case 'm':
1069104349Sphk        XML_UseParserAsHandlerArg(parser);
1070104349Sphk        XML_SetElementHandler(parser, metaStartElement, metaEndElement);
1071104349Sphk        XML_SetProcessingInstructionHandler(parser, metaProcessingInstruction);
1072104349Sphk        XML_SetCommentHandler(parser, metaComment);
1073104349Sphk        XML_SetCdataSectionHandler(parser, metaStartCdataSection,
1074104349Sphk                                   metaEndCdataSection);
1075104349Sphk        XML_SetCharacterDataHandler(parser, metaCharacterData);
1076104349Sphk        XML_SetDoctypeDeclHandler(parser, metaStartDoctypeDecl,
1077104349Sphk                                  metaEndDoctypeDecl);
1078104349Sphk        XML_SetEntityDeclHandler(parser, metaEntityDecl);
1079104349Sphk        XML_SetNotationDeclHandler(parser, metaNotationDecl);
1080104349Sphk        XML_SetNamespaceDeclHandler(parser, metaStartNamespaceDecl,
1081104349Sphk                                    metaEndNamespaceDecl);
1082104349Sphk        metaStartDocument(parser);
1083104349Sphk        break;
1084104349Sphk      case 'c':
1085104349Sphk        XML_UseParserAsHandlerArg(parser);
1086104349Sphk        XML_SetDefaultHandler(parser, markup);
1087104349Sphk        XML_SetElementHandler(parser, defaultStartElement, defaultEndElement);
1088104349Sphk        XML_SetCharacterDataHandler(parser, defaultCharacterData);
1089104349Sphk        XML_SetProcessingInstructionHandler(parser,
1090104349Sphk                                            defaultProcessingInstruction);
1091104349Sphk        break;
1092104349Sphk      default:
1093104349Sphk        if (useNamespaces)
1094104349Sphk          XML_SetElementHandler(parser, startElementNS, endElementNS);
1095104349Sphk        else
1096104349Sphk          XML_SetElementHandler(parser, startElement, endElement);
1097104349Sphk        XML_SetCharacterDataHandler(parser, characterData);
1098104349Sphk#ifndef W3C14N
1099104349Sphk        XML_SetProcessingInstructionHandler(parser, processingInstruction);
1100355604Sdelphij        if (requiresNotations) {
1101355604Sdelphij          XML_SetDoctypeDeclHandler(parser, startDoctypeDecl, endDoctypeDecl);
1102355604Sdelphij          XML_SetNotationDeclHandler(parser, notationDecl);
1103355604Sdelphij        }
1104104349Sphk#endif /* not W3C14N */
1105104349Sphk        break;
1106104349Sphk      }
1107104349Sphk    }
1108104349Sphk    if (windowsCodePages)
1109104349Sphk      XML_SetUnknownEncodingHandler(parser, unknownEncoding, 0);
1110104349Sphk    result = XML_ProcessFile(parser, useStdin ? NULL : argv[i], processFlags);
1111104349Sphk    if (outputDir) {
1112104349Sphk      if (outputType == 'm')
1113104349Sphk        metaEndDocument(parser);
1114355604Sdelphij      fclose(userData.fp);
1115355604Sdelphij      if (! result) {
1116104349Sphk        tremove(outName);
1117247296Sdelphij      }
1118104349Sphk      free(outName);
1119104349Sphk    }
1120104349Sphk    XML_ParserFree(parser);
1121355604Sdelphij    if (! result) {
1122355604Sdelphij      exit(2);
1123355604Sdelphij    }
1124104349Sphk  }
1125104349Sphk  return 0;
1126104349Sphk}
1127