1/*
2The contents of this file are subject to the Mozilla Public License
3Version 1.1 (the "License"); you may not use this file except in
4compliance with the License. You may obtain a copy of the License at
5http://www.mozilla.org/MPL/
6
7Software distributed under the License is distributed on an "AS IS"
8basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
9License for the specific language governing rights and limitations
10under the License.
11
12The Original Code is expat.
13
14The Initial Developer of the Original Code is James Clark.
15Portions created by James Clark are Copyright (C) 1998, 1999
16James Clark. All Rights Reserved.
17
18Contributor(s):
19
20Alternatively, the contents of this file may be used under the terms
21of the GNU General Public License (the "GPL"), in which case the
22provisions of the GPL are applicable instead of those above.  If you
23wish to allow use of your version of this file only under the terms of
24the GPL and not to allow others to use your version of this file under
25the MPL, indicate your decision by deleting the provisions above and
26replace them with the notice and other provisions required by the
27GPL. If you do not delete the provisions above, a recipient may use
28your version of this file under either the MPL or the GPL.
29*/
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <stddef.h>
34#include <string.h>
35#include <fcntl.h>
36#include "xmlparse.h"
37#include "xmlfile.h"
38#include "xmltchar.h"
39#include "filemap.h"
40
41#ifdef _MSC_VER
42#include <io.h>
43#endif
44
45#ifdef _POSIX_SOURCE
46#include <unistd.h>
47#endif
48
49#ifndef O_BINARY
50#ifdef _O_BINARY
51#define O_BINARY _O_BINARY
52#else
53#define O_BINARY 0
54#endif
55#endif
56
57#ifdef _DEBUG
58#define READ_SIZE 16
59#else
60#define READ_SIZE (1024*8)
61#endif
62
63
64
65typedef struct {
66  XML_Parser parser;
67  int *retPtr;
68} PROCESS_ARGS;
69
70static
71void reportError(XML_Parser parser, const XML_Char *filename)
72{
73  int code = XML_GetErrorCode(parser);
74  const XML_Char *message = XML_ErrorString(code);
75  if (message)
76    ftprintf(stdout, T("%s:%d:%ld: %s\n"),
77	     filename,
78	     XML_GetErrorLineNumber(parser),
79	     XML_GetErrorColumnNumber(parser),
80	     message);
81  else
82    ftprintf(stderr, T("%s: (unknown message %d)\n"), filename, code);
83}
84
85static
86void processFile(const void *data,
87		 size_t size,
88		 const XML_Char *filename,
89		 void *args)
90{
91  XML_Parser parser = ((PROCESS_ARGS *)args)->parser;
92  int *retPtr = ((PROCESS_ARGS *)args)->retPtr;
93  if (!XML_Parse(parser, data, size, 1)) {
94    reportError(parser, filename);
95    *retPtr = 0;
96  }
97  else
98    *retPtr = 1;
99}
100
101static
102int isAsciiLetter(XML_Char c)
103{
104  return (T('a') <= c && c <= T('z')) || (T('A') <= c && c <= T('Z'));
105}
106
107static
108const XML_Char *resolveSystemId(const XML_Char *base, const XML_Char *systemId, XML_Char **toFree)
109{
110  XML_Char *s;
111  *toFree = 0;
112  if (!base
113      || *systemId == T('/')
114#ifdef WIN32
115      || *systemId == T('\\')
116      || (isAsciiLetter(systemId[0]) && systemId[1] == T(':'))
117#endif
118     )
119    return systemId;
120  *toFree = (XML_Char *)malloc((tcslen(base) + tcslen(systemId) + 2)*sizeof(XML_Char));
121  if (!*toFree)
122    return systemId;
123  tcscpy(*toFree, base);
124  s = *toFree;
125  if (tcsrchr(s, T('/')))
126    s = tcsrchr(s, T('/')) + 1;
127#ifdef WIN32
128  if (tcsrchr(s, T('\\')))
129    s = tcsrchr(s, T('\\')) + 1;
130#endif
131  tcscpy(s, systemId);
132  return *toFree;
133}
134
135static
136int externalEntityRefFilemap(XML_Parser parser,
137			     const XML_Char *context,
138			     const XML_Char *base,
139			     const XML_Char *systemId,
140			     const XML_Char *publicId)
141{
142  int result;
143  XML_Char *s;
144  const XML_Char *filename;
145  XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
146  PROCESS_ARGS args;
147  args.retPtr = &result;
148  args.parser = entParser;
149  filename = resolveSystemId(base, systemId, &s);
150  XML_SetBase(entParser, filename);
151  if (!filemap(filename, processFile, &args))
152    result = 0;
153  free(s);
154  XML_ParserFree(entParser);
155  return result;
156}
157
158static
159int processStream(const XML_Char *filename, XML_Parser parser)
160{
161  int fd = topen(filename, O_BINARY|O_RDONLY);
162  if (fd < 0) {
163    tperror(filename);
164    return 0;
165  }
166  for (;;) {
167    int nread;
168    char *buf = XML_GetBuffer(parser, READ_SIZE);
169    if (!buf) {
170      close(fd);
171      ftprintf(stderr, T("%s: out of memory\n"), filename);
172      return 0;
173    }
174    nread = read(fd, buf, READ_SIZE);
175    if (nread < 0) {
176      tperror(filename);
177      close(fd);
178      return 0;
179    }
180    if (!XML_ParseBuffer(parser, nread, nread == 0)) {
181      reportError(parser, filename);
182      close(fd);
183      return 0;
184    }
185    if (nread == 0) {
186      close(fd);
187      break;;
188    }
189  }
190  return 1;
191}
192
193static
194int externalEntityRefStream(XML_Parser parser,
195			    const XML_Char *context,
196			    const XML_Char *base,
197			    const XML_Char *systemId,
198			    const XML_Char *publicId)
199{
200  XML_Char *s;
201  const XML_Char *filename;
202  int ret;
203  XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
204  filename = resolveSystemId(base, systemId, &s);
205  XML_SetBase(entParser, filename);
206  ret = processStream(filename, entParser);
207  free(s);
208  XML_ParserFree(entParser);
209  return ret;
210}
211
212int XML_ProcessFile(XML_Parser parser,
213		    const XML_Char *filename,
214		    unsigned flags)
215{
216  int result;
217
218  if (!XML_SetBase(parser, filename)) {
219    ftprintf(stderr, T("%s: out of memory"), filename);
220    exit(1);
221  }
222
223  if (flags & XML_EXTERNAL_ENTITIES)
224      XML_SetExternalEntityRefHandler(parser,
225	                              (flags & XML_MAP_FILE)
226				      ? externalEntityRefFilemap
227				      : externalEntityRefStream);
228  if (flags & XML_MAP_FILE) {
229    PROCESS_ARGS args;
230    args.retPtr = &result;
231    args.parser = parser;
232    if (!filemap(filename, processFile, &args))
233      result = 0;
234  }
235  else
236    result = processStream(filename, parser);
237  return result;
238}
239