blob: a47f9894c0a17bbbd83d1ba6e6e03763381b328d [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/**
2 * uri.c: set of generic URI related routines
3 *
William M. Brack015ccb22005-02-13 08:18:52 +00004 * Reference: RFCs 2396, 2732 and 2373
Owen Taylor3473f882001-02-23 17:55:21 +00005 *
6 * See Copyright for the status of this software.
7 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00008 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00009 */
10
Daniel Veillard34ce8be2002-03-18 19:37:11 +000011#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000012#include "libxml.h"
13
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
15
16#include <libxml/xmlmemory.h>
17#include <libxml/uri.h>
Daniel Veillardd0463562001-10-13 09:15:48 +000018#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000019#include <libxml/xmlerror.h>
20
21/************************************************************************
22 * *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000023 * Macros to differentiate various character type *
Owen Taylor3473f882001-02-23 17:55:21 +000024 * directly extracted from RFC 2396 *
25 * *
26 ************************************************************************/
27
28/*
29 * alpha = lowalpha | upalpha
30 */
31#define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
32
33
34/*
35 * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
36 * "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
37 * "u" | "v" | "w" | "x" | "y" | "z"
38 */
39
40#define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
41
42/*
43 * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
44 * "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
45 * "U" | "V" | "W" | "X" | "Y" | "Z"
46 */
47#define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
48
Daniel Veillardbe3eb202004-07-09 12:05:25 +000049#ifdef IS_DIGIT
50#undef IS_DIGIT
51#endif
Owen Taylor3473f882001-02-23 17:55:21 +000052/*
53 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
54 */
Owen Taylor3473f882001-02-23 17:55:21 +000055#define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
56
57/*
58 * alphanum = alpha | digit
59 */
60
61#define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
62
63/*
64 * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
65 * "a" | "b" | "c" | "d" | "e" | "f"
66 */
67
68#define IS_HEX(x) ((IS_DIGIT(x)) || (((x) >= 'a') && ((x) <= 'f')) || \
69 (((x) >= 'A') && ((x) <= 'F')))
70
71/*
72 * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
73 */
74
75#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') || \
76 ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') || \
77 ((x) == '(') || ((x) == ')'))
78
79
80/*
William M. Brack015ccb22005-02-13 08:18:52 +000081 * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
82 * "[" | "]"
Owen Taylor3473f882001-02-23 17:55:21 +000083 */
84
85#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
86 ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
William M. Brack015ccb22005-02-13 08:18:52 +000087 ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
88 ((x) == ']'))
Owen Taylor3473f882001-02-23 17:55:21 +000089
90/*
91 * unreserved = alphanum | mark
92 */
93
94#define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
95
96/*
97 * escaped = "%" hex hex
98 */
99
100#define IS_ESCAPED(p) ((*(p) == '%') && (IS_HEX((p)[1])) && \
101 (IS_HEX((p)[2])))
102
103/*
104 * uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
105 * "&" | "=" | "+" | "$" | ","
106 */
107#define IS_URIC_NO_SLASH(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||\
108 ((*(p) == ';')) || ((*(p) == '?')) || ((*(p) == ':')) ||\
109 ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||\
110 ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ',')))
111
112/*
113 * pchar = unreserved | escaped | ":" | "@" | "&" | "=" | "+" | "$" | ","
114 */
115#define IS_PCHAR(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \
116 ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||\
117 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||\
118 ((*(p) == ',')))
119
120/*
121 * rel_segment = 1*( unreserved | escaped |
122 * ";" | "@" | "&" | "=" | "+" | "$" | "," )
123 */
124
125#define IS_SEGMENT(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \
126 ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) || \
127 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) || \
128 ((*(p) == ',')))
129
130/*
131 * scheme = alpha *( alpha | digit | "+" | "-" | "." )
132 */
133
134#define IS_SCHEME(x) ((IS_ALPHA(x)) || (IS_DIGIT(x)) || \
135 ((x) == '+') || ((x) == '-') || ((x) == '.'))
136
137/*
138 * reg_name = 1*( unreserved | escaped | "$" | "," |
139 * ";" | ":" | "@" | "&" | "=" | "+" )
140 */
141
142#define IS_REG_NAME(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \
143 ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) || \
144 ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) || \
145 ((*(p) == '=')) || ((*(p) == '+')))
146
147/*
148 * userinfo = *( unreserved | escaped | ";" | ":" | "&" | "=" |
149 * "+" | "$" | "," )
150 */
151#define IS_USERINFO(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \
152 ((*(p) == ';')) || ((*(p) == ':')) || ((*(p) == '&')) || \
153 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) || \
154 ((*(p) == ',')))
155
156/*
157 * uric = reserved | unreserved | escaped
158 */
159
160#define IS_URIC(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \
161 (IS_RESERVED(*(p))))
162
Daniel Veillard4def3bd2001-10-30 09:47:47 +0000163/*
William M. Brack015ccb22005-02-13 08:18:52 +0000164* unwise = "{" | "}" | "|" | "\" | "^" | "`"
Daniel Veillard4def3bd2001-10-30 09:47:47 +0000165*/
Daniel Veillardbb6808e2001-10-29 23:59:27 +0000166
Daniel Veillard4def3bd2001-10-30 09:47:47 +0000167#define IS_UNWISE(p) \
168 (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) || \
169 ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) || \
170 ((*(p) == ']')) || ((*(p) == '`')))
Daniel Veillardbb6808e2001-10-29 23:59:27 +0000171
172/*
Owen Taylor3473f882001-02-23 17:55:21 +0000173 * Skip to next pointer char, handle escaped sequences
174 */
175
176#define NEXT(p) ((*p == '%')? p += 3 : p++)
177
178/*
179 * Productions from the spec.
180 *
181 * authority = server | reg_name
182 * reg_name = 1*( unreserved | escaped | "$" | "," |
183 * ";" | ":" | "@" | "&" | "=" | "+" )
184 *
185 * path = [ abs_path | opaque_part ]
186 */
187
Daniel Veillard336a8e12005-08-07 10:46:19 +0000188#define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n))
189
Owen Taylor3473f882001-02-23 17:55:21 +0000190/************************************************************************
191 * *
192 * Generic URI structure functions *
193 * *
194 ************************************************************************/
195
196/**
197 * xmlCreateURI:
198 *
199 * Simply creates an empty xmlURI
200 *
201 * Returns the new structure or NULL in case of error
202 */
203xmlURIPtr
204xmlCreateURI(void) {
205 xmlURIPtr ret;
206
207 ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI));
208 if (ret == NULL) {
209 xmlGenericError(xmlGenericErrorContext,
210 "xmlCreateURI: out of memory\n");
211 return(NULL);
212 }
213 memset(ret, 0, sizeof(xmlURI));
214 return(ret);
215}
216
217/**
218 * xmlSaveUri:
219 * @uri: pointer to an xmlURI
220 *
221 * Save the URI as an escaped string
222 *
223 * Returns a new string (to be deallocated by caller)
224 */
225xmlChar *
226xmlSaveUri(xmlURIPtr uri) {
227 xmlChar *ret = NULL;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000228 xmlChar *temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000229 const char *p;
230 int len;
231 int max;
232
233 if (uri == NULL) return(NULL);
234
235
236 max = 80;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000237 ret = (xmlChar *) xmlMallocAtomic((max + 1) * sizeof(xmlChar));
Owen Taylor3473f882001-02-23 17:55:21 +0000238 if (ret == NULL) {
239 xmlGenericError(xmlGenericErrorContext,
240 "xmlSaveUri: out of memory\n");
241 return(NULL);
242 }
243 len = 0;
244
245 if (uri->scheme != NULL) {
246 p = uri->scheme;
247 while (*p != 0) {
248 if (len >= max) {
249 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000250 temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
251 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000252 xmlGenericError(xmlGenericErrorContext,
253 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000254 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000255 return(NULL);
256 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000257 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000258 }
259 ret[len++] = *p++;
260 }
261 if (len >= max) {
262 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000263 temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
264 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000265 xmlGenericError(xmlGenericErrorContext,
266 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000267 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000268 return(NULL);
269 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000270 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000271 }
272 ret[len++] = ':';
273 }
274 if (uri->opaque != NULL) {
275 p = uri->opaque;
276 while (*p != 0) {
277 if (len + 3 >= max) {
278 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000279 temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
280 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000281 xmlGenericError(xmlGenericErrorContext,
282 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000283 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000284 return(NULL);
285 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000286 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000287 }
Daniel Veillard9231ff92003-03-23 22:00:51 +0000288 if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
Owen Taylor3473f882001-02-23 17:55:21 +0000289 ret[len++] = *p++;
290 else {
291 int val = *(unsigned char *)p++;
292 int hi = val / 0x10, lo = val % 0x10;
293 ret[len++] = '%';
294 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
295 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
296 }
297 }
Owen Taylor3473f882001-02-23 17:55:21 +0000298 } else {
299 if (uri->server != NULL) {
300 if (len + 3 >= max) {
301 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000302 temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
303 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000304 xmlGenericError(xmlGenericErrorContext,
305 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000306 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000307 return(NULL);
308 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000309 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000310 }
311 ret[len++] = '/';
312 ret[len++] = '/';
313 if (uri->user != NULL) {
314 p = uri->user;
315 while (*p != 0) {
316 if (len + 3 >= max) {
317 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000318 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000319 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000320 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000321 xmlGenericError(xmlGenericErrorContext,
322 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000323 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000324 return(NULL);
325 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000326 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000327 }
328 if ((IS_UNRESERVED(*(p))) ||
329 ((*(p) == ';')) || ((*(p) == ':')) ||
330 ((*(p) == '&')) || ((*(p) == '=')) ||
331 ((*(p) == '+')) || ((*(p) == '$')) ||
332 ((*(p) == ',')))
333 ret[len++] = *p++;
334 else {
335 int val = *(unsigned char *)p++;
336 int hi = val / 0x10, lo = val % 0x10;
337 ret[len++] = '%';
338 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
339 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
340 }
341 }
342 if (len + 3 >= max) {
343 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000344 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000345 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000346 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000347 xmlGenericError(xmlGenericErrorContext,
348 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000349 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000350 return(NULL);
351 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000352 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000353 }
354 ret[len++] = '@';
355 }
356 p = uri->server;
357 while (*p != 0) {
358 if (len >= max) {
359 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000360 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000361 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000362 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000363 xmlGenericError(xmlGenericErrorContext,
364 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000365 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000366 return(NULL);
367 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000368 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000369 }
370 ret[len++] = *p++;
371 }
372 if (uri->port > 0) {
373 if (len + 10 >= max) {
374 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000375 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000376 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000377 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000378 xmlGenericError(xmlGenericErrorContext,
379 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000380 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000381 return(NULL);
382 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000383 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000384 }
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000385 len += snprintf((char *) &ret[len], max - len, ":%d", uri->port);
Owen Taylor3473f882001-02-23 17:55:21 +0000386 }
387 } else if (uri->authority != NULL) {
388 if (len + 3 >= max) {
389 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000390 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000391 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000392 if (temp == NULL) {
393 xmlGenericError(xmlGenericErrorContext,
394 "xmlSaveUri: out of memory\n");
395 xmlFree(ret);
396 return(NULL);
397 }
398 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000399 }
400 ret[len++] = '/';
401 ret[len++] = '/';
402 p = uri->authority;
403 while (*p != 0) {
404 if (len + 3 >= max) {
405 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000406 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000407 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000408 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000409 xmlGenericError(xmlGenericErrorContext,
410 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000411 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000412 return(NULL);
413 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000414 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000415 }
416 if ((IS_UNRESERVED(*(p))) ||
417 ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
418 ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
419 ((*(p) == '=')) || ((*(p) == '+')))
420 ret[len++] = *p++;
421 else {
422 int val = *(unsigned char *)p++;
423 int hi = val / 0x10, lo = val % 0x10;
424 ret[len++] = '%';
425 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
426 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
427 }
428 }
429 } else if (uri->scheme != NULL) {
430 if (len + 3 >= max) {
431 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000432 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000433 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000434 if (temp == NULL) {
435 xmlGenericError(xmlGenericErrorContext,
436 "xmlSaveUri: out of memory\n");
437 xmlFree(ret);
438 return(NULL);
439 }
440 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000441 }
442 ret[len++] = '/';
443 ret[len++] = '/';
444 }
445 if (uri->path != NULL) {
446 p = uri->path;
Daniel Veillarde54c3172008-03-25 13:22:41 +0000447 /*
448 * the colon in file:///d: should not be escaped or
449 * Windows accesses fail later.
450 */
451 if ((uri->scheme != NULL) &&
452 (p[0] == '/') &&
453 (((p[1] >= 'a') && (p[1] <= 'z')) ||
454 ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
455 (p[2] == ':') &&
456 (xmlStrEqual(uri->scheme, BAD_CAST "file"))) {
457 if (len + 3 >= max) {
458 max *= 2;
459 ret = (xmlChar *) xmlRealloc(ret,
460 (max + 1) * sizeof(xmlChar));
461 if (ret == NULL) {
462 xmlGenericError(xmlGenericErrorContext,
463 "xmlSaveUri: out of memory\n");
464 return(NULL);
465 }
466 }
467 ret[len++] = *p++;
468 ret[len++] = *p++;
469 ret[len++] = *p++;
470 }
Owen Taylor3473f882001-02-23 17:55:21 +0000471 while (*p != 0) {
472 if (len + 3 >= max) {
473 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000474 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000475 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000476 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000477 xmlGenericError(xmlGenericErrorContext,
478 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000479 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000480 return(NULL);
481 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000482 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000483 }
484 if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
485 ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
486 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
487 ((*(p) == ',')))
488 ret[len++] = *p++;
489 else {
490 int val = *(unsigned char *)p++;
491 int hi = val / 0x10, lo = val % 0x10;
492 ret[len++] = '%';
493 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
494 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
495 }
496 }
497 }
Daniel Veillarda1413b82007-04-26 08:33:28 +0000498 if (uri->query_raw != NULL) {
499 if (len + 1 >= max) {
500 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000501 temp = (xmlChar *) xmlRealloc(ret,
Daniel Veillarda1413b82007-04-26 08:33:28 +0000502 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000503 if (temp == NULL) {
504 xmlGenericError(xmlGenericErrorContext,
505 "xmlSaveUri: out of memory\n");
506 xmlFree(ret);
507 return(NULL);
508 }
509 ret = temp;
Daniel Veillarda1413b82007-04-26 08:33:28 +0000510 }
511 ret[len++] = '?';
512 p = uri->query_raw;
513 while (*p != 0) {
514 if (len + 1 >= max) {
515 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000516 temp = (xmlChar *) xmlRealloc(ret,
Daniel Veillarda1413b82007-04-26 08:33:28 +0000517 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000518 if (temp == NULL) {
Daniel Veillarda1413b82007-04-26 08:33:28 +0000519 xmlGenericError(xmlGenericErrorContext,
520 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000521 xmlFree(ret);
Daniel Veillarda1413b82007-04-26 08:33:28 +0000522 return(NULL);
523 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000524 ret = temp;
Daniel Veillarda1413b82007-04-26 08:33:28 +0000525 }
526 ret[len++] = *p++;
527 }
528 } else if (uri->query != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000529 if (len + 3 >= max) {
530 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000531 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000532 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000533 if (temp == NULL) {
534 xmlGenericError(xmlGenericErrorContext,
535 "xmlSaveUri: out of memory\n");
536 xmlFree(ret);
537 return(NULL);
538 }
539 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000540 }
541 ret[len++] = '?';
542 p = uri->query;
543 while (*p != 0) {
544 if (len + 3 >= max) {
545 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000546 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000547 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000548 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000549 xmlGenericError(xmlGenericErrorContext,
550 "xmlSaveUri: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000551 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000552 return(NULL);
553 }
Daniel Veillarded86dc22008-04-24 11:58:41 +0000554 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000555 }
556 if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
557 ret[len++] = *p++;
558 else {
559 int val = *(unsigned char *)p++;
560 int hi = val / 0x10, lo = val % 0x10;
561 ret[len++] = '%';
562 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
563 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
564 }
565 }
566 }
Daniel Veillardfdd27d22002-11-28 11:55:38 +0000567 }
568 if (uri->fragment != NULL) {
569 if (len + 3 >= max) {
570 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000571 temp = (xmlChar *) xmlRealloc(ret,
Daniel Veillardfdd27d22002-11-28 11:55:38 +0000572 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000573 if (temp == NULL) {
574 xmlGenericError(xmlGenericErrorContext,
575 "xmlSaveUri: out of memory\n");
576 xmlFree(ret);
577 return(NULL);
578 }
579 ret = temp;
Daniel Veillardfdd27d22002-11-28 11:55:38 +0000580 }
581 ret[len++] = '#';
582 p = uri->fragment;
583 while (*p != 0) {
Owen Taylor3473f882001-02-23 17:55:21 +0000584 if (len + 3 >= max) {
585 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000586 temp = (xmlChar *) xmlRealloc(ret,
Owen Taylor3473f882001-02-23 17:55:21 +0000587 (max + 1) * sizeof(xmlChar));
Daniel Veillarded86dc22008-04-24 11:58:41 +0000588 if (temp == NULL) {
589 xmlGenericError(xmlGenericErrorContext,
590 "xmlSaveUri: out of memory\n");
591 xmlFree(ret);
592 return(NULL);
593 }
594 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000595 }
Daniel Veillardfdd27d22002-11-28 11:55:38 +0000596 if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
597 ret[len++] = *p++;
598 else {
599 int val = *(unsigned char *)p++;
600 int hi = val / 0x10, lo = val % 0x10;
601 ret[len++] = '%';
602 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
603 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Owen Taylor3473f882001-02-23 17:55:21 +0000604 }
605 }
Owen Taylor3473f882001-02-23 17:55:21 +0000606 }
Daniel Veillardfdd27d22002-11-28 11:55:38 +0000607 if (len >= max) {
608 max *= 2;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000609 temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
610 if (temp == NULL) {
611 xmlGenericError(xmlGenericErrorContext,
612 "xmlSaveUri: out of memory\n");
613 xmlFree(ret);
614 return(NULL);
615 }
616 ret = temp;
Daniel Veillardfdd27d22002-11-28 11:55:38 +0000617 }
618 ret[len++] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000619 return(ret);
620}
621
622/**
623 * xmlPrintURI:
624 * @stream: a FILE* for the output
625 * @uri: pointer to an xmlURI
626 *
William M. Brackf3cf1a12005-01-06 02:25:59 +0000627 * Prints the URI in the stream @stream.
Owen Taylor3473f882001-02-23 17:55:21 +0000628 */
629void
630xmlPrintURI(FILE *stream, xmlURIPtr uri) {
631 xmlChar *out;
632
633 out = xmlSaveUri(uri);
634 if (out != NULL) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000635 fprintf(stream, "%s", (char *) out);
Owen Taylor3473f882001-02-23 17:55:21 +0000636 xmlFree(out);
637 }
638}
639
640/**
641 * xmlCleanURI:
642 * @uri: pointer to an xmlURI
643 *
644 * Make sure the xmlURI struct is free of content
645 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000646static void
Owen Taylor3473f882001-02-23 17:55:21 +0000647xmlCleanURI(xmlURIPtr uri) {
648 if (uri == NULL) return;
649
650 if (uri->scheme != NULL) xmlFree(uri->scheme);
651 uri->scheme = NULL;
652 if (uri->server != NULL) xmlFree(uri->server);
653 uri->server = NULL;
654 if (uri->user != NULL) xmlFree(uri->user);
655 uri->user = NULL;
656 if (uri->path != NULL) xmlFree(uri->path);
657 uri->path = NULL;
658 if (uri->fragment != NULL) xmlFree(uri->fragment);
659 uri->fragment = NULL;
660 if (uri->opaque != NULL) xmlFree(uri->opaque);
661 uri->opaque = NULL;
662 if (uri->authority != NULL) xmlFree(uri->authority);
663 uri->authority = NULL;
664 if (uri->query != NULL) xmlFree(uri->query);
665 uri->query = NULL;
Daniel Veillarda1413b82007-04-26 08:33:28 +0000666 if (uri->query_raw != NULL) xmlFree(uri->query_raw);
667 uri->query_raw = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000668}
669
670/**
671 * xmlFreeURI:
672 * @uri: pointer to an xmlURI
673 *
674 * Free up the xmlURI struct
675 */
676void
677xmlFreeURI(xmlURIPtr uri) {
678 if (uri == NULL) return;
679
680 if (uri->scheme != NULL) xmlFree(uri->scheme);
681 if (uri->server != NULL) xmlFree(uri->server);
682 if (uri->user != NULL) xmlFree(uri->user);
683 if (uri->path != NULL) xmlFree(uri->path);
684 if (uri->fragment != NULL) xmlFree(uri->fragment);
685 if (uri->opaque != NULL) xmlFree(uri->opaque);
686 if (uri->authority != NULL) xmlFree(uri->authority);
687 if (uri->query != NULL) xmlFree(uri->query);
Daniel Veillarda1413b82007-04-26 08:33:28 +0000688 if (uri->query_raw != NULL) xmlFree(uri->query_raw);
Owen Taylor3473f882001-02-23 17:55:21 +0000689 xmlFree(uri);
690}
691
692/************************************************************************
693 * *
694 * Helper functions *
695 * *
696 ************************************************************************/
697
Owen Taylor3473f882001-02-23 17:55:21 +0000698/**
699 * xmlNormalizeURIPath:
700 * @path: pointer to the path string
701 *
702 * Applies the 5 normalization steps to a path string--that is, RFC 2396
703 * Section 5.2, steps 6.c through 6.g.
704 *
705 * Normalization occurs directly on the string, no new allocation is done
706 *
707 * Returns 0 or an error code
708 */
709int
710xmlNormalizeURIPath(char *path) {
711 char *cur, *out;
712
713 if (path == NULL)
714 return(-1);
715
716 /* Skip all initial "/" chars. We want to get to the beginning of the
717 * first non-empty segment.
718 */
719 cur = path;
720 while (cur[0] == '/')
721 ++cur;
722 if (cur[0] == '\0')
723 return(0);
724
725 /* Keep everything we've seen so far. */
726 out = cur;
727
728 /*
729 * Analyze each segment in sequence for cases (c) and (d).
730 */
731 while (cur[0] != '\0') {
732 /*
733 * c) All occurrences of "./", where "." is a complete path segment,
734 * are removed from the buffer string.
735 */
736 if ((cur[0] == '.') && (cur[1] == '/')) {
737 cur += 2;
Daniel Veillardfcbd74a2001-06-26 07:47:23 +0000738 /* '//' normalization should be done at this point too */
739 while (cur[0] == '/')
740 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +0000741 continue;
742 }
743
744 /*
745 * d) If the buffer string ends with "." as a complete path segment,
746 * that "." is removed.
747 */
748 if ((cur[0] == '.') && (cur[1] == '\0'))
749 break;
750
751 /* Otherwise keep the segment. */
752 while (cur[0] != '/') {
753 if (cur[0] == '\0')
754 goto done_cd;
755 (out++)[0] = (cur++)[0];
756 }
Daniel Veillardfcbd74a2001-06-26 07:47:23 +0000757 /* nomalize // */
758 while ((cur[0] == '/') && (cur[1] == '/'))
759 cur++;
760
Owen Taylor3473f882001-02-23 17:55:21 +0000761 (out++)[0] = (cur++)[0];
762 }
763 done_cd:
764 out[0] = '\0';
765
766 /* Reset to the beginning of the first segment for the next sequence. */
767 cur = path;
768 while (cur[0] == '/')
769 ++cur;
770 if (cur[0] == '\0')
771 return(0);
772
773 /*
774 * Analyze each segment in sequence for cases (e) and (f).
775 *
776 * e) All occurrences of "<segment>/../", where <segment> is a
777 * complete path segment not equal to "..", are removed from the
778 * buffer string. Removal of these path segments is performed
779 * iteratively, removing the leftmost matching pattern on each
780 * iteration, until no matching pattern remains.
781 *
782 * f) If the buffer string ends with "<segment>/..", where <segment>
783 * is a complete path segment not equal to "..", that
784 * "<segment>/.." is removed.
785 *
786 * To satisfy the "iterative" clause in (e), we need to collapse the
787 * string every time we find something that needs to be removed. Thus,
788 * we don't need to keep two pointers into the string: we only need a
789 * "current position" pointer.
790 */
791 while (1) {
Daniel Veillard608d0ac2003-08-14 22:44:25 +0000792 char *segp, *tmp;
Owen Taylor3473f882001-02-23 17:55:21 +0000793
794 /* At the beginning of each iteration of this loop, "cur" points to
795 * the first character of the segment we want to examine.
796 */
797
798 /* Find the end of the current segment. */
799 segp = cur;
800 while ((segp[0] != '/') && (segp[0] != '\0'))
801 ++segp;
802
803 /* If this is the last segment, we're done (we need at least two
804 * segments to meet the criteria for the (e) and (f) cases).
805 */
806 if (segp[0] == '\0')
807 break;
808
809 /* If the first segment is "..", or if the next segment _isn't_ "..",
810 * keep this segment and try the next one.
811 */
812 ++segp;
813 if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
814 || ((segp[0] != '.') || (segp[1] != '.')
815 || ((segp[2] != '/') && (segp[2] != '\0')))) {
816 cur = segp;
817 continue;
818 }
819
820 /* If we get here, remove this segment and the next one and back up
821 * to the previous segment (if there is one), to implement the
822 * "iteratively" clause. It's pretty much impossible to back up
823 * while maintaining two pointers into the buffer, so just compact
824 * the whole buffer now.
825 */
826
827 /* If this is the end of the buffer, we're done. */
828 if (segp[2] == '\0') {
829 cur[0] = '\0';
830 break;
831 }
Daniel Veillard608d0ac2003-08-14 22:44:25 +0000832 /* Valgrind complained, strcpy(cur, segp + 3); */
833 /* string will overlap, do not use strcpy */
834 tmp = cur;
835 segp += 3;
836 while ((*tmp++ = *segp++) != 0);
Owen Taylor3473f882001-02-23 17:55:21 +0000837
838 /* If there are no previous segments, then keep going from here. */
839 segp = cur;
840 while ((segp > path) && ((--segp)[0] == '/'))
841 ;
842 if (segp == path)
843 continue;
844
845 /* "segp" is pointing to the end of a previous segment; find it's
846 * start. We need to back up to the previous segment and start
847 * over with that to handle things like "foo/bar/../..". If we
848 * don't do this, then on the first pass we'll remove the "bar/..",
849 * but be pointing at the second ".." so we won't realize we can also
850 * remove the "foo/..".
851 */
852 cur = segp;
853 while ((cur > path) && (cur[-1] != '/'))
854 --cur;
855 }
856 out[0] = '\0';
857
858 /*
859 * g) If the resulting buffer string still begins with one or more
860 * complete path segments of "..", then the reference is
861 * considered to be in error. Implementations may handle this
862 * error by retaining these components in the resolved path (i.e.,
863 * treating them as part of the final URI), by removing them from
864 * the resolved path (i.e., discarding relative levels above the
865 * root), or by avoiding traversal of the reference.
866 *
867 * We discard them from the final path.
868 */
869 if (path[0] == '/') {
870 cur = path;
Daniel Veillard9231ff92003-03-23 22:00:51 +0000871 while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
Owen Taylor3473f882001-02-23 17:55:21 +0000872 && ((cur[3] == '/') || (cur[3] == '\0')))
873 cur += 3;
874
875 if (cur != path) {
876 out = path;
877 while (cur[0] != '\0')
878 (out++)[0] = (cur++)[0];
879 out[0] = 0;
880 }
881 }
882
883 return(0);
884}
Owen Taylor3473f882001-02-23 17:55:21 +0000885
Daniel Veillard966a31e2004-05-09 02:58:44 +0000886static int is_hex(char c) {
887 if (((c >= '0') && (c <= '9')) ||
888 ((c >= 'a') && (c <= 'f')) ||
889 ((c >= 'A') && (c <= 'F')))
890 return(1);
891 return(0);
892}
893
Owen Taylor3473f882001-02-23 17:55:21 +0000894/**
895 * xmlURIUnescapeString:
896 * @str: the string to unescape
Daniel Veillard60087f32001-10-10 09:45:09 +0000897 * @len: the length in bytes to unescape (or <= 0 to indicate full string)
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000898 * @target: optional destination buffer
Owen Taylor3473f882001-02-23 17:55:21 +0000899 *
Daniel Veillarda44294f2007-04-24 08:57:54 +0000900 * Unescaping routine, but does not check that the string is an URI. The
901 * output is a direct unsigned char translation of %XX values (no encoding)
Daniel Veillard79187652007-04-24 10:19:52 +0000902 * Note that the length of the result can only be smaller or same size as
903 * the input string.
Owen Taylor3473f882001-02-23 17:55:21 +0000904 *
Daniel Veillard79187652007-04-24 10:19:52 +0000905 * Returns a copy of the string, but unescaped, will return NULL only in case
906 * of error
Owen Taylor3473f882001-02-23 17:55:21 +0000907 */
908char *
909xmlURIUnescapeString(const char *str, int len, char *target) {
910 char *ret, *out;
911 const char *in;
912
913 if (str == NULL)
914 return(NULL);
915 if (len <= 0) len = strlen(str);
Daniel Veillardd2298792003-02-14 16:54:11 +0000916 if (len < 0) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000917
918 if (target == NULL) {
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000919 ret = (char *) xmlMallocAtomic(len + 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000920 if (ret == NULL) {
921 xmlGenericError(xmlGenericErrorContext,
922 "xmlURIUnescapeString: out of memory\n");
923 return(NULL);
924 }
925 } else
926 ret = target;
927 in = str;
928 out = ret;
929 while(len > 0) {
Daniel Veillard8399ff32004-09-22 21:57:53 +0000930 if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
Owen Taylor3473f882001-02-23 17:55:21 +0000931 in++;
932 if ((*in >= '0') && (*in <= '9'))
933 *out = (*in - '0');
934 else if ((*in >= 'a') && (*in <= 'f'))
935 *out = (*in - 'a') + 10;
936 else if ((*in >= 'A') && (*in <= 'F'))
937 *out = (*in - 'A') + 10;
938 in++;
939 if ((*in >= '0') && (*in <= '9'))
940 *out = *out * 16 + (*in - '0');
941 else if ((*in >= 'a') && (*in <= 'f'))
942 *out = *out * 16 + (*in - 'a') + 10;
943 else if ((*in >= 'A') && (*in <= 'F'))
944 *out = *out * 16 + (*in - 'A') + 10;
945 in++;
946 len -= 3;
947 out++;
948 } else {
949 *out++ = *in++;
950 len--;
951 }
952 }
953 *out = 0;
954 return(ret);
955}
956
957/**
Daniel Veillard8514c672001-05-23 10:29:12 +0000958 * xmlURIEscapeStr:
959 * @str: string to escape
960 * @list: exception list string of chars not to escape
Owen Taylor3473f882001-02-23 17:55:21 +0000961 *
Daniel Veillard8514c672001-05-23 10:29:12 +0000962 * This routine escapes a string to hex, ignoring reserved characters (a-z)
963 * and the characters in the exception list.
Owen Taylor3473f882001-02-23 17:55:21 +0000964 *
Daniel Veillard8514c672001-05-23 10:29:12 +0000965 * Returns a new escaped string or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +0000966 */
967xmlChar *
Daniel Veillard8514c672001-05-23 10:29:12 +0000968xmlURIEscapeStr(const xmlChar *str, const xmlChar *list) {
969 xmlChar *ret, ch;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000970 xmlChar *temp;
Owen Taylor3473f882001-02-23 17:55:21 +0000971 const xmlChar *in;
Daniel Veillard8514c672001-05-23 10:29:12 +0000972
Owen Taylor3473f882001-02-23 17:55:21 +0000973 unsigned int len, out;
974
975 if (str == NULL)
976 return(NULL);
William M. Brackf3cf1a12005-01-06 02:25:59 +0000977 if (str[0] == 0)
978 return(xmlStrdup(str));
Owen Taylor3473f882001-02-23 17:55:21 +0000979 len = xmlStrlen(str);
Daniel Veillarde645e8c2002-10-22 17:35:37 +0000980 if (!(len > 0)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000981
982 len += 20;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000983 ret = (xmlChar *) xmlMallocAtomic(len);
Owen Taylor3473f882001-02-23 17:55:21 +0000984 if (ret == NULL) {
985 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000986 "xmlURIEscapeStr: out of memory\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000987 return(NULL);
988 }
989 in = (const xmlChar *) str;
990 out = 0;
991 while(*in != 0) {
992 if (len - out <= 3) {
993 len += 20;
Daniel Veillarded86dc22008-04-24 11:58:41 +0000994 temp = (xmlChar *) xmlRealloc(ret, len);
995 if (temp == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +0000996 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000997 "xmlURIEscapeStr: out of memory\n");
Daniel Veillarded86dc22008-04-24 11:58:41 +0000998 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000999 return(NULL);
1000 }
Daniel Veillarded86dc22008-04-24 11:58:41 +00001001 ret = temp;
Owen Taylor3473f882001-02-23 17:55:21 +00001002 }
Daniel Veillard8514c672001-05-23 10:29:12 +00001003
1004 ch = *in;
1005
Daniel Veillardeb475a32002-04-14 22:00:22 +00001006 if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!xmlStrchr(list, ch))) {
Owen Taylor3473f882001-02-23 17:55:21 +00001007 unsigned char val;
1008 ret[out++] = '%';
Daniel Veillard8514c672001-05-23 10:29:12 +00001009 val = ch >> 4;
Owen Taylor3473f882001-02-23 17:55:21 +00001010 if (val <= 9)
1011 ret[out++] = '0' + val;
1012 else
1013 ret[out++] = 'A' + val - 0xA;
Daniel Veillard8514c672001-05-23 10:29:12 +00001014 val = ch & 0xF;
Owen Taylor3473f882001-02-23 17:55:21 +00001015 if (val <= 9)
1016 ret[out++] = '0' + val;
1017 else
1018 ret[out++] = 'A' + val - 0xA;
1019 in++;
1020 } else {
1021 ret[out++] = *in++;
1022 }
Daniel Veillard8514c672001-05-23 10:29:12 +00001023
Owen Taylor3473f882001-02-23 17:55:21 +00001024 }
1025 ret[out] = 0;
1026 return(ret);
1027}
1028
Daniel Veillard8514c672001-05-23 10:29:12 +00001029/**
1030 * xmlURIEscape:
1031 * @str: the string of the URI to escape
1032 *
1033 * Escaping routine, does not do validity checks !
1034 * It will try to escape the chars needing this, but this is heuristic
1035 * based it's impossible to be sure.
1036 *
Daniel Veillard8514c672001-05-23 10:29:12 +00001037 * Returns an copy of the string, but escaped
Daniel Veillard6278fb52001-05-25 07:38:41 +00001038 *
1039 * 25 May 2001
1040 * Uses xmlParseURI and xmlURIEscapeStr to try to escape correctly
1041 * according to RFC2396.
1042 * - Carl Douglas
Daniel Veillard8514c672001-05-23 10:29:12 +00001043 */
1044xmlChar *
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001045xmlURIEscape(const xmlChar * str)
1046{
Daniel Veillard6278fb52001-05-25 07:38:41 +00001047 xmlChar *ret, *segment = NULL;
1048 xmlURIPtr uri;
Daniel Veillardbb6808e2001-10-29 23:59:27 +00001049 int ret2;
Daniel Veillard8514c672001-05-23 10:29:12 +00001050
Daniel Veillard6278fb52001-05-25 07:38:41 +00001051#define NULLCHK(p) if(!p) { \
1052 xmlGenericError(xmlGenericErrorContext, \
1053 "xmlURIEscape: out of memory\n"); \
Daniel Veillarded86dc22008-04-24 11:58:41 +00001054 xmlFreeURI(uri); \
1055 return NULL; } \
Daniel Veillard6278fb52001-05-25 07:38:41 +00001056
Daniel Veillardbb6808e2001-10-29 23:59:27 +00001057 if (str == NULL)
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001058 return (NULL);
Daniel Veillardbb6808e2001-10-29 23:59:27 +00001059
1060 uri = xmlCreateURI();
1061 if (uri != NULL) {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001062 /*
1063 * Allow escaping errors in the unescaped form
1064 */
1065 uri->cleanup = 1;
1066 ret2 = xmlParseURIReference(uri, (const char *)str);
Daniel Veillardbb6808e2001-10-29 23:59:27 +00001067 if (ret2) {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001068 xmlFreeURI(uri);
1069 return (NULL);
1070 }
Daniel Veillardbb6808e2001-10-29 23:59:27 +00001071 }
Daniel Veillard6278fb52001-05-25 07:38:41 +00001072
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001073 if (!uri)
1074 return NULL;
Daniel Veillard6278fb52001-05-25 07:38:41 +00001075
1076 ret = NULL;
1077
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001078 if (uri->scheme) {
1079 segment = xmlURIEscapeStr(BAD_CAST uri->scheme, BAD_CAST "+-.");
1080 NULLCHK(segment)
1081 ret = xmlStrcat(ret, segment);
1082 ret = xmlStrcat(ret, BAD_CAST ":");
1083 xmlFree(segment);
Daniel Veillard6278fb52001-05-25 07:38:41 +00001084 }
1085
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001086 if (uri->authority) {
1087 segment =
1088 xmlURIEscapeStr(BAD_CAST uri->authority, BAD_CAST "/?;:@");
1089 NULLCHK(segment)
1090 ret = xmlStrcat(ret, BAD_CAST "//");
1091 ret = xmlStrcat(ret, segment);
1092 xmlFree(segment);
Daniel Veillard6278fb52001-05-25 07:38:41 +00001093 }
1094
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001095 if (uri->user) {
1096 segment = xmlURIEscapeStr(BAD_CAST uri->user, BAD_CAST ";:&=+$,");
1097 NULLCHK(segment)
Daniel Veillard0a194582004-04-01 20:09:22 +00001098 ret = xmlStrcat(ret,BAD_CAST "//");
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001099 ret = xmlStrcat(ret, segment);
1100 ret = xmlStrcat(ret, BAD_CAST "@");
1101 xmlFree(segment);
Daniel Veillard6278fb52001-05-25 07:38:41 +00001102 }
1103
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001104 if (uri->server) {
1105 segment = xmlURIEscapeStr(BAD_CAST uri->server, BAD_CAST "/?;:@");
1106 NULLCHK(segment)
Daniel Veillard0a194582004-04-01 20:09:22 +00001107 if (uri->user == NULL)
1108 ret = xmlStrcat(ret, BAD_CAST "//");
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001109 ret = xmlStrcat(ret, segment);
1110 xmlFree(segment);
Daniel Veillard6278fb52001-05-25 07:38:41 +00001111 }
1112
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001113 if (uri->port) {
1114 xmlChar port[10];
1115
Daniel Veillard43d3f612001-11-10 11:57:23 +00001116 snprintf((char *) port, 10, "%d", uri->port);
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001117 ret = xmlStrcat(ret, BAD_CAST ":");
1118 ret = xmlStrcat(ret, port);
Daniel Veillard6278fb52001-05-25 07:38:41 +00001119 }
1120
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001121 if (uri->path) {
1122 segment =
1123 xmlURIEscapeStr(BAD_CAST uri->path, BAD_CAST ":@&=+$,/?;");
1124 NULLCHK(segment)
1125 ret = xmlStrcat(ret, segment);
1126 xmlFree(segment);
Daniel Veillard6278fb52001-05-25 07:38:41 +00001127 }
1128
Daniel Veillarda1413b82007-04-26 08:33:28 +00001129 if (uri->query_raw) {
1130 ret = xmlStrcat(ret, BAD_CAST "?");
1131 ret = xmlStrcat(ret, BAD_CAST uri->query_raw);
1132 }
1133 else if (uri->query) {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001134 segment =
1135 xmlURIEscapeStr(BAD_CAST uri->query, BAD_CAST ";/?:@&=+,$");
1136 NULLCHK(segment)
1137 ret = xmlStrcat(ret, BAD_CAST "?");
1138 ret = xmlStrcat(ret, segment);
1139 xmlFree(segment);
Daniel Veillard6278fb52001-05-25 07:38:41 +00001140 }
1141
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001142 if (uri->opaque) {
1143 segment = xmlURIEscapeStr(BAD_CAST uri->opaque, BAD_CAST "");
1144 NULLCHK(segment)
1145 ret = xmlStrcat(ret, segment);
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001146 xmlFree(segment);
Daniel Veillard6278fb52001-05-25 07:38:41 +00001147 }
1148
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001149 if (uri->fragment) {
1150 segment = xmlURIEscapeStr(BAD_CAST uri->fragment, BAD_CAST "#");
1151 NULLCHK(segment)
1152 ret = xmlStrcat(ret, BAD_CAST "#");
1153 ret = xmlStrcat(ret, segment);
1154 xmlFree(segment);
Daniel Veillard6278fb52001-05-25 07:38:41 +00001155 }
Daniel Veillard43d3f612001-11-10 11:57:23 +00001156
1157 xmlFreeURI(uri);
Daniel Veillard6278fb52001-05-25 07:38:41 +00001158#undef NULLCHK
Daniel Veillard8514c672001-05-23 10:29:12 +00001159
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001160 return (ret);
Daniel Veillard8514c672001-05-23 10:29:12 +00001161}
1162
Owen Taylor3473f882001-02-23 17:55:21 +00001163/************************************************************************
1164 * *
1165 * Escaped URI parsing *
1166 * *
1167 ************************************************************************/
1168
1169/**
1170 * xmlParseURIFragment:
1171 * @uri: pointer to an URI structure
1172 * @str: pointer to the string to analyze
1173 *
1174 * Parse an URI fragment string and fills in the appropriate fields
1175 * of the @uri structure.
1176 *
1177 * fragment = *uric
1178 *
1179 * Returns 0 or the error code
1180 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001181static int
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001182xmlParseURIFragment(xmlURIPtr uri, const char **str)
1183{
Daniel Veillard30e76072006-03-09 14:13:55 +00001184 const char *cur;
1185
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001186 if (str == NULL)
1187 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001188
Daniel Veillard30e76072006-03-09 14:13:55 +00001189 cur = *str;
1190
Daniel Veillardfdd27d22002-11-28 11:55:38 +00001191 while (IS_URIC(cur) || IS_UNWISE(cur))
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001192 NEXT(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001193 if (uri != NULL) {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001194 if (uri->fragment != NULL)
1195 xmlFree(uri->fragment);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001196 if (uri->cleanup & 2)
1197 uri->fragment = STRNDUP(*str, cur - *str);
1198 else
1199 uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001200 }
1201 *str = cur;
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001202 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001203}
1204
1205/**
1206 * xmlParseURIQuery:
1207 * @uri: pointer to an URI structure
1208 * @str: pointer to the string to analyze
1209 *
1210 * Parse the query part of an URI
1211 *
1212 * query = *uric
1213 *
1214 * Returns 0 or the error code
1215 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001216static int
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001217xmlParseURIQuery(xmlURIPtr uri, const char **str)
1218{
Daniel Veillard30e76072006-03-09 14:13:55 +00001219 const char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00001220
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001221 if (str == NULL)
1222 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001223
Daniel Veillard30e76072006-03-09 14:13:55 +00001224 cur = *str;
1225
Daniel Veillard336a8e12005-08-07 10:46:19 +00001226 while ((IS_URIC(cur)) ||
1227 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001228 NEXT(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001229 if (uri != NULL) {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001230 if (uri->query != NULL)
1231 xmlFree(uri->query);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001232 if (uri->cleanup & 2)
1233 uri->query = STRNDUP(*str, cur - *str);
1234 else
1235 uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
Daniel Veillarda1413b82007-04-26 08:33:28 +00001236
1237 /* Save the raw bytes of the query as well.
1238 * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114
1239 */
1240 if (uri->query_raw != NULL)
1241 xmlFree (uri->query_raw);
1242 uri->query_raw = STRNDUP (*str, cur - *str);
Owen Taylor3473f882001-02-23 17:55:21 +00001243 }
1244 *str = cur;
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001245 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001246}
1247
1248/**
1249 * xmlParseURIScheme:
1250 * @uri: pointer to an URI structure
1251 * @str: pointer to the string to analyze
1252 *
1253 * Parse an URI scheme
1254 *
1255 * scheme = alpha *( alpha | digit | "+" | "-" | "." )
1256 *
1257 * Returns 0 or the error code
1258 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001259static int
Owen Taylor3473f882001-02-23 17:55:21 +00001260xmlParseURIScheme(xmlURIPtr uri, const char **str) {
1261 const char *cur;
1262
1263 if (str == NULL)
1264 return(-1);
1265
1266 cur = *str;
1267 if (!IS_ALPHA(*cur))
1268 return(2);
1269 cur++;
1270 while (IS_SCHEME(*cur)) cur++;
1271 if (uri != NULL) {
1272 if (uri->scheme != NULL) xmlFree(uri->scheme);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001273 uri->scheme = STRNDUP(*str, cur - *str);
Owen Taylor3473f882001-02-23 17:55:21 +00001274 }
1275 *str = cur;
1276 return(0);
1277}
1278
1279/**
1280 * xmlParseURIOpaquePart:
1281 * @uri: pointer to an URI structure
1282 * @str: pointer to the string to analyze
1283 *
1284 * Parse an URI opaque part
1285 *
1286 * opaque_part = uric_no_slash *uric
1287 *
1288 * Returns 0 or the error code
1289 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001290static int
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001291xmlParseURIOpaquePart(xmlURIPtr uri, const char **str)
1292{
Owen Taylor3473f882001-02-23 17:55:21 +00001293 const char *cur;
1294
1295 if (str == NULL)
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001296 return (-1);
1297
Owen Taylor3473f882001-02-23 17:55:21 +00001298 cur = *str;
Daniel Veillard336a8e12005-08-07 10:46:19 +00001299 if (!((IS_URIC_NO_SLASH(cur)) ||
1300 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))) {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001301 return (3);
Owen Taylor3473f882001-02-23 17:55:21 +00001302 }
1303 NEXT(cur);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001304 while ((IS_URIC(cur)) ||
1305 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001306 NEXT(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001307 if (uri != NULL) {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001308 if (uri->opaque != NULL)
1309 xmlFree(uri->opaque);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001310 if (uri->cleanup & 2)
1311 uri->opaque = STRNDUP(*str, cur - *str);
1312 else
1313 uri->opaque = xmlURIUnescapeString(*str, cur - *str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001314 }
1315 *str = cur;
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001316 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001317}
1318
1319/**
1320 * xmlParseURIServer:
1321 * @uri: pointer to an URI structure
1322 * @str: pointer to the string to analyze
1323 *
1324 * Parse a server subpart of an URI, it's a finer grain analysis
1325 * of the authority part.
1326 *
1327 * server = [ [ userinfo "@" ] hostport ]
1328 * userinfo = *( unreserved | escaped |
1329 * ";" | ":" | "&" | "=" | "+" | "$" | "," )
1330 * hostport = host [ ":" port ]
William M. Brack015ccb22005-02-13 08:18:52 +00001331 * host = hostname | IPv4address | IPv6reference
Owen Taylor3473f882001-02-23 17:55:21 +00001332 * hostname = *( domainlabel "." ) toplabel [ "." ]
1333 * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
1334 * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
William M. Brack015ccb22005-02-13 08:18:52 +00001335 * IPv6reference = "[" IPv6address "]"
1336 * IPv6address = hexpart [ ":" IPv4address ]
1337 * IPv4address = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
1338 * hexpart = hexseq | hexseq "::" [ hexseq ]| "::" [ hexseq ]
1339 * hexseq = hex4 *( ":" hex4)
1340 * hex4 = 1*4hexdig
Owen Taylor3473f882001-02-23 17:55:21 +00001341 * port = *digit
1342 *
1343 * Returns 0 or the error code
1344 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001345static int
Owen Taylor3473f882001-02-23 17:55:21 +00001346xmlParseURIServer(xmlURIPtr uri, const char **str) {
1347 const char *cur;
1348 const char *host, *tmp;
William M. Brack015ccb22005-02-13 08:18:52 +00001349 const int IPV4max = 4;
1350 const int IPV6max = 8;
Daniel Veillard9231ff92003-03-23 22:00:51 +00001351 int oct;
Owen Taylor3473f882001-02-23 17:55:21 +00001352
1353 if (str == NULL)
1354 return(-1);
1355
1356 cur = *str;
1357
1358 /*
William M. Brack015ccb22005-02-13 08:18:52 +00001359 * is there a userinfo ?
Owen Taylor3473f882001-02-23 17:55:21 +00001360 */
1361 while (IS_USERINFO(cur)) NEXT(cur);
1362 if (*cur == '@') {
1363 if (uri != NULL) {
1364 if (uri->user != NULL) xmlFree(uri->user);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001365 if (uri->cleanup & 2)
Daniel Veillarde61d75f2007-05-28 14:16:33 +00001366 uri->user = STRNDUP(*str, cur - *str);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001367 else
1368 uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001369 }
1370 cur++;
1371 } else {
1372 if (uri != NULL) {
1373 if (uri->user != NULL) xmlFree(uri->user);
1374 uri->user = NULL;
1375 }
1376 cur = *str;
1377 }
1378 /*
1379 * This can be empty in the case where there is no server
1380 */
1381 host = cur;
1382 if (*cur == '/') {
1383 if (uri != NULL) {
1384 if (uri->authority != NULL) xmlFree(uri->authority);
1385 uri->authority = NULL;
1386 if (uri->server != NULL) xmlFree(uri->server);
1387 uri->server = NULL;
1388 uri->port = 0;
1389 }
1390 return(0);
1391 }
1392 /*
William M. Brack015ccb22005-02-13 08:18:52 +00001393 * host part of hostport can denote an IPV4 address, an IPV6 address
1394 * or an unresolved name. Check the IP first, its easier to detect
1395 * errors if wrong one.
1396 * An IPV6 address must start with a '[' and end with a ']'.
Owen Taylor3473f882001-02-23 17:55:21 +00001397 */
William M. Brack015ccb22005-02-13 08:18:52 +00001398 if (*cur == '[') {
1399 int compress=0;
1400 cur++;
1401 for (oct = 0; oct < IPV6max; ++oct) {
1402 if (*cur == ':') {
1403 if (compress)
1404 return(3); /* multiple compression attempted */
1405 if (!oct) { /* initial char is compression */
1406 if (*++cur != ':')
1407 return(3);
1408 }
1409 compress = 1; /* set compression-encountered flag */
1410 cur++; /* skip over the second ':' */
1411 continue;
1412 }
1413 while(IS_HEX(*cur)) cur++;
1414 if (oct == (IPV6max-1))
1415 continue;
1416 if (*cur != ':')
1417 break;
1418 cur++;
1419 }
1420 if ((!compress) && (oct != IPV6max))
1421 return(3);
1422 if (*cur != ']')
1423 return(3);
1424 if (uri != NULL) {
1425 if (uri->server != NULL) xmlFree(uri->server);
1426 uri->server = (char *)xmlStrndup((xmlChar *)host+1,
1427 (cur-host)-1);
1428 }
1429 cur++;
1430 } else {
1431 /*
1432 * Not IPV6, maybe IPV4
1433 */
1434 for (oct = 0; oct < IPV4max; ++oct) {
1435 if (*cur == '.')
1436 return(3); /* e.g. http://.xml/ or http://18.29..30/ */
1437 while(IS_DIGIT(*cur)) cur++;
1438 if (oct == (IPV4max-1))
1439 continue;
1440 if (*cur != '.')
1441 break;
1442 cur++;
1443 }
Owen Taylor3473f882001-02-23 17:55:21 +00001444 }
William M. Brack015ccb22005-02-13 08:18:52 +00001445 if ((host[0] != '[') && (oct < IPV4max || (*cur == '.' && cur++) ||
1446 IS_ALPHA(*cur))) {
Daniel Veillard9231ff92003-03-23 22:00:51 +00001447 /* maybe host_name */
1448 if (!IS_ALPHANUM(*cur))
1449 return(4); /* e.g. http://xml.$oft */
1450 do {
1451 do ++cur; while (IS_ALPHANUM(*cur));
1452 if (*cur == '-') {
1453 --cur;
1454 if (*cur == '.')
1455 return(5); /* e.g. http://xml.-soft */
1456 ++cur;
1457 continue;
1458 }
1459 if (*cur == '.') {
1460 --cur;
1461 if (*cur == '-')
1462 return(6); /* e.g. http://xml-.soft */
1463 if (*cur == '.')
1464 return(7); /* e.g. http://xml..soft */
1465 ++cur;
1466 continue;
1467 }
1468 break;
1469 } while (1);
1470 tmp = cur;
1471 if (tmp[-1] == '.')
1472 --tmp; /* e.g. http://xml.$Oft/ */
1473 do --tmp; while (tmp >= host && IS_ALPHANUM(*tmp));
1474 if ((++tmp == host || tmp[-1] == '.') && !IS_ALPHA(*tmp))
1475 return(8); /* e.g. http://xmlsOft.0rg/ */
Owen Taylor3473f882001-02-23 17:55:21 +00001476 }
Owen Taylor3473f882001-02-23 17:55:21 +00001477 if (uri != NULL) {
1478 if (uri->authority != NULL) xmlFree(uri->authority);
1479 uri->authority = NULL;
William M. Brack015ccb22005-02-13 08:18:52 +00001480 if (host[0] != '[') { /* it's not an IPV6 addr */
1481 if (uri->server != NULL) xmlFree(uri->server);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001482 if (uri->cleanup & 2)
1483 uri->server = STRNDUP(host, cur - host);
1484 else
1485 uri->server = xmlURIUnescapeString(host, cur - host, NULL);
William M. Brack015ccb22005-02-13 08:18:52 +00001486 }
Owen Taylor3473f882001-02-23 17:55:21 +00001487 }
Owen Taylor3473f882001-02-23 17:55:21 +00001488 /*
1489 * finish by checking for a port presence.
1490 */
1491 if (*cur == ':') {
1492 cur++;
1493 if (IS_DIGIT(*cur)) {
1494 if (uri != NULL)
1495 uri->port = 0;
1496 while (IS_DIGIT(*cur)) {
1497 if (uri != NULL)
1498 uri->port = uri->port * 10 + (*cur - '0');
1499 cur++;
1500 }
1501 }
1502 }
1503 *str = cur;
1504 return(0);
1505}
1506
1507/**
1508 * xmlParseURIRelSegment:
1509 * @uri: pointer to an URI structure
1510 * @str: pointer to the string to analyze
1511 *
1512 * Parse an URI relative segment
1513 *
1514 * rel_segment = 1*( unreserved | escaped | ";" | "@" | "&" | "=" |
1515 * "+" | "$" | "," )
1516 *
1517 * Returns 0 or the error code
1518 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001519static int
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001520xmlParseURIRelSegment(xmlURIPtr uri, const char **str)
1521{
Owen Taylor3473f882001-02-23 17:55:21 +00001522 const char *cur;
1523
1524 if (str == NULL)
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001525 return (-1);
1526
Owen Taylor3473f882001-02-23 17:55:21 +00001527 cur = *str;
Daniel Veillard336a8e12005-08-07 10:46:19 +00001528 if (!((IS_SEGMENT(cur)) ||
1529 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))) {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001530 return (3);
Owen Taylor3473f882001-02-23 17:55:21 +00001531 }
1532 NEXT(cur);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001533 while ((IS_SEGMENT(cur)) ||
1534 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001535 NEXT(cur);
Owen Taylor3473f882001-02-23 17:55:21 +00001536 if (uri != NULL) {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001537 if (uri->path != NULL)
1538 xmlFree(uri->path);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001539 if (uri->cleanup & 2)
1540 uri->path = STRNDUP(*str, cur - *str);
1541 else
1542 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001543 }
1544 *str = cur;
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001545 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001546}
1547
1548/**
1549 * xmlParseURIPathSegments:
1550 * @uri: pointer to an URI structure
1551 * @str: pointer to the string to analyze
1552 * @slash: should we add a leading slash
1553 *
1554 * Parse an URI set of path segments
1555 *
1556 * path_segments = segment *( "/" segment )
1557 * segment = *pchar *( ";" param )
1558 * param = *pchar
1559 *
1560 * Returns 0 or the error code
1561 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001562static int
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001563xmlParseURIPathSegments(xmlURIPtr uri, const char **str, int slash)
1564{
Owen Taylor3473f882001-02-23 17:55:21 +00001565 const char *cur;
1566
1567 if (str == NULL)
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001568 return (-1);
1569
Owen Taylor3473f882001-02-23 17:55:21 +00001570 cur = *str;
1571
1572 do {
Daniel Veillard336a8e12005-08-07 10:46:19 +00001573 while ((IS_PCHAR(cur)) ||
1574 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001575 NEXT(cur);
Daniel Veillard234bc4e2002-05-24 11:03:05 +00001576 while (*cur == ';') {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001577 cur++;
Daniel Veillard336a8e12005-08-07 10:46:19 +00001578 while ((IS_PCHAR(cur)) ||
1579 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001580 NEXT(cur);
1581 }
1582 if (*cur != '/')
1583 break;
1584 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00001585 } while (1);
1586 if (uri != NULL) {
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001587 int len, len2 = 0;
1588 char *path;
Owen Taylor3473f882001-02-23 17:55:21 +00001589
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001590 /*
1591 * Concat the set of path segments to the current path
1592 */
1593 len = cur - *str;
1594 if (slash)
1595 len++;
Owen Taylor3473f882001-02-23 17:55:21 +00001596
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001597 if (uri->path != NULL) {
1598 len2 = strlen(uri->path);
1599 len += len2;
1600 }
Daniel Veillard3c908dc2003-04-19 00:07:51 +00001601 path = (char *) xmlMallocAtomic(len + 1);
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001602 if (path == NULL) {
William M. Bracka3215c72004-07-31 16:24:01 +00001603 xmlGenericError(xmlGenericErrorContext,
1604 "xmlParseURIPathSegments: out of memory\n");
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001605 *str = cur;
1606 return (-1);
1607 }
1608 if (uri->path != NULL)
1609 memcpy(path, uri->path, len2);
1610 if (slash) {
1611 path[len2] = '/';
1612 len2++;
1613 }
1614 path[len2] = 0;
Daniel Veillard336a8e12005-08-07 10:46:19 +00001615 if (cur - *str > 0) {
1616 if (uri->cleanup & 2) {
1617 memcpy(&path[len2], *str, cur - *str);
1618 path[len2 + (cur - *str)] = 0;
1619 } else
1620 xmlURIUnescapeString(*str, cur - *str, &path[len2]);
1621 }
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001622 if (uri->path != NULL)
1623 xmlFree(uri->path);
1624 uri->path = path;
Owen Taylor3473f882001-02-23 17:55:21 +00001625 }
1626 *str = cur;
Daniel Veillard4def3bd2001-10-30 09:47:47 +00001627 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00001628}
1629
1630/**
1631 * xmlParseURIAuthority:
1632 * @uri: pointer to an URI structure
1633 * @str: pointer to the string to analyze
1634 *
1635 * Parse the authority part of an URI.
1636 *
1637 * authority = server | reg_name
1638 * server = [ [ userinfo "@" ] hostport ]
1639 * reg_name = 1*( unreserved | escaped | "$" | "," | ";" | ":" |
1640 * "@" | "&" | "=" | "+" )
1641 *
1642 * Note : this is completely ambiguous since reg_name is allowed to
1643 * use the full set of chars in use by server:
1644 *
1645 * 3.2.1. Registry-based Naming Authority
1646 *
1647 * The structure of a registry-based naming authority is specific
1648 * to the URI scheme, but constrained to the allowed characters
1649 * for an authority component.
1650 *
1651 * Returns 0 or the error code
1652 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001653static int
Owen Taylor3473f882001-02-23 17:55:21 +00001654xmlParseURIAuthority(xmlURIPtr uri, const char **str) {
1655 const char *cur;
1656 int ret;
1657
1658 if (str == NULL)
1659 return(-1);
1660
1661 cur = *str;
1662
1663 /*
1664 * try first to parse it as a server string.
1665 */
1666 ret = xmlParseURIServer(uri, str);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001667 if ((ret == 0) && (*str != NULL) &&
1668 ((**str == 0) || (**str == '/') || (**str == '?')))
Owen Taylor3473f882001-02-23 17:55:21 +00001669 return(0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001670 *str = cur;
Owen Taylor3473f882001-02-23 17:55:21 +00001671
1672 /*
1673 * failed, fallback to reg_name
1674 */
1675 if (!IS_REG_NAME(cur)) {
1676 return(5);
1677 }
1678 NEXT(cur);
1679 while (IS_REG_NAME(cur)) NEXT(cur);
1680 if (uri != NULL) {
1681 if (uri->server != NULL) xmlFree(uri->server);
1682 uri->server = NULL;
1683 if (uri->user != NULL) xmlFree(uri->user);
1684 uri->user = NULL;
1685 if (uri->authority != NULL) xmlFree(uri->authority);
Daniel Veillard336a8e12005-08-07 10:46:19 +00001686 if (uri->cleanup & 2)
1687 uri->authority = STRNDUP(*str, cur - *str);
1688 else
1689 uri->authority = xmlURIUnescapeString(*str, cur - *str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001690 }
1691 *str = cur;
1692 return(0);
1693}
1694
1695/**
1696 * xmlParseURIHierPart:
1697 * @uri: pointer to an URI structure
1698 * @str: pointer to the string to analyze
1699 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001700 * Parse an URI hierarchical part
Owen Taylor3473f882001-02-23 17:55:21 +00001701 *
1702 * hier_part = ( net_path | abs_path ) [ "?" query ]
1703 * abs_path = "/" path_segments
1704 * net_path = "//" authority [ abs_path ]
1705 *
1706 * Returns 0 or the error code
1707 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001708static int
Owen Taylor3473f882001-02-23 17:55:21 +00001709xmlParseURIHierPart(xmlURIPtr uri, const char **str) {
1710 int ret;
1711 const char *cur;
1712
1713 if (str == NULL)
1714 return(-1);
1715
1716 cur = *str;
1717
1718 if ((cur[0] == '/') && (cur[1] == '/')) {
1719 cur += 2;
1720 ret = xmlParseURIAuthority(uri, &cur);
1721 if (ret != 0)
1722 return(ret);
1723 if (cur[0] == '/') {
1724 cur++;
1725 ret = xmlParseURIPathSegments(uri, &cur, 1);
1726 }
1727 } else if (cur[0] == '/') {
1728 cur++;
1729 ret = xmlParseURIPathSegments(uri, &cur, 1);
1730 } else {
1731 return(4);
1732 }
1733 if (ret != 0)
1734 return(ret);
1735 if (*cur == '?') {
1736 cur++;
1737 ret = xmlParseURIQuery(uri, &cur);
1738 if (ret != 0)
1739 return(ret);
1740 }
1741 *str = cur;
1742 return(0);
1743}
1744
1745/**
1746 * xmlParseAbsoluteURI:
1747 * @uri: pointer to an URI structure
1748 * @str: pointer to the string to analyze
1749 *
1750 * Parse an URI reference string and fills in the appropriate fields
1751 * of the @uri structure
1752 *
1753 * absoluteURI = scheme ":" ( hier_part | opaque_part )
1754 *
1755 * Returns 0 or the error code
1756 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001757static int
Owen Taylor3473f882001-02-23 17:55:21 +00001758xmlParseAbsoluteURI(xmlURIPtr uri, const char **str) {
1759 int ret;
Daniel Veillard20ee8c02001-10-05 09:18:14 +00001760 const char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00001761
1762 if (str == NULL)
1763 return(-1);
1764
Daniel Veillard20ee8c02001-10-05 09:18:14 +00001765 cur = *str;
1766
Owen Taylor3473f882001-02-23 17:55:21 +00001767 ret = xmlParseURIScheme(uri, str);
1768 if (ret != 0) return(ret);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00001769 if (**str != ':') {
1770 *str = cur;
Owen Taylor3473f882001-02-23 17:55:21 +00001771 return(1);
Daniel Veillard20ee8c02001-10-05 09:18:14 +00001772 }
Owen Taylor3473f882001-02-23 17:55:21 +00001773 (*str)++;
1774 if (**str == '/')
1775 return(xmlParseURIHierPart(uri, str));
1776 return(xmlParseURIOpaquePart(uri, str));
1777}
1778
1779/**
1780 * xmlParseRelativeURI:
1781 * @uri: pointer to an URI structure
1782 * @str: pointer to the string to analyze
1783 *
1784 * Parse an relative URI string and fills in the appropriate fields
1785 * of the @uri structure
1786 *
1787 * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
1788 * abs_path = "/" path_segments
1789 * net_path = "//" authority [ abs_path ]
1790 * rel_path = rel_segment [ abs_path ]
1791 *
1792 * Returns 0 or the error code
1793 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001794static int
Owen Taylor3473f882001-02-23 17:55:21 +00001795xmlParseRelativeURI(xmlURIPtr uri, const char **str) {
1796 int ret = 0;
1797 const char *cur;
1798
1799 if (str == NULL)
1800 return(-1);
1801
1802 cur = *str;
1803 if ((cur[0] == '/') && (cur[1] == '/')) {
1804 cur += 2;
1805 ret = xmlParseURIAuthority(uri, &cur);
1806 if (ret != 0)
1807 return(ret);
1808 if (cur[0] == '/') {
1809 cur++;
1810 ret = xmlParseURIPathSegments(uri, &cur, 1);
1811 }
1812 } else if (cur[0] == '/') {
1813 cur++;
1814 ret = xmlParseURIPathSegments(uri, &cur, 1);
1815 } else if (cur[0] != '#' && cur[0] != '?') {
1816 ret = xmlParseURIRelSegment(uri, &cur);
1817 if (ret != 0)
1818 return(ret);
1819 if (cur[0] == '/') {
1820 cur++;
1821 ret = xmlParseURIPathSegments(uri, &cur, 1);
1822 }
1823 }
1824 if (ret != 0)
1825 return(ret);
1826 if (*cur == '?') {
1827 cur++;
1828 ret = xmlParseURIQuery(uri, &cur);
1829 if (ret != 0)
1830 return(ret);
1831 }
1832 *str = cur;
1833 return(ret);
1834}
1835
1836/**
1837 * xmlParseURIReference:
1838 * @uri: pointer to an URI structure
1839 * @str: the string to analyze
1840 *
1841 * Parse an URI reference string and fills in the appropriate fields
1842 * of the @uri structure
1843 *
1844 * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
1845 *
1846 * Returns 0 or the error code
1847 */
1848int
1849xmlParseURIReference(xmlURIPtr uri, const char *str) {
1850 int ret;
1851 const char *tmp = str;
1852
1853 if (str == NULL)
1854 return(-1);
1855 xmlCleanURI(uri);
1856
1857 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001858 * Try first to parse absolute refs, then fallback to relative if
Owen Taylor3473f882001-02-23 17:55:21 +00001859 * it fails.
1860 */
1861 ret = xmlParseAbsoluteURI(uri, &str);
1862 if (ret != 0) {
1863 xmlCleanURI(uri);
1864 str = tmp;
1865 ret = xmlParseRelativeURI(uri, &str);
1866 }
1867 if (ret != 0) {
1868 xmlCleanURI(uri);
1869 return(ret);
1870 }
1871
1872 if (*str == '#') {
1873 str++;
1874 ret = xmlParseURIFragment(uri, &str);
1875 if (ret != 0) return(ret);
1876 }
1877 if (*str != 0) {
1878 xmlCleanURI(uri);
1879 return(1);
1880 }
1881 return(0);
1882}
1883
1884/**
1885 * xmlParseURI:
1886 * @str: the URI string to analyze
1887 *
1888 * Parse an URI
1889 *
1890 * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
1891 *
William M. Brackf3cf1a12005-01-06 02:25:59 +00001892 * Returns a newly built xmlURIPtr or NULL in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001893 */
1894xmlURIPtr
1895xmlParseURI(const char *str) {
1896 xmlURIPtr uri;
1897 int ret;
1898
1899 if (str == NULL)
1900 return(NULL);
1901 uri = xmlCreateURI();
1902 if (uri != NULL) {
1903 ret = xmlParseURIReference(uri, str);
1904 if (ret) {
1905 xmlFreeURI(uri);
1906 return(NULL);
1907 }
1908 }
1909 return(uri);
1910}
1911
Daniel Veillard336a8e12005-08-07 10:46:19 +00001912/**
1913 * xmlParseURIRaw:
1914 * @str: the URI string to analyze
1915 * @raw: if 1 unescaping of URI pieces are disabled
1916 *
1917 * Parse an URI but allows to keep intact the original fragments.
1918 *
1919 * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
1920 *
1921 * Returns a newly built xmlURIPtr or NULL in case of error
1922 */
1923xmlURIPtr
1924xmlParseURIRaw(const char *str, int raw) {
1925 xmlURIPtr uri;
1926 int ret;
1927
1928 if (str == NULL)
1929 return(NULL);
1930 uri = xmlCreateURI();
1931 if (uri != NULL) {
1932 if (raw) {
1933 uri->cleanup |= 2;
1934 }
1935 ret = xmlParseURIReference(uri, str);
1936 if (ret) {
1937 xmlFreeURI(uri);
1938 return(NULL);
1939 }
1940 }
1941 return(uri);
1942}
1943
Owen Taylor3473f882001-02-23 17:55:21 +00001944/************************************************************************
1945 * *
1946 * Public functions *
1947 * *
1948 ************************************************************************/
1949
1950/**
1951 * xmlBuildURI:
1952 * @URI: the URI instance found in the document
1953 * @base: the base value
1954 *
1955 * Computes he final URI of the reference done by checking that
1956 * the given URI is valid, and building the final URI using the
1957 * base URI. This is processed according to section 5.2 of the
1958 * RFC 2396
1959 *
1960 * 5.2. Resolving Relative References to Absolute Form
1961 *
1962 * Returns a new URI string (to be freed by the caller) or NULL in case
1963 * of error.
1964 */
1965xmlChar *
1966xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
1967 xmlChar *val = NULL;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001968 int ret, len, indx, cur, out;
Owen Taylor3473f882001-02-23 17:55:21 +00001969 xmlURIPtr ref = NULL;
1970 xmlURIPtr bas = NULL;
1971 xmlURIPtr res = NULL;
1972
1973 /*
1974 * 1) The URI reference is parsed into the potential four components and
1975 * fragment identifier, as described in Section 4.3.
1976 *
1977 * NOTE that a completely empty URI is treated by modern browsers
1978 * as a reference to "." rather than as a synonym for the current
1979 * URI. Should we do that here?
1980 */
1981 if (URI == NULL)
1982 ret = -1;
1983 else {
1984 if (*URI) {
1985 ref = xmlCreateURI();
1986 if (ref == NULL)
1987 goto done;
1988 ret = xmlParseURIReference(ref, (const char *) URI);
1989 }
1990 else
1991 ret = 0;
1992 }
1993 if (ret != 0)
1994 goto done;
Daniel Veillard7b4b2f92003-01-06 13:11:20 +00001995 if ((ref != NULL) && (ref->scheme != NULL)) {
1996 /*
1997 * The URI is absolute don't modify.
1998 */
1999 val = xmlStrdup(URI);
2000 goto done;
2001 }
Owen Taylor3473f882001-02-23 17:55:21 +00002002 if (base == NULL)
2003 ret = -1;
2004 else {
2005 bas = xmlCreateURI();
2006 if (bas == NULL)
2007 goto done;
2008 ret = xmlParseURIReference(bas, (const char *) base);
2009 }
2010 if (ret != 0) {
2011 if (ref)
2012 val = xmlSaveUri(ref);
2013 goto done;
2014 }
2015 if (ref == NULL) {
2016 /*
2017 * the base fragment must be ignored
2018 */
2019 if (bas->fragment != NULL) {
2020 xmlFree(bas->fragment);
2021 bas->fragment = NULL;
2022 }
2023 val = xmlSaveUri(bas);
2024 goto done;
2025 }
2026
2027 /*
2028 * 2) If the path component is empty and the scheme, authority, and
2029 * query components are undefined, then it is a reference to the
2030 * current document and we are done. Otherwise, the reference URI's
2031 * query and fragment components are defined as found (or not found)
2032 * within the URI reference and not inherited from the base URI.
2033 *
2034 * NOTE that in modern browsers, the parsing differs from the above
2035 * in the following aspect: the query component is allowed to be
2036 * defined while still treating this as a reference to the current
2037 * document.
2038 */
2039 res = xmlCreateURI();
2040 if (res == NULL)
2041 goto done;
2042 if ((ref->scheme == NULL) && (ref->path == NULL) &&
2043 ((ref->authority == NULL) && (ref->server == NULL))) {
2044 if (bas->scheme != NULL)
2045 res->scheme = xmlMemStrdup(bas->scheme);
2046 if (bas->authority != NULL)
2047 res->authority = xmlMemStrdup(bas->authority);
2048 else if (bas->server != NULL) {
2049 res->server = xmlMemStrdup(bas->server);
2050 if (bas->user != NULL)
2051 res->user = xmlMemStrdup(bas->user);
2052 res->port = bas->port;
2053 }
2054 if (bas->path != NULL)
2055 res->path = xmlMemStrdup(bas->path);
Daniel Veillarda1413b82007-04-26 08:33:28 +00002056 if (ref->query_raw != NULL)
2057 res->query_raw = xmlMemStrdup (ref->query_raw);
2058 else if (ref->query != NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00002059 res->query = xmlMemStrdup(ref->query);
Daniel Veillarda1413b82007-04-26 08:33:28 +00002060 else if (bas->query_raw != NULL)
2061 res->query_raw = xmlMemStrdup(bas->query_raw);
Owen Taylor3473f882001-02-23 17:55:21 +00002062 else if (bas->query != NULL)
2063 res->query = xmlMemStrdup(bas->query);
2064 if (ref->fragment != NULL)
2065 res->fragment = xmlMemStrdup(ref->fragment);
2066 goto step_7;
2067 }
Owen Taylor3473f882001-02-23 17:55:21 +00002068
2069 /*
2070 * 3) If the scheme component is defined, indicating that the reference
2071 * starts with a scheme name, then the reference is interpreted as an
2072 * absolute URI and we are done. Otherwise, the reference URI's
2073 * scheme is inherited from the base URI's scheme component.
2074 */
2075 if (ref->scheme != NULL) {
2076 val = xmlSaveUri(ref);
2077 goto done;
2078 }
2079 if (bas->scheme != NULL)
2080 res->scheme = xmlMemStrdup(bas->scheme);
Daniel Veillard9231ff92003-03-23 22:00:51 +00002081
Daniel Veillarda1413b82007-04-26 08:33:28 +00002082 if (ref->query_raw != NULL)
2083 res->query_raw = xmlMemStrdup(ref->query_raw);
2084 else if (ref->query != NULL)
Daniel Veillard9231ff92003-03-23 22:00:51 +00002085 res->query = xmlMemStrdup(ref->query);
2086 if (ref->fragment != NULL)
2087 res->fragment = xmlMemStrdup(ref->fragment);
Owen Taylor3473f882001-02-23 17:55:21 +00002088
2089 /*
2090 * 4) If the authority component is defined, then the reference is a
2091 * network-path and we skip to step 7. Otherwise, the reference
2092 * URI's authority is inherited from the base URI's authority
2093 * component, which will also be undefined if the URI scheme does not
2094 * use an authority component.
2095 */
2096 if ((ref->authority != NULL) || (ref->server != NULL)) {
2097 if (ref->authority != NULL)
2098 res->authority = xmlMemStrdup(ref->authority);
2099 else {
2100 res->server = xmlMemStrdup(ref->server);
2101 if (ref->user != NULL)
2102 res->user = xmlMemStrdup(ref->user);
2103 res->port = ref->port;
2104 }
2105 if (ref->path != NULL)
2106 res->path = xmlMemStrdup(ref->path);
2107 goto step_7;
2108 }
2109 if (bas->authority != NULL)
2110 res->authority = xmlMemStrdup(bas->authority);
2111 else if (bas->server != NULL) {
2112 res->server = xmlMemStrdup(bas->server);
2113 if (bas->user != NULL)
2114 res->user = xmlMemStrdup(bas->user);
2115 res->port = bas->port;
2116 }
2117
2118 /*
2119 * 5) If the path component begins with a slash character ("/"), then
2120 * the reference is an absolute-path and we skip to step 7.
2121 */
2122 if ((ref->path != NULL) && (ref->path[0] == '/')) {
2123 res->path = xmlMemStrdup(ref->path);
2124 goto step_7;
2125 }
2126
2127
2128 /*
2129 * 6) If this step is reached, then we are resolving a relative-path
2130 * reference. The relative path needs to be merged with the base
2131 * URI's path. Although there are many ways to do this, we will
2132 * describe a simple method using a separate string buffer.
2133 *
2134 * Allocate a buffer large enough for the result string.
2135 */
2136 len = 2; /* extra / and 0 */
2137 if (ref->path != NULL)
2138 len += strlen(ref->path);
2139 if (bas->path != NULL)
2140 len += strlen(bas->path);
Daniel Veillard3c908dc2003-04-19 00:07:51 +00002141 res->path = (char *) xmlMallocAtomic(len);
Owen Taylor3473f882001-02-23 17:55:21 +00002142 if (res->path == NULL) {
2143 xmlGenericError(xmlGenericErrorContext,
2144 "xmlBuildURI: out of memory\n");
2145 goto done;
2146 }
2147 res->path[0] = 0;
2148
2149 /*
2150 * a) All but the last segment of the base URI's path component is
2151 * copied to the buffer. In other words, any characters after the
2152 * last (right-most) slash character, if any, are excluded.
2153 */
2154 cur = 0;
2155 out = 0;
2156 if (bas->path != NULL) {
2157 while (bas->path[cur] != 0) {
2158 while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
2159 cur++;
2160 if (bas->path[cur] == 0)
2161 break;
2162
2163 cur++;
2164 while (out < cur) {
2165 res->path[out] = bas->path[out];
2166 out++;
2167 }
2168 }
2169 }
2170 res->path[out] = 0;
2171
2172 /*
2173 * b) The reference's path component is appended to the buffer
2174 * string.
2175 */
2176 if (ref->path != NULL && ref->path[0] != 0) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002177 indx = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002178 /*
2179 * Ensure the path includes a '/'
2180 */
2181 if ((out == 0) && (bas->server != NULL))
2182 res->path[out++] = '/';
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002183 while (ref->path[indx] != 0) {
2184 res->path[out++] = ref->path[indx++];
Owen Taylor3473f882001-02-23 17:55:21 +00002185 }
2186 }
2187 res->path[out] = 0;
2188
2189 /*
2190 * Steps c) to h) are really path normalization steps
2191 */
2192 xmlNormalizeURIPath(res->path);
2193
2194step_7:
2195
2196 /*
2197 * 7) The resulting URI components, including any inherited from the
2198 * base URI, are recombined to give the absolute form of the URI
2199 * reference.
2200 */
2201 val = xmlSaveUri(res);
2202
2203done:
2204 if (ref != NULL)
2205 xmlFreeURI(ref);
2206 if (bas != NULL)
2207 xmlFreeURI(bas);
2208 if (res != NULL)
2209 xmlFreeURI(res);
2210 return(val);
2211}
2212
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002213/**
William M. Brackf7789b12004-06-07 08:57:27 +00002214 * xmlBuildRelativeURI:
2215 * @URI: the URI reference under consideration
2216 * @base: the base value
2217 *
2218 * Expresses the URI of the reference in terms relative to the
2219 * base. Some examples of this operation include:
2220 * base = "http://site1.com/docs/book1.html"
2221 * URI input URI returned
2222 * docs/pic1.gif pic1.gif
2223 * docs/img/pic1.gif img/pic1.gif
2224 * img/pic1.gif ../img/pic1.gif
2225 * http://site1.com/docs/pic1.gif pic1.gif
2226 * http://site2.com/docs/pic1.gif http://site2.com/docs/pic1.gif
2227 *
2228 * base = "docs/book1.html"
2229 * URI input URI returned
2230 * docs/pic1.gif pic1.gif
2231 * docs/img/pic1.gif img/pic1.gif
2232 * img/pic1.gif ../img/pic1.gif
2233 * http://site1.com/docs/pic1.gif http://site1.com/docs/pic1.gif
2234 *
2235 *
2236 * Note: if the URI reference is really wierd or complicated, it may be
2237 * worthwhile to first convert it into a "nice" one by calling
2238 * xmlBuildURI (using 'base') before calling this routine,
2239 * since this routine (for reasonable efficiency) assumes URI has
2240 * already been through some validation.
2241 *
2242 * Returns a new URI string (to be freed by the caller) or NULL in case
2243 * error.
2244 */
2245xmlChar *
2246xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base)
2247{
2248 xmlChar *val = NULL;
2249 int ret;
2250 int ix;
2251 int pos = 0;
2252 int nbslash = 0;
William M. Brack820d5ed2005-09-14 05:24:27 +00002253 int len;
William M. Brackf7789b12004-06-07 08:57:27 +00002254 xmlURIPtr ref = NULL;
2255 xmlURIPtr bas = NULL;
2256 xmlChar *bptr, *uptr, *vptr;
Daniel Veillard0f7b3312005-09-15 14:15:20 +00002257 int remove_path = 0;
William M. Brackf7789b12004-06-07 08:57:27 +00002258
2259 if ((URI == NULL) || (*URI == 0))
2260 return NULL;
William M. Brackf7789b12004-06-07 08:57:27 +00002261
2262 /*
2263 * First parse URI into a standard form
2264 */
2265 ref = xmlCreateURI ();
2266 if (ref == NULL)
2267 return NULL;
William M. Brack38c4b332005-07-25 18:39:34 +00002268 /* If URI not already in "relative" form */
2269 if (URI[0] != '.') {
2270 ret = xmlParseURIReference (ref, (const char *) URI);
2271 if (ret != 0)
2272 goto done; /* Error in URI, return NULL */
2273 } else
2274 ref->path = (char *)xmlStrdup(URI);
William M. Brackf7789b12004-06-07 08:57:27 +00002275
2276 /*
2277 * Next parse base into the same standard form
2278 */
2279 if ((base == NULL) || (*base == 0)) {
2280 val = xmlStrdup (URI);
2281 goto done;
2282 }
2283 bas = xmlCreateURI ();
2284 if (bas == NULL)
2285 goto done;
William M. Brack38c4b332005-07-25 18:39:34 +00002286 if (base[0] != '.') {
2287 ret = xmlParseURIReference (bas, (const char *) base);
2288 if (ret != 0)
2289 goto done; /* Error in base, return NULL */
2290 } else
2291 bas->path = (char *)xmlStrdup(base);
William M. Brackf7789b12004-06-07 08:57:27 +00002292
2293 /*
2294 * If the scheme / server on the URI differs from the base,
2295 * just return the URI
2296 */
2297 if ((ref->scheme != NULL) &&
Daniel Veillard0f7b3312005-09-15 14:15:20 +00002298 ((bas->scheme == NULL) ||
2299 (xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) ||
2300 (xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)))) {
William M. Brackf7789b12004-06-07 08:57:27 +00002301 val = xmlStrdup (URI);
2302 goto done;
2303 }
Daniel Veillard0f7b3312005-09-15 14:15:20 +00002304 if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) {
2305 val = xmlStrdup(BAD_CAST "");
2306 goto done;
2307 }
2308 if (bas->path == NULL) {
2309 val = xmlStrdup((xmlChar *)ref->path);
2310 goto done;
2311 }
2312 if (ref->path == NULL) {
2313 ref->path = (char *) "/";
2314 remove_path = 1;
2315 }
William M. Brackf7789b12004-06-07 08:57:27 +00002316
2317 /*
2318 * At this point (at last!) we can compare the two paths
2319 *
William M. Brack820d5ed2005-09-14 05:24:27 +00002320 * First we take care of the special case where either of the
2321 * two path components may be missing (bug 316224)
William M. Brackf7789b12004-06-07 08:57:27 +00002322 */
William M. Brack820d5ed2005-09-14 05:24:27 +00002323 if (bas->path == NULL) {
2324 if (ref->path != NULL) {
Daniel Veillard0f7b3312005-09-15 14:15:20 +00002325 uptr = (xmlChar *) ref->path;
William M. Brack820d5ed2005-09-14 05:24:27 +00002326 if (*uptr == '/')
2327 uptr++;
William M. Brack50420192007-07-20 01:09:08 +00002328 /* exception characters from xmlSaveUri */
2329 val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
William M. Brack820d5ed2005-09-14 05:24:27 +00002330 }
2331 goto done;
2332 }
William M. Brackf7789b12004-06-07 08:57:27 +00002333 bptr = (xmlChar *)bas->path;
William M. Brack820d5ed2005-09-14 05:24:27 +00002334 if (ref->path == NULL) {
2335 for (ix = 0; bptr[ix] != 0; ix++) {
William M. Brackf7789b12004-06-07 08:57:27 +00002336 if (bptr[ix] == '/')
2337 nbslash++;
2338 }
William M. Brack820d5ed2005-09-14 05:24:27 +00002339 uptr = NULL;
2340 len = 1; /* this is for a string terminator only */
2341 } else {
2342 /*
2343 * Next we compare the two strings and find where they first differ
2344 */
2345 if ((ref->path[pos] == '.') && (ref->path[pos+1] == '/'))
2346 pos += 2;
2347 if ((*bptr == '.') && (bptr[1] == '/'))
2348 bptr += 2;
2349 else if ((*bptr == '/') && (ref->path[pos] != '/'))
2350 bptr++;
2351 while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0))
2352 pos++;
William M. Brackf7789b12004-06-07 08:57:27 +00002353
William M. Brack820d5ed2005-09-14 05:24:27 +00002354 if (bptr[pos] == ref->path[pos]) {
Daniel Veillard0f7b3312005-09-15 14:15:20 +00002355 val = xmlStrdup(BAD_CAST "");
William M. Brack820d5ed2005-09-14 05:24:27 +00002356 goto done; /* (I can't imagine why anyone would do this) */
2357 }
2358
2359 /*
2360 * In URI, "back up" to the last '/' encountered. This will be the
2361 * beginning of the "unique" suffix of URI
2362 */
2363 ix = pos;
2364 if ((ref->path[ix] == '/') && (ix > 0))
2365 ix--;
Daniel Veillard0f7b3312005-09-15 14:15:20 +00002366 else if ((ref->path[ix] == 0) && (ix > 1) && (ref->path[ix - 1] == '/'))
2367 ix -= 2;
William M. Brack820d5ed2005-09-14 05:24:27 +00002368 for (; ix > 0; ix--) {
2369 if (ref->path[ix] == '/')
2370 break;
2371 }
2372 if (ix == 0) {
2373 uptr = (xmlChar *)ref->path;
2374 } else {
2375 ix++;
2376 uptr = (xmlChar *)&ref->path[ix];
2377 }
2378
2379 /*
2380 * In base, count the number of '/' from the differing point
2381 */
2382 if (bptr[pos] != ref->path[pos]) {/* check for trivial URI == base */
2383 for (; bptr[ix] != 0; ix++) {
2384 if (bptr[ix] == '/')
2385 nbslash++;
2386 }
2387 }
2388 len = xmlStrlen (uptr) + 1;
2389 }
2390
William M. Brackf7789b12004-06-07 08:57:27 +00002391 if (nbslash == 0) {
William M. Brack820d5ed2005-09-14 05:24:27 +00002392 if (uptr != NULL)
William M. Brack50420192007-07-20 01:09:08 +00002393 /* exception characters from xmlSaveUri */
2394 val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
William M. Brackf7789b12004-06-07 08:57:27 +00002395 goto done;
2396 }
William M. Brackf7789b12004-06-07 08:57:27 +00002397
2398 /*
2399 * Allocate just enough space for the returned string -
2400 * length of the remainder of the URI, plus enough space
2401 * for the "../" groups, plus one for the terminator
2402 */
William M. Brack820d5ed2005-09-14 05:24:27 +00002403 val = (xmlChar *) xmlMalloc (len + 3 * nbslash);
William M. Brackf7789b12004-06-07 08:57:27 +00002404 if (val == NULL) {
William M. Brack42331a92004-07-29 07:07:16 +00002405 xmlGenericError(xmlGenericErrorContext,
2406 "xmlBuildRelativeURI: out of memory\n");
William M. Brackf7789b12004-06-07 08:57:27 +00002407 goto done;
2408 }
2409 vptr = val;
2410 /*
2411 * Put in as many "../" as needed
2412 */
2413 for (; nbslash>0; nbslash--) {
2414 *vptr++ = '.';
2415 *vptr++ = '.';
2416 *vptr++ = '/';
2417 }
2418 /*
2419 * Finish up with the end of the URI
2420 */
Daniel Veillard0f7b3312005-09-15 14:15:20 +00002421 if (uptr != NULL) {
2422 if ((vptr > val) && (len > 0) &&
2423 (uptr[0] == '/') && (vptr[-1] == '/')) {
2424 memcpy (vptr, uptr + 1, len - 1);
2425 vptr[len - 2] = 0;
2426 } else {
2427 memcpy (vptr, uptr, len);
2428 vptr[len - 1] = 0;
2429 }
2430 } else {
William M. Brack820d5ed2005-09-14 05:24:27 +00002431 vptr[len - 1] = 0;
Daniel Veillard0f7b3312005-09-15 14:15:20 +00002432 }
William M. Brackf7789b12004-06-07 08:57:27 +00002433
William M. Brack50420192007-07-20 01:09:08 +00002434 /* escape the freshly-built path */
2435 vptr = val;
2436 /* exception characters from xmlSaveUri */
2437 val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,");
2438 xmlFree(vptr);
2439
Daniel Veillard0f7b3312005-09-15 14:15:20 +00002440done:
William M. Brackf7789b12004-06-07 08:57:27 +00002441 /*
2442 * Free the working variables
2443 */
Daniel Veillard0f7b3312005-09-15 14:15:20 +00002444 if (remove_path != 0)
2445 ref->path = NULL;
William M. Brackf7789b12004-06-07 08:57:27 +00002446 if (ref != NULL)
2447 xmlFreeURI (ref);
2448 if (bas != NULL)
2449 xmlFreeURI (bas);
2450
2451 return val;
2452}
2453
2454/**
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002455 * xmlCanonicPath:
2456 * @path: the resource locator in a filesystem notation
2457 *
2458 * Constructs a canonic path from the specified path.
2459 *
2460 * Returns a new canonic path, or a duplicate of the path parameter if the
2461 * construction fails. The caller is responsible for freeing the memory occupied
2462 * by the returned string. If there is insufficient memory available, or the
2463 * argument is NULL, the function returns NULL.
2464 */
2465#define IS_WINDOWS_PATH(p) \
2466 ((p != NULL) && \
2467 (((p[0] >= 'a') && (p[0] <= 'z')) || \
2468 ((p[0] >= 'A') && (p[0] <= 'Z'))) && \
2469 (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))
Daniel Veillardb8efdda2006-10-10 12:37:14 +00002470xmlChar *
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002471xmlCanonicPath(const xmlChar *path)
2472{
William M. Brack22242272007-01-27 07:59:37 +00002473/*
2474 * For Windows implementations, additional work needs to be done to
2475 * replace backslashes in pathnames with "forward slashes"
2476 */
Daniel Veillardc64b8e92003-02-24 11:47:13 +00002477#if defined(_WIN32) && !defined(__CYGWIN__)
Igor Zlatkovicce076162003-02-23 13:39:39 +00002478 int len = 0;
2479 int i = 0;
Igor Zlatkovicce076162003-02-23 13:39:39 +00002480 xmlChar *p = NULL;
Daniel Veillardc64b8e92003-02-24 11:47:13 +00002481#endif
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002482 xmlURIPtr uri;
Daniel Veillard336a8e12005-08-07 10:46:19 +00002483 xmlChar *ret;
2484 const xmlChar *absuri;
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002485
2486 if (path == NULL)
2487 return(NULL);
Daniel Veillard69f8a132008-02-05 08:37:56 +00002488
2489 /* sanitize filename starting with // so it can be used as URI */
2490 if ((path[0] == '/') && (path[1] == '/') && (path[2] != '/'))
2491 path++;
2492
Daniel Veillardc64b8e92003-02-24 11:47:13 +00002493 if ((uri = xmlParseURI((const char *) path)) != NULL) {
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002494 xmlFreeURI(uri);
2495 return xmlStrdup(path);
2496 }
2497
William M. Brack22242272007-01-27 07:59:37 +00002498 /* Check if this is an "absolute uri" */
Daniel Veillard336a8e12005-08-07 10:46:19 +00002499 absuri = xmlStrstr(path, BAD_CAST "://");
2500 if (absuri != NULL) {
2501 int l, j;
2502 unsigned char c;
2503 xmlChar *escURI;
2504
2505 /*
2506 * this looks like an URI where some parts have not been
William M. Brack22242272007-01-27 07:59:37 +00002507 * escaped leading to a parsing problem. Check that the first
Daniel Veillard336a8e12005-08-07 10:46:19 +00002508 * part matches a protocol.
2509 */
2510 l = absuri - path;
William M. Brack22242272007-01-27 07:59:37 +00002511 /* Bypass if first part (part before the '://') is > 20 chars */
Daniel Veillard336a8e12005-08-07 10:46:19 +00002512 if ((l <= 0) || (l > 20))
2513 goto path_processing;
William M. Brack22242272007-01-27 07:59:37 +00002514 /* Bypass if any non-alpha characters are present in first part */
Daniel Veillard336a8e12005-08-07 10:46:19 +00002515 for (j = 0;j < l;j++) {
2516 c = path[j];
2517 if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))))
2518 goto path_processing;
2519 }
2520
William M. Brack22242272007-01-27 07:59:37 +00002521 /* Escape all except the characters specified in the supplied path */
Daniel Veillard336a8e12005-08-07 10:46:19 +00002522 escURI = xmlURIEscapeStr(path, BAD_CAST ":/?_.#&;=");
2523 if (escURI != NULL) {
William M. Brack22242272007-01-27 07:59:37 +00002524 /* Try parsing the escaped path */
Daniel Veillard336a8e12005-08-07 10:46:19 +00002525 uri = xmlParseURI((const char *) escURI);
William M. Brack22242272007-01-27 07:59:37 +00002526 /* If successful, return the escaped string */
Daniel Veillard336a8e12005-08-07 10:46:19 +00002527 if (uri != NULL) {
2528 xmlFreeURI(uri);
2529 return escURI;
2530 }
Daniel Veillard336a8e12005-08-07 10:46:19 +00002531 }
2532 }
2533
2534path_processing:
William M. Brack22242272007-01-27 07:59:37 +00002535/* For Windows implementations, replace backslashes with 'forward slashes' */
Daniel Veillard336a8e12005-08-07 10:46:19 +00002536#if defined(_WIN32) && !defined(__CYGWIN__)
2537 /*
William M. Brack22242272007-01-27 07:59:37 +00002538 * Create a URI structure
Daniel Veillard336a8e12005-08-07 10:46:19 +00002539 */
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002540 uri = xmlCreateURI();
William M. Brack22242272007-01-27 07:59:37 +00002541 if (uri == NULL) { /* Guard against 'out of memory' */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002542 return(NULL);
2543 }
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002544
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002545 len = xmlStrlen(path);
2546 if ((len > 2) && IS_WINDOWS_PATH(path)) {
William M. Brack22242272007-01-27 07:59:37 +00002547 /* make the scheme 'file' */
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002548 uri->scheme = xmlStrdup(BAD_CAST "file");
William M. Brack22242272007-01-27 07:59:37 +00002549 /* allocate space for leading '/' + path + string terminator */
Daniel Veillardb8efdda2006-10-10 12:37:14 +00002550 uri->path = xmlMallocAtomic(len + 2);
2551 if (uri->path == NULL) {
William M. Brack22242272007-01-27 07:59:37 +00002552 xmlFreeURI(uri); /* Guard agains 'out of memory' */
Daniel Veillardb8efdda2006-10-10 12:37:14 +00002553 return(NULL);
2554 }
William M. Brack22242272007-01-27 07:59:37 +00002555 /* Put in leading '/' plus path */
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002556 uri->path[0] = '/';
Igor Zlatkovicce076162003-02-23 13:39:39 +00002557 p = uri->path + 1;
2558 strncpy(p, path, len + 1);
2559 } else {
Daniel Veillardb8efdda2006-10-10 12:37:14 +00002560 uri->path = xmlStrdup(path);
2561 if (uri->path == NULL) {
2562 xmlFreeURI(uri);
2563 return(NULL);
2564 }
Igor Zlatkovicce076162003-02-23 13:39:39 +00002565 p = uri->path;
2566 }
William M. Brack22242272007-01-27 07:59:37 +00002567 /* Now change all occurences of '\' to '/' */
Igor Zlatkovicce076162003-02-23 13:39:39 +00002568 while (*p != '\0') {
2569 if (*p == '\\')
2570 *p = '/';
2571 p++;
2572 }
Daniel Veillard8f3392e2006-02-03 09:45:10 +00002573
Daniel Veillardb8efdda2006-10-10 12:37:14 +00002574 if (uri->scheme == NULL) {
William M. Brack22242272007-01-27 07:59:37 +00002575 ret = xmlStrdup((const xmlChar *) uri->path);
Daniel Veillardb8efdda2006-10-10 12:37:14 +00002576 } else {
2577 ret = xmlSaveUri(uri);
2578 }
Daniel Veillard8f3392e2006-02-03 09:45:10 +00002579
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002580 xmlFreeURI(uri);
Daniel Veillard336a8e12005-08-07 10:46:19 +00002581#else
2582 ret = xmlStrdup((const xmlChar *) path);
2583#endif
Igor Zlatkovicf2238e62003-02-19 14:50:35 +00002584 return(ret);
2585}
Owen Taylor3473f882001-02-23 17:55:21 +00002586
Daniel Veillardb8efdda2006-10-10 12:37:14 +00002587/**
2588 * xmlPathToURI:
2589 * @path: the resource locator in a filesystem notation
2590 *
2591 * Constructs an URI expressing the existing path
2592 *
2593 * Returns a new URI, or a duplicate of the path parameter if the
2594 * construction fails. The caller is responsible for freeing the memory
2595 * occupied by the returned string. If there is insufficient memory available,
2596 * or the argument is NULL, the function returns NULL.
2597 */
2598xmlChar *
2599xmlPathToURI(const xmlChar *path)
2600{
2601 xmlURIPtr uri;
2602 xmlURI temp;
2603 xmlChar *ret, *cal;
2604
2605 if (path == NULL)
2606 return(NULL);
2607
2608 if ((uri = xmlParseURI((const char *) path)) != NULL) {
2609 xmlFreeURI(uri);
2610 return xmlStrdup(path);
2611 }
2612 cal = xmlCanonicPath(path);
2613 if (cal == NULL)
2614 return(NULL);
Daniel Veillard481dcfc2006-11-06 08:54:18 +00002615#if defined(_WIN32) && !defined(__CYGWIN__)
2616 /* xmlCanonicPath can return an URI on Windows (is that the intended behaviour?)
2617 If 'cal' is a valid URI allready then we are done here, as continuing would make
2618 it invalid. */
2619 if ((uri = xmlParseURI((const char *) cal)) != NULL) {
2620 xmlFreeURI(uri);
2621 return cal;
2622 }
2623 /* 'cal' can contain a relative path with backslashes. If that is processed
2624 by xmlSaveURI, they will be escaped and the external entity loader machinery
2625 will fail. So convert them to slashes. Misuse 'ret' for walking. */
2626 ret = cal;
2627 while (*ret != '\0') {
2628 if (*ret == '\\')
2629 *ret = '/';
2630 ret++;
2631 }
2632#endif
Daniel Veillardb8efdda2006-10-10 12:37:14 +00002633 memset(&temp, 0, sizeof(temp));
2634 temp.path = (char *) cal;
2635 ret = xmlSaveUri(&temp);
2636 xmlFree(cal);
2637 return(ret);
2638}
Daniel Veillard5d4644e2005-04-01 13:11:58 +00002639#define bottom_uri
2640#include "elfgcchack.h"