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