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