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