1 /*
2  * The contents of this file are subject to the Mozilla Public
3  * License Version 1.1 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of
5  * the License at http://www.mozilla.org/MPL/
6  *
7  * Software distributed under the License is distributed on an "AS
8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9  * implied. See the License for the specific language governing
10  * rights and limitations under the License.
11  *
12  * The Original Code is the Sablotron XSLT Processor.
13  *
14  * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15  * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16  * Ginger Alliance Ltd. All Rights Reserved.
17  *
18  * Contributor(s):
19  *
20  * Alternatively, the contents of this file may be used under the
21  * terms of the GNU General Public License Version 2 or later (the
22  * "GPL"), in which case the provisions of the GPL are applicable
23  * instead of those above.  If you wish to allow use of your
24  * version of this file only under the terms of the GPL and not to
25  * allow others to use your version of this file under the MPL,
26  * indicate your decision by deleting the provisions above and
27  * replace them with the notice and other provisions required by
28  * the GPL.  If you do not delete the provisions above, a recipient
29  * may use your version of this file under either the MPL or the
30  * GPL.
31  */
32 
33 #include "base.h"
34 #include "platform.h"
35 #include "proc.h"
36 #include "utf8.h"
37 // #include <new.h>
38 #include <ctype.h>
39 // #include <strings.h>
40 
41 // GP: clean
42 
43 #if defined(CHECK_LEAKS)
44 #pragma Msg("Building with leak checking")
45 #endif
46 
47 // includes for time measurement moved to platform.cpp
48 
49 /****************************************
50 X S L   c o n s t a n t s
51 ****************************************/
52 
53 // !!!!!!!!!!!!!!!!!!!!!
54 // the order of items in the following tables must agree with
55 // that in the corresponding enums as defined in base.h
56 
57 const char* xslOpNames[]=
58 {
59     "apply-imports","apply-templates",
60     "attribute","attribute-set",
61     "call-template","choose",
62     "comment", "copy","copy-of",
63     "decimal-format","element",
64     "fallback","for-each",
65     "if","import",
66     "include","key",
67     "message","namespace-alias",
68     "number","otherwise",
69     "output","param",
70     "preserve-space","processing-instruction",
71     "sort","strip-space",
72     "stylesheet","template",
73     "text","transform",
74     "value-of","variable",
75     "when","with-param",
76     NULL
77 };
78 
79 const char* xslAttNames[]=
80 {
81     "case-order", "cdata-section-elements", "count",
82     "data-type", "decimal-separator", "digit", "disable-output-escaping", "doctype-public", "doctype-system",
83     "elements", "encoding", "exclude-result-prefixes", "extension-element-prefixes",
84     "format", "from",
85     "grouping-separator", "grouping-size",
86     "href",
87     "id", "indent", "infinity",
88     "lang", "letter-value", "level",
89     "match", "media-type", "method", "minus-sign", "mode",
90     "name", "namespace", "NaN",
91     "omit-xml-declaration", "order",
92     "pattern-separator", "percent", "per-mille", "priority",
93     "result-prefix",
94     "select", "standalone", "stylesheet-prefix",
95     "terminate", "test",
96     "use", "use-attribute-sets",
97     "value", "version",
98     "zero-digit",
99     NULL
100 };
101 
102 const char* axisNames[]=
103 {
104     "ancestor","ancestor-or-self",
105         "attribute","child",
106         "descendant","descendant-or-self",
107         "following","following-sibling",
108         "namespace","parent",
109         "preceding","preceding-sibling",
110         "self",
111         NULL,
112         "root"
113 };
114 
115 const char* vertexTypeNames[] =
116 {
117     "","root","element","attribute",
118         "text","processing instruction","comment","namespace"
119 };
120 
121 const char* exNodeTypeNames[] =
122 {
123     "node", "text",
124         "processing-instruction", "comment",
125         NULL
126 };
127 
128 const char* theXSLTNamespace = "http://www.w3.org/1999/XSL/Transform";
129 const char* oldXSLTNamespace = "http://www.w3.org/XSL/Transform/1.0";
130 const char* theXMLNamespace = "http://www.w3.org/XML/1998/namespace";
131 const char* theXHTMLNamespace = "http://www.w3.org/1999/xhtml";
132 const char* theXMLNSNamespace = "http://www.w3.org/2000/xmlns/";
133 const char* theSabExtNamespace = "http://www.gingerall.org/sablotron/extension";
134 const char* theEXSLTDynNamespace = "http://exslt.org/dynamic";
135 
136 const char* theWhitespace = " \t\x0a\x0d";
137 
138 //
139 //  escape strings
140 //
141 
142 const char
143     * escNewline = "&#10;",
144     * escTab = "&#9;",
145     * escLess = "&lt;",
146     * escGreater = "&gt;",
147     * escQuote = "&quot;",
148     * escApos = "&apos;";
149 
150 //
151 //  handler types
152 //  to match HandlerType in shandler.h
153 //
154 
155 const char* hlrTypeNames[] = {"message", "scheme", "streaming",
156                               "miscellaneous", "encoding"};
157 
158 /*****************************************************************
159 Global handlers that can be set via Sablot functions
160 *****************************************************************/
161 
162 // URI scheme handler
163 SchemeHandler* theSchemeHandler = NULL;
164 // message handler (errors, warnings, log messages...)
165 MessageHandler* theMessageHandler = NULL;
166 // SAX call handler (streamed access to the result document)
167 SAXHandler* theSAXHandler = NULL;
168 void* theSAXUserData = NULL;
169 
170 /****************************************
171 l o o k u p
172 ****************************************/
173 
174 // Finds a string in a NULL-terminated table of pointers.
175 
lookup(const char * str,const char ** table)176 int lookup(const char* str, const char** table)
177 {
178     const char **p = table;
179     int i = 0;
180     while (*p)
181     {
182         if (!strcmp(str,*p)) return i;
183         p++; i++;
184     };
185     return i;
186 }
187 
lookupNoCase(const char * str,const char ** table)188 int lookupNoCase(const char* str, const char** table)
189 {
190     const char **p = table;
191     int i = 0;
192     while (*p)
193     {
194         if (strEqNoCase(str,*p)) return i;
195         p++; i++;
196     };
197     return i;
198 }
199 
200 
201 
202 /*****************************************************************
203 stdopen(), stdclose()
204 *****************************************************************/
205 
isstd(const char * fname)206 Bool isstd(const char *fname)
207 {
208     if (!strcmp(fname,"/__stdin") || !strcmp(fname,"/__stderr")
209         || !strcmp(fname,"/__stdout"))
210         return TRUE;
211     return FALSE;
212 }
213 
stdclose(FILE * f)214 int stdclose(FILE *f)
215 {
216     if ((!f) || (f == stdin) || (f == stdout) || (f == stderr))
217         return 0;
218     else return fclose(f);
219 }
220 
stdopen(const char * fn,const char * mode)221 FILE* stdopen(const char *fn, const char *mode)
222 {
223   if (!strcmp(fn,"/__stderr"))
224     return stderr;
225   else if (!strcmp(fn,"/__stdout"))
226     return stdout;
227   else if (!strcmp(fn,"/__stdin"))
228     return stdin;
229   else
230     {
231       //we suppose we are working with uri PATH part
232       //on windows platforms it has form "/c:/bla/blah"
233       //so we need to remove the leading slash
234 #ifdef __WIN_TOOLS
235       const char * _fn;
236       if (fn[0] == '/' && fn[2] == ':')
237 	_fn = fn + 1;
238       else
239 	_fn = fn;
240 #else
241       const char * _fn = fn;
242 #endif
243       FILE* x = fopen(_fn,mode);
244       if (x) return x;
245       return NULL;
246     };
247 };
248 
249 /*****************************************************************
250 strEqNoCase
251 *****************************************************************/
252 
strEqNoCase(const char * s1,const char * s2)253 Bool strEqNoCase(const char* s1, const char* s2)
254 {
255     int i;
256     for (i = 0; s1[i]; i++)
257     {
258         if (tolower(s1[i]) != tolower(s2[i]))
259             return FALSE;
260     }
261     return s2[i] ? FALSE : TRUE;
262 }
263 
264 /*****************************************************************
265 Memory leaks
266 *****************************************************************/
267 
checkLeak()268 void checkLeak()
269 {
270 #if (defined(WIN32) && defined(CHECK_LEAKS))
271     _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
272     _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
273     _CrtMemDumpAllObjectsSince(NULL);
274 #endif
275 }
276 
memStats()277 void memStats()
278 {
279 #if (defined(WIN32) && defined(CHECK_LEAKS))
280     _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
281     _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
282     _CrtMemState memsnap;
283     _CrtMemCheckpoint(&memsnap);
284     _CrtMemDumpStatistics(&memsnap);
285 #endif
286 }
287 
288 /*****************************************************************
289 new handler
290 *****************************************************************/
291 
292 //#ifdef _DEBUG
293 //#pragma Msg("'new' handler in linux?")
294 //#endif
295 /*
296 #ifdef WIN32
297 static _PNH oldNewHandler = NULL;
298 #endif
299 
300 int sablotNewHandler(size_t size)
301 {
302 #if defined(WIN32) || defined(__linux__) || defined(__unix)
303         throw(E_MEMORY);
304 #else
305         //situation.error(E_MEMORY, *theEmptyString, theEmptyString);
306 #endif
307     return 0;
308 }
309 
310 void pushNewHandler()
311 {
312 #ifdef WIN32
313     sabassert(!oldNewHandler);
314     oldNewHandler = _set_new_handler(sablotNewHandler);
315 #endif
316 }
317 
318 void popNewHandler()
319 {
320 #ifdef WIN32
321     _set_new_handler( oldNewHandler );
322     oldNewHandler = NULL;
323 #endif
324 }
325 */
326 /*****************************************************************
327 fcomp
328 
329   float comparison: returns 0 / 1 / -1 if p1 == / > / < p2.
330 *****************************************************************/
331 
fcomp(double p1,double p2)332 int fcomp(double p1, double p2)
333 {
334     double d = p1 - p2;
335     if ((d < EPS) && (d > -EPS)) return 0;
336     else return (d > 0 ? 1 : -1);
337 }
338 
339 //  time
340 
getMillisecsDiff(double originalTime)341 Str getMillisecsDiff(double originalTime)
342 {
343     char buf[20];
344     // getMillisecs() is in platform.cpp
345     sprintf(buf, "%.3f", getMillisecs() - originalTime);
346     return Str(buf);
347 }
348 
349 
350 /**************** XML name checks ********************/
351 
isValidNCName(const char * name)352 Bool isValidNCName(const char* name)
353 {
354   int len = utf8StrLength(name);
355   if (len == 0) return FALSE;
356 
357   wchar_t *buff = new wchar_t[len + 1];
358 
359   utf8ToUtf16(buff, name);
360 
361   Bool result = utf8IsLetter(buff[0]) || buff[0] == 0x005F; //underscore
362   for (int i = 1; i < len && result; i++)
363     {
364       result =
365 	utf8IsLetter(buff[i]) ||
366 	utf8IsDigit(buff[i]) ||
367 	utf8IsCombiningChar(buff[i]) ||
368 	utf8IsExtender(buff[i]) ||
369 	buff[i] == 0x002E || //dot
370 	buff[i] == 0x002D || //hyphen
371 	buff[i] == 0x005F; //underscore
372     }
373 
374   delete[] buff;
375   return result;
376 }
377 
isValidQName(const char * name)378 Bool isValidQName(const char* name)
379 {
380   char *local = NULL;
381   char *start = NULL;
382   Bool copy = false;
383   Bool result = TRUE;
384 
385   char *colon = (char *)strchr(name, ':');
386   if (colon)
387     {
388       //*colon = '\0';
389       local = colon + 1;
390       copy = true;
391       start = new char[colon - name + 1];
392       strncpy(start, name, colon - name);
393       start[colon - name] = '\0';
394     } else {
395       start = (char*)name;
396     }
397 
398   result = isValidNCName(start) && (local == NULL || isValidNCName(local));
399 
400   //if (colon) *colon = ':';
401   if (copy) delete start;
402   return result;
403 }
404 
405 
406 //string parsing
getWhDelimString(char * & list,Str & firstPart)407 Bool getWhDelimString(char *&list, Str& firstPart)
408 {
409     skipWhite(list);
410     if (!*list) return FALSE;
411     char *list_was = list;
412     for(; *list && !isWhite(*list); list++);
413     firstPart.nset(list_was, (int)(list - list_was));
414     return TRUE;
415 }
416