xmlfile.c revision 8a666ab336063fc53e446702fdf9ffe14af69e71
1/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
2   See the file COPYING for copying permission.
3*/
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <stddef.h>
8#include <string.h>
9#include <fcntl.h>
10
11#ifdef COMPILED_FROM_DSP
12#include "winconfig.h"
13#elif defined(MACOS_CLASSIC)
14#include "macconfig.h"
15#elif defined(__amigaos4__)
16#include "amigaconfig.h"
17#elif defined(HAVE_EXPAT_CONFIG_H)
18#include <expat_config.h>
19#endif /* ndef COMPILED_FROM_DSP */
20
21#include "expat.h"
22#include "xmlfile.h"
23#include "xmltchar.h"
24#include "filemap.h"
25
26#ifdef _MSC_VER
27#include <io.h>
28#endif
29
30#ifdef AMIGA_SHARED_LIB
31#include <proto/expat.h>
32#endif
33
34#ifdef HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37
38#ifndef O_BINARY
39#ifdef _O_BINARY
40#define O_BINARY _O_BINARY
41#else
42#define O_BINARY 0
43#endif
44#endif
45
46#ifdef _DEBUG
47#define READ_SIZE 16
48#else
49#define READ_SIZE (1024*8)
50#endif
51
52
53typedef struct {
54  XML_Parser parser;
55  int *retPtr;
56} PROCESS_ARGS;
57
58static void
59reportError(XML_Parser parser, const XML_Char *filename)
60{
61  enum XML_Error code = XML_GetErrorCode(parser);
62  const XML_Char *message = XML_ErrorString(code);
63  if (message)
64    ftprintf(stdout, T("%s:%" XML_FMT_INT_MOD "u:%" XML_FMT_INT_MOD "u: %s\n"),
65             filename,
66             XML_GetErrorLineNumber(parser),
67             XML_GetErrorColumnNumber(parser),
68             message);
69  else
70    ftprintf(stderr, T("%s: (unknown message %d)\n"), filename, code);
71}
72
73static void
74processFile(const void *data, size_t size,
75            const XML_Char *filename, void *args)
76{
77  XML_Parser parser = ((PROCESS_ARGS *)args)->parser;
78  int *retPtr = ((PROCESS_ARGS *)args)->retPtr;
79  if (XML_Parse(parser, (const char *)data, size, 1) == XML_STATUS_ERROR) {
80    reportError(parser, filename);
81    *retPtr = 0;
82  }
83  else
84    *retPtr = 1;
85}
86
87#ifdef WIN32
88
89static int
90isAsciiLetter(XML_Char c)
91{
92  return (T('a') <= c && c <= T('z')) || (T('A') <= c && c <= T('Z'));
93}
94
95#endif /* WIN32 */
96
97static const XML_Char *
98resolveSystemId(const XML_Char *base, const XML_Char *systemId,
99                XML_Char **toFree)
100{
101  XML_Char *s;
102  *toFree = 0;
103  if (!base
104      || *systemId == T('/')
105#ifdef WIN32
106      || *systemId == T('\\')
107      || (isAsciiLetter(systemId[0]) && systemId[1] == T(':'))
108#endif
109     )
110    return systemId;
111  *toFree = (XML_Char *)malloc((tcslen(base) + tcslen(systemId) + 2)
112                               * sizeof(XML_Char));
113  if (!*toFree)
114    return systemId;
115  tcscpy(*toFree, base);
116  s = *toFree;
117  if (tcsrchr(s, T('/')))
118    s = tcsrchr(s, T('/')) + 1;
119#ifdef WIN32
120  if (tcsrchr(s, T('\\')))
121    s = tcsrchr(s, T('\\')) + 1;
122#endif
123  tcscpy(s, systemId);
124  return *toFree;
125}
126
127static int
128externalEntityRefFilemap(XML_Parser parser,
129                         const XML_Char *context,
130                         const XML_Char *base,
131                         const XML_Char *systemId,
132                         const XML_Char *publicId)
133{
134  int result;
135  XML_Char *s;
136  const XML_Char *filename;
137  XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
138  PROCESS_ARGS args;
139  args.retPtr = &result;
140  args.parser = entParser;
141  filename = resolveSystemId(base, systemId, &s);
142  XML_SetBase(entParser, filename);
143  if (!filemap(filename, processFile, &args))
144    result = 0;
145  free(s);
146  XML_ParserFree(entParser);
147  return result;
148}
149
150static int
151processStream(const XML_Char *filename, XML_Parser parser)
152{
153  /* passing NULL for filename means read intput from stdin */
154  int fd = 0;   /* 0 is the fileno for stdin */
155
156  if (filename != NULL) {
157    fd = topen(filename, O_BINARY|O_RDONLY);
158    if (fd < 0) {
159      tperror(filename);
160      return 0;
161    }
162  }
163  for (;;) {
164    int nread;
165    char *buf = (char *)XML_GetBuffer(parser, READ_SIZE);
166    if (!buf) {
167      if (filename != NULL)
168        close(fd);
169      ftprintf(stderr, T("%s: out of memory\n"),
170               filename != NULL ? filename : "xmlwf");
171      return 0;
172    }
173    nread = read(fd, buf, READ_SIZE);
174    if (nread < 0) {
175      tperror(filename != NULL ? filename : "STDIN");
176      if (filename != NULL)
177        close(fd);
178      return 0;
179    }
180    if (XML_ParseBuffer(parser, nread, nread == 0) == XML_STATUS_ERROR) {
181      reportError(parser, filename != NULL ? filename : "STDIN");
182      if (filename != NULL)
183        close(fd);
184      return 0;
185    }
186    if (nread == 0) {
187      if (filename != NULL)
188        close(fd);
189      break;;
190    }
191  }
192  return 1;
193}
194
195static int
196externalEntityRefStream(XML_Parser parser,
197                        const XML_Char *context,
198                        const XML_Char *base,
199                        const XML_Char *systemId,
200                        const XML_Char *publicId)
201{
202  XML_Char *s;
203  const XML_Char *filename;
204  int ret;
205  XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
206  filename = resolveSystemId(base, systemId, &s);
207  XML_SetBase(entParser, filename);
208  ret = processStream(filename, entParser);
209  free(s);
210  XML_ParserFree(entParser);
211  return ret;
212}
213
214int
215XML_ProcessFile(XML_Parser parser,
216                const XML_Char *filename,
217                unsigned flags)
218{
219  int result;
220
221  if (!XML_SetBase(parser, filename)) {
222    ftprintf(stderr, T("%s: out of memory"), filename);
223    exit(1);
224  }
225
226  if (flags & XML_EXTERNAL_ENTITIES)
227      XML_SetExternalEntityRefHandler(parser,
228                                      (flags & XML_MAP_FILE)
229                                      ? externalEntityRefFilemap
230                                      : externalEntityRefStream);
231  if (flags & XML_MAP_FILE) {
232    PROCESS_ARGS args;
233    args.retPtr = &result;
234    args.parser = parser;
235    if (!filemap(filename, processFile, &args))
236      result = 0;
237  }
238  else
239    result = processStream(filename, parser);
240  return result;
241}
242