blob: 1ef6687a307a5759fbf98a80ece61aaa05ceed2f [file] [log] [blame]
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001/**
2 * uri.c: set of generic URI related routines
3 *
4 * Reference: RFC 2396
5 *
6 * See Copyright for the status of this software.
7 *
8 * Daniel.Veillard@w3.org
9 */
10
11#ifdef WIN32
12#define INCLUDE_WINSOCK
13#include "win32config.h"
14#else
15#include "config.h"
16#endif
17
18#include <stdio.h>
19#include <string.h>
20
Daniel Veillard361d8452000-04-03 19:48:13 +000021#include <libxml/xmlmemory.h>
22#include <libxml/uri.h>
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000023#include <libxml/xmlerror.h>
Daniel Veillard3dd82e72000-03-20 11:48:04 +000024
Daniel Veillard9e8bfae2000-11-06 16:43:11 +000025/************************************************************************
26 * *
27 * Macros to differenciate various character type *
28 * directly extracted from RFC 2396 *
29 * *
30 ************************************************************************/
31
Daniel Veillard06047432000-04-24 11:33:38 +000032/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +000033 * alpha = lowalpha | upalpha
34 */
35#define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
36
37
Daniel Veillard06047432000-04-24 11:33:38 +000038/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +000039 * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
40 * "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
41 * "u" | "v" | "w" | "x" | "y" | "z"
42 */
43
44#define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
45
Daniel Veillard06047432000-04-24 11:33:38 +000046/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +000047 * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
48 * "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
49 * "U" | "V" | "W" | "X" | "Y" | "Z"
50 */
51#define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
52
Daniel Veillard06047432000-04-24 11:33:38 +000053/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +000054 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
55 */
56
57#define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
58
Daniel Veillard06047432000-04-24 11:33:38 +000059/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +000060 * alphanum = alpha | digit
61 */
62
63#define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
64
Daniel Veillard06047432000-04-24 11:33:38 +000065/*
66 * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
Daniel Veillard3dd82e72000-03-20 11:48:04 +000067 * "a" | "b" | "c" | "d" | "e" | "f"
68 */
69
70#define IS_HEX(x) ((IS_DIGIT(x)) || (((x) >= 'a') && ((x) <= 'f')) || \
71 (((x) >= 'A') && ((x) <= 'F')))
72
Daniel Veillard06047432000-04-24 11:33:38 +000073/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +000074 * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
75 */
76
77#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') || \
78 ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') || \
79 ((x) == '(') || ((x) == ')'))
80
81
Daniel Veillard06047432000-04-24 11:33:38 +000082/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +000083 * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
84 */
85
86#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
87 ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
88 ((x) == '+') || ((x) == '$') || ((x) == ','))
89
Daniel Veillard06047432000-04-24 11:33:38 +000090/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +000091 * unreserved = alphanum | mark
92 */
93
94#define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
95
Daniel Veillard06047432000-04-24 11:33:38 +000096/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +000097 * escaped = "%" hex hex
98 */
99
100#define IS_ESCAPED(p) ((*(p) == '%') && (IS_HEX((p)[1])) && \
101 (IS_HEX((p)[2])))
102
Daniel Veillard06047432000-04-24 11:33:38 +0000103/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000104 * 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
Daniel Veillard06047432000-04-24 11:33:38 +0000112/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000113 * 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
Daniel Veillard06047432000-04-24 11:33:38 +0000120/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000121 * 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
Daniel Veillard06047432000-04-24 11:33:38 +0000130/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000131 * scheme = alpha *( alpha | digit | "+" | "-" | "." )
132 */
133
134#define IS_SCHEME(x) ((IS_ALPHA(x)) || (IS_DIGIT(x)) || \
135 ((x) == '+') || ((x) == '-') || ((x) == '.'))
136
Daniel Veillard06047432000-04-24 11:33:38 +0000137/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000138 * 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
Daniel Veillard06047432000-04-24 11:33:38 +0000147/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000148 * 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
Daniel Veillard06047432000-04-24 11:33:38 +0000156/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000157 * uric = reserved | unreserved | escaped
158 */
159
160#define IS_URIC(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) || \
161 (IS_RESERVED(*(p))))
162
Daniel Veillard06047432000-04-24 11:33:38 +0000163/*
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000164 * Skip to next pointer char, handle escaped sequences
165 */
166
167#define NEXT(p) ((*p == '%')? p += 3 : p++)
168
Daniel Veillard06047432000-04-24 11:33:38 +0000169/*
Daniel Veillard361d8452000-04-03 19:48:13 +0000170 * Productions from the spec.
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000171 *
Daniel Veillard361d8452000-04-03 19:48:13 +0000172 * authority = server | reg_name
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000173 * reg_name = 1*( unreserved | escaped | "$" | "," |
174 * ";" | ":" | "@" | "&" | "=" | "+" )
Daniel Veillard361d8452000-04-03 19:48:13 +0000175 *
176 * path = [ abs_path | opaque_part ]
177 */
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000178
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000179/************************************************************************
180 * *
181 * Generic URI structure functions *
182 * *
183 ************************************************************************/
184
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000185/**
186 * xmlCreateURI:
187 *
188 * Simply creates an empty xmlURI
189 *
190 * Returns the new structure or NULL in case of error
191 */
192xmlURIPtr
193xmlCreateURI(void) {
194 xmlURIPtr ret;
195
196 ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI));
197 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000198 xmlGenericError(xmlGenericErrorContext,
199 "xmlCreateURI: out of memory\n");
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000200 return(NULL);
201 }
202 memset(ret, 0, sizeof(xmlURI));
203 return(ret);
204}
205
206/**
Daniel Veillardec303412000-03-24 13:41:54 +0000207 * xmlSaveUri:
208 * @uri: pointer to an xmlURI
209 *
210 * Save the URI as an escaped string
211 *
212 * Returns a new string (to be deallocated by caller)
213 */
214xmlChar *
215xmlSaveUri(xmlURIPtr uri) {
216 xmlChar *ret = NULL;
217 const char *p;
218 int len;
219 int max;
220
221 if (uri == NULL) return(NULL);
222
223
224 max = 80;
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000225 ret = (xmlChar *) xmlMalloc((max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000226 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000227 xmlGenericError(xmlGenericErrorContext,
228 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000229 return(NULL);
230 }
231 len = 0;
232
233 if (uri->scheme != NULL) {
234 p = uri->scheme;
235 while (*p != 0) {
236 if (len >= max) {
237 max *= 2;
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000238 ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000239 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000240 xmlGenericError(xmlGenericErrorContext,
241 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000242 return(NULL);
243 }
244 }
245 ret[len++] = *p++;
246 }
247 if (len >= max) {
248 max *= 2;
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000249 ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000250 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000251 xmlGenericError(xmlGenericErrorContext,
252 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000253 return(NULL);
254 }
255 }
256 ret[len++] = ':';
257 }
258 if (uri->opaque != NULL) {
259 p = uri->opaque;
260 while (*p != 0) {
261 if (len + 3 >= max) {
262 max *= 2;
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000263 ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000264 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000265 xmlGenericError(xmlGenericErrorContext,
266 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000267 return(NULL);
268 }
269 }
270 if ((IS_UNRESERVED(*(p))) ||
271 ((*(p) == ';')) || ((*(p) == '?')) || ((*(p) == ':')) ||
272 ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||
273 ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ',')))
274 ret[len++] = *p++;
275 else {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000276 int val = *(unsigned char *)p++;
277 int hi = val / 0x10, lo = val % 0x10;
Daniel Veillardec303412000-03-24 13:41:54 +0000278 ret[len++] = '%';
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000279 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
280 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Daniel Veillardec303412000-03-24 13:41:54 +0000281 }
282 }
283 if (len >= max) {
284 max *= 2;
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000285 ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000286 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000287 xmlGenericError(xmlGenericErrorContext,
288 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000289 return(NULL);
290 }
291 }
292 ret[len++] = 0;
293 } else {
Daniel Veillard361d8452000-04-03 19:48:13 +0000294 if (uri->server != NULL) {
295 if (len + 3 >= max) {
296 max *= 2;
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000297 ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
Daniel Veillard361d8452000-04-03 19:48:13 +0000298 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000299 xmlGenericError(xmlGenericErrorContext,
300 "xmlSaveUri: out of memory\n");
Daniel Veillard361d8452000-04-03 19:48:13 +0000301 return(NULL);
302 }
303 }
304 ret[len++] = '/';
305 ret[len++] = '/';
306 if (uri->user != NULL) {
307 p = uri->user;
308 while (*p != 0) {
309 if (len + 3 >= max) {
310 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000311 ret = (xmlChar *) xmlRealloc(ret,
312 (max + 1) * sizeof(xmlChar));
Daniel Veillard361d8452000-04-03 19:48:13 +0000313 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000314 xmlGenericError(xmlGenericErrorContext,
315 "xmlSaveUri: out of memory\n");
Daniel Veillard361d8452000-04-03 19:48:13 +0000316 return(NULL);
317 }
318 }
319 if ((IS_UNRESERVED(*(p))) ||
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000320 ((*(p) == ';')) || ((*(p) == ':')) ||
321 ((*(p) == '&')) || ((*(p) == '=')) ||
322 ((*(p) == '+')) || ((*(p) == '$')) ||
Daniel Veillard361d8452000-04-03 19:48:13 +0000323 ((*(p) == ',')))
324 ret[len++] = *p++;
325 else {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000326 int val = *(unsigned char *)p++;
327 int hi = val / 0x10, lo = val % 0x10;
Daniel Veillard361d8452000-04-03 19:48:13 +0000328 ret[len++] = '%';
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000329 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
330 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Daniel Veillard361d8452000-04-03 19:48:13 +0000331 }
332 }
333 if (len + 3 >= max) {
334 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000335 ret = (xmlChar *) xmlRealloc(ret,
336 (max + 1) * sizeof(xmlChar));
Daniel Veillard361d8452000-04-03 19:48:13 +0000337 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000338 xmlGenericError(xmlGenericErrorContext,
339 "xmlSaveUri: out of memory\n");
Daniel Veillard361d8452000-04-03 19:48:13 +0000340 return(NULL);
341 }
342 }
343 ret[len++] = '@';
344 }
345 p = uri->server;
346 while (*p != 0) {
347 if (len >= max) {
348 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000349 ret = (xmlChar *) xmlRealloc(ret,
350 (max + 1) * sizeof(xmlChar));
Daniel Veillard361d8452000-04-03 19:48:13 +0000351 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000352 xmlGenericError(xmlGenericErrorContext,
353 "xmlSaveUri: out of memory\n");
Daniel Veillard361d8452000-04-03 19:48:13 +0000354 return(NULL);
355 }
356 }
357 ret[len++] = *p++;
358 }
359 if (uri->port > 0) {
360 if (len + 10 >= max) {
361 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000362 ret = (xmlChar *) xmlRealloc(ret,
363 (max + 1) * sizeof(xmlChar));
Daniel Veillard361d8452000-04-03 19:48:13 +0000364 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000365 xmlGenericError(xmlGenericErrorContext,
366 "xmlSaveUri: out of memory\n");
Daniel Veillard361d8452000-04-03 19:48:13 +0000367 return(NULL);
368 }
369 }
370 len += sprintf((char *) &ret[len], ":%d", uri->port);
371 }
372 } else if (uri->authority != NULL) {
Daniel Veillardec303412000-03-24 13:41:54 +0000373 if (len + 3 >= max) {
374 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000375 ret = (xmlChar *) xmlRealloc(ret,
376 (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000377 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000378 xmlGenericError(xmlGenericErrorContext,
379 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000380 return(NULL);
381 }
382 }
383 ret[len++] = '/';
384 ret[len++] = '/';
385 p = uri->authority;
386 while (*p != 0) {
387 if (len + 3 >= max) {
388 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000389 ret = (xmlChar *) xmlRealloc(ret,
390 (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000391 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000392 xmlGenericError(xmlGenericErrorContext,
393 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000394 return(NULL);
395 }
396 }
397 if ((IS_UNRESERVED(*(p))) ||
398 ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
399 ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
400 ((*(p) == '=')) || ((*(p) == '+')))
401 ret[len++] = *p++;
402 else {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000403 int val = *(unsigned char *)p++;
404 int hi = val / 0x10, lo = val % 0x10;
Daniel Veillardec303412000-03-24 13:41:54 +0000405 ret[len++] = '%';
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000406 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
407 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Daniel Veillardec303412000-03-24 13:41:54 +0000408 }
409 }
Daniel Veillard740abf52000-10-02 23:04:54 +0000410 } else if (uri->scheme != NULL) {
411 if (len + 3 >= max) {
412 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000413 ret = (xmlChar *) xmlRealloc(ret,
414 (max + 1) * sizeof(xmlChar));
Daniel Veillard740abf52000-10-02 23:04:54 +0000415 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000416 xmlGenericError(xmlGenericErrorContext,
417 "xmlSaveUri: out of memory\n");
Daniel Veillard740abf52000-10-02 23:04:54 +0000418 return(NULL);
419 }
420 }
421 ret[len++] = '/';
422 ret[len++] = '/';
Daniel Veillardec303412000-03-24 13:41:54 +0000423 }
424 if (uri->path != NULL) {
425 p = uri->path;
426 while (*p != 0) {
427 if (len + 3 >= max) {
428 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000429 ret = (xmlChar *) xmlRealloc(ret,
430 (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000431 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000432 xmlGenericError(xmlGenericErrorContext,
433 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000434 return(NULL);
435 }
436 }
437 if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
438 ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
439 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
440 ((*(p) == ',')))
441 ret[len++] = *p++;
442 else {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000443 int val = *(unsigned char *)p++;
444 int hi = val / 0x10, lo = val % 0x10;
Daniel Veillardec303412000-03-24 13:41:54 +0000445 ret[len++] = '%';
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000446 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
447 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Daniel Veillardec303412000-03-24 13:41:54 +0000448 }
449 }
450 }
451 if (uri->query != NULL) {
452 if (len + 3 >= max) {
453 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000454 ret = (xmlChar *) xmlRealloc(ret,
455 (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000456 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000457 xmlGenericError(xmlGenericErrorContext,
458 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000459 return(NULL);
460 }
461 }
462 ret[len++] = '?';
463 p = uri->query;
464 while (*p != 0) {
465 if (len + 3 >= max) {
466 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000467 ret = (xmlChar *) xmlRealloc(ret,
468 (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000469 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000470 xmlGenericError(xmlGenericErrorContext,
471 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000472 return(NULL);
473 }
474 }
475 if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
476 ret[len++] = *p++;
477 else {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000478 int val = *(unsigned char *)p++;
479 int hi = val / 0x10, lo = val % 0x10;
Daniel Veillardec303412000-03-24 13:41:54 +0000480 ret[len++] = '%';
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000481 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
482 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Daniel Veillardec303412000-03-24 13:41:54 +0000483 }
484 }
485 }
486 if (uri->fragment != NULL) {
487 if (len + 3 >= max) {
488 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000489 ret = (xmlChar *) xmlRealloc(ret,
490 (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000491 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000492 xmlGenericError(xmlGenericErrorContext,
493 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000494 return(NULL);
495 }
496 }
497 ret[len++] = '#';
498 p = uri->fragment;
499 while (*p != 0) {
500 if (len + 3 >= max) {
501 max *= 2;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000502 ret = (xmlChar *) xmlRealloc(ret,
503 (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000504 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000505 xmlGenericError(xmlGenericErrorContext,
506 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000507 return(NULL);
508 }
509 }
510 if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
511 ret[len++] = *p++;
512 else {
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000513 int val = *(unsigned char *)p++;
514 int hi = val / 0x10, lo = val % 0x10;
Daniel Veillardec303412000-03-24 13:41:54 +0000515 ret[len++] = '%';
Daniel Veillard4fb87ee2000-09-19 12:25:59 +0000516 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
517 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Daniel Veillardec303412000-03-24 13:41:54 +0000518 }
519 }
520 }
521 if (len >= max) {
522 max *= 2;
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000523 ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
Daniel Veillardec303412000-03-24 13:41:54 +0000524 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000525 xmlGenericError(xmlGenericErrorContext,
526 "xmlSaveUri: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +0000527 return(NULL);
528 }
529 }
530 ret[len++] = 0;
531 }
532 return(ret);
533}
534
535/**
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000536 * xmlPrintURI:
537 * @stream: a FILE* for the output
538 * @uri: pointer to an xmlURI
539 *
540 * Prints the URI in the stream @steam.
541 */
542void
543xmlPrintURI(FILE *stream, xmlURIPtr uri) {
Daniel Veillardec303412000-03-24 13:41:54 +0000544 xmlChar *out;
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000545
Daniel Veillardec303412000-03-24 13:41:54 +0000546 out = xmlSaveUri(uri);
547 if (out != NULL) {
548 fprintf(stream, "%s", out);
549 xmlFree(out);
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000550 }
551}
552
553/**
554 * xmlCleanURI:
555 * @uri: pointer to an xmlURI
556 *
557 * Make sure the xmlURI struct is free of content
558 */
559void
560xmlCleanURI(xmlURIPtr uri) {
561 if (uri == NULL) return;
562
563 if (uri->scheme != NULL) xmlFree(uri->scheme);
564 uri->scheme = NULL;
565 if (uri->server != NULL) xmlFree(uri->server);
566 uri->server = NULL;
Daniel Veillard361d8452000-04-03 19:48:13 +0000567 if (uri->user != NULL) xmlFree(uri->user);
568 uri->user = NULL;
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000569 if (uri->path != NULL) xmlFree(uri->path);
570 uri->path = NULL;
571 if (uri->fragment != NULL) xmlFree(uri->fragment);
572 uri->fragment = NULL;
573 if (uri->opaque != NULL) xmlFree(uri->opaque);
574 uri->opaque = NULL;
575 if (uri->authority != NULL) xmlFree(uri->authority);
576 uri->authority = NULL;
577 if (uri->query != NULL) xmlFree(uri->query);
578 uri->query = NULL;
579}
580
581/**
582 * xmlFreeURI:
583 * @uri: pointer to an xmlURI
584 *
585 * Free up the xmlURI struct
586 */
587void
588xmlFreeURI(xmlURIPtr uri) {
589 if (uri == NULL) return;
590
591 if (uri->scheme != NULL) xmlFree(uri->scheme);
592 if (uri->server != NULL) xmlFree(uri->server);
Daniel Veillard361d8452000-04-03 19:48:13 +0000593 if (uri->user != NULL) xmlFree(uri->user);
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000594 if (uri->path != NULL) xmlFree(uri->path);
595 if (uri->fragment != NULL) xmlFree(uri->fragment);
596 if (uri->opaque != NULL) xmlFree(uri->opaque);
597 if (uri->authority != NULL) xmlFree(uri->authority);
598 if (uri->query != NULL) xmlFree(uri->query);
599 memset(uri, -1, sizeof(xmlURI));
600 xmlFree(uri);
601}
602
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000603/************************************************************************
604 * *
605 * Helper functions *
606 * *
607 ************************************************************************/
608
609/**
610 * xmlNormalizeURIPath:
611 * @path: pointer to the path string
612 *
613 * applies the 5 normalization steps to a path string
614 * Normalization occurs directly on the string, no new allocation is done
615 *
616 * Returns 0 or an error code
617 */
618int
619xmlNormalizeURIPath(char *path) {
620 int cur, out;
621
622 if (path == NULL)
623 return(-1);
624 cur = 0;
625 out = 0;
626 while ((path[cur] != 0) && (path[cur] != '/')) cur++;
627 if (path[cur] == 0)
628 return(0);
629
630 /* we are positionned at the beginning of the first segment */
631 cur++;
632 out = cur;
633
634 /*
635 * Analyze each segment in sequence.
636 */
637 while (path[cur] != 0) {
638 /*
639 * c) All occurrences of "./", where "." is a complete path segment,
640 * are removed from the buffer string.
641 */
642 if ((path[cur] == '.') && (path[cur + 1] == '/')) {
643 cur += 2;
644 continue;
645 }
646
647 /*
648 * d) If the buffer string ends with "." as a complete path segment,
649 * that "." is removed.
650 */
651 if ((path[cur] == '.') && (path[cur + 1] == 0)) {
652 path[out] = 0;
653 break;
654 }
655
656 /* read the segment */
657 while ((path[cur] != 0) && (path[cur] != '/')) {
658 path[out++] = path[cur++];
659 }
660 path[out++] = path[cur];
661 if (path[cur] != 0) {
662 cur++;
663 }
664 }
665
666 cur = 0;
667 out = 0;
668 while ((path[cur] != 0) && (path[cur] != '/')) cur++;
669 if (path[cur] == 0)
670 return(0);
671 /* we are positionned at the beginning of the first segment */
672 cur++;
673 out = cur;
674 /*
675 * Analyze each segment in sequence.
676 */
677 while (path[cur] != 0) {
678 /*
679 * e) All occurrences of "<segment>/../", where <segment> is a
680 * complete path segment not equal to "..", are removed from the
681 * buffer string. Removal of these path segments is performed
682 * iteratively, removing the leftmost matching pattern on each
683 * iteration, until no matching pattern remains.
684 */
685 if ((cur > 1) && (out > 1) &&
686 (path[cur] == '/') && (path[cur + 1] == '.') &&
687 (path[cur + 2] == '.') && (path[cur + 3] == '/') &&
688 ((path[out] != '.') || (path[out - 1] != '.') ||
689 (path[out - 2] != '/'))) {
690 cur += 3;
691 out --;
692 while ((out > 0) && (path[out] != '/')) { out --; }
693 path[out] = 0;
694 continue;
695 }
696
697 /*
698 * f) If the buffer string ends with "<segment>/..", where <segment>
699 * is a complete path segment not equal to "..", that
700 * "<segment>/.." is removed.
701 */
702 if ((path[cur] == '/') && (path[cur + 1] == '.') &&
703 (path[cur + 2] == '.') && (path[cur + 3] == 0) &&
704 ((path[out] != '.') || (path[out - 1] != '.') ||
705 (path[out - 2] != '/'))) {
706 cur += 4;
707 out --;
708 while ((out > 0) && (path[out - 1] != '/')) { out --; }
709 path[out] = 0;
710 continue;
711 }
712
713 path[out++] = path[cur++]; /* / or 0 */
714 }
715 path[out] = 0;
716
717 /*
718 * g) If the resulting buffer string still begins with one or more
719 * complete path segments of "..", then the reference is
720 * considered to be in error. Implementations may handle this
721 * error by retaining these components in the resolved path (i.e.,
722 * treating them as part of the final URI), by removing them from
723 * the resolved path (i.e., discarding relative levels above the
724 * root), or by avoiding traversal of the reference.
725 *
726 * We discard them from the final path.
727 */
728 cur = 0;
729 while ((path[cur] == '/') && (path[cur + 1] == '.') &&
730 (path[cur + 2] == '.'))
731 cur += 3;
732 if (cur != 0) {
733 out = 0;
734 while (path[cur] != 0) path[out++] = path[cur++];
735 path[out] = 0;
736 }
737 return(0);
738}
739
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000740/**
Daniel Veillard361d8452000-04-03 19:48:13 +0000741 * xmlURIUnescapeString:
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000742 * @str: the string to unescape
743 * @len: the lenght in bytes to unescape (or <= 0 to indicate full string)
744 * @target: optionnal destination buffer
745 *
746 * Unescaping routine, does not do validity checks !
Daniel Veillardec303412000-03-24 13:41:54 +0000747 * Output is direct unsigned char translation of %XX values (no encoding)
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000748 *
749 * Returns an copy of the string, but unescaped
750 */
751char *
Daniel Veillard361d8452000-04-03 19:48:13 +0000752xmlURIUnescapeString(const char *str, int len, char *target) {
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000753 char *ret, *out;
754 const char *in;
755
756 if (str == NULL)
757 return(NULL);
758 if (len <= 0) len = strlen(str);
759 if (len <= 0) return(NULL);
760
761 if (target == NULL) {
762 ret = (char *) xmlMalloc(len + 1);
763 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000764 xmlGenericError(xmlGenericErrorContext,
765 "xmlURIUnescapeString: out of memory\n");
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000766 return(NULL);
767 }
768 } else
769 ret = target;
770 in = str;
771 out = ret;
772 while(len > 0) {
773 if (*in == '%') {
774 in++;
775 if ((*in >= '0') && (*in <= '9'))
776 *out = (*in - '0');
777 else if ((*in >= 'a') && (*in <= 'f'))
778 *out = (*in - 'a') + 10;
779 else if ((*in >= 'A') && (*in <= 'F'))
780 *out = (*in - 'A') + 10;
781 in++;
782 if ((*in >= '0') && (*in <= '9'))
783 *out = *out * 16 + (*in - '0');
784 else if ((*in >= 'a') && (*in <= 'f'))
785 *out = *out * 16 + (*in - 'a') + 10;
786 else if ((*in >= 'A') && (*in <= 'F'))
787 *out = *out * 16 + (*in - 'A') + 10;
788 in++;
789 len -= 3;
Daniel Veillardec303412000-03-24 13:41:54 +0000790 out++;
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000791 } else {
792 *out++ = *in++;
793 len--;
794 }
795 }
796 *out = 0;
797 return(ret);
798}
799
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000800/**
801 * xmlURIEscape:
802 * @str: the string of the URI to escape
803 *
804 * Escaping routine, does not do validity checks !
805 * It will try to escape the chars needing this, but this is heuristic
806 * based it's impossible to be sure.
807 *
808 * Returns an copy of the string, but escaped
809 */
810xmlChar *
811xmlURIEscape(const xmlChar *str) {
812 xmlChar *ret;
813 const xmlChar *in;
814 unsigned int len, out;
815
816 if (str == NULL)
817 return(NULL);
818 len = xmlStrlen(str);
819 if (len <= 0) return(NULL);
820
821 len += 20;
822 ret = (xmlChar *) xmlMalloc(len);
823 if (ret == NULL) {
824 xmlGenericError(xmlGenericErrorContext,
825 "xmlURIEscape: out of memory\n");
826 return(NULL);
827 }
828 in = (const xmlChar *) str;
829 out = 0;
830 while(*in != 0) {
831 if (len - out <= 3) {
832 len += 20;
833 ret = (xmlChar *) xmlRealloc(ret, len);
834 if (ret == NULL) {
835 xmlGenericError(xmlGenericErrorContext,
836 "xmlURIEscape: out of memory\n");
837 return(NULL);
838 }
839 }
840 if ((!IS_UNRESERVED(*in)) && (*in != ':') && (*in != '/') &&
841 (*in != '?') && (*in != '#')) {
842 unsigned char val;
843 ret[out++] = '%';
844 val = *in >> 4;
845 if (val <= 9)
846 ret[out++] = '0' + val;
847 else
848 ret[out++] = 'A' + val - 0xA;
849 val = *in & 0xF;
850 if (val <= 9)
851 ret[out++] = '0' + val;
852 else
853 ret[out++] = 'A' + val - 0xA;
854 in++;
855 } else {
856 ret[out++] = *in++;
857 }
858 }
859 ret[out] = 0;
860 return(ret);
861}
862
863/************************************************************************
864 * *
865 * Escaped URI parsing *
866 * *
867 ************************************************************************/
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000868
869/**
870 * xmlParseURIFragment:
871 * @uri: pointer to an URI structure
872 * @str: pointer to the string to analyze
873 *
874 * Parse an URI fragment string and fills in the appropriate fields
875 * of the @uri structure.
876 *
877 * fragment = *uric
878 *
879 * Returns 0 or the error code
880 */
881int
882xmlParseURIFragment(xmlURIPtr uri, const char **str) {
883 const char *cur = *str;
884
885 if (str == NULL) return(-1);
886
887 while (IS_URIC(cur)) NEXT(cur);
888 if (uri != NULL) {
889 if (uri->fragment != NULL) xmlFree(uri->fragment);
Daniel Veillard361d8452000-04-03 19:48:13 +0000890 uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000891 }
892 *str = cur;
893 return(0);
894}
895
896/**
897 * xmlParseURIQuery:
898 * @uri: pointer to an URI structure
899 * @str: pointer to the string to analyze
900 *
901 * Parse the query part of an URI
902 *
903 * query = *uric
904 *
905 * Returns 0 or the error code
906 */
907int
908xmlParseURIQuery(xmlURIPtr uri, const char **str) {
909 const char *cur = *str;
910
911 if (str == NULL) return(-1);
912
913 while (IS_URIC(cur)) NEXT(cur);
914 if (uri != NULL) {
915 if (uri->query != NULL) xmlFree(uri->query);
Daniel Veillard361d8452000-04-03 19:48:13 +0000916 uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000917 }
918 *str = cur;
919 return(0);
920}
921
922/**
923 * xmlParseURIScheme:
924 * @uri: pointer to an URI structure
925 * @str: pointer to the string to analyze
926 *
927 * Parse an URI scheme
928 *
929 * scheme = alpha *( alpha | digit | "+" | "-" | "." )
930 *
931 * Returns 0 or the error code
932 */
933int
934xmlParseURIScheme(xmlURIPtr uri, const char **str) {
935 const char *cur;
936
937 if (str == NULL)
938 return(-1);
939
940 cur = *str;
941 if (!IS_ALPHA(*cur))
942 return(2);
943 cur++;
944 while (IS_SCHEME(*cur)) cur++;
945 if (uri != NULL) {
946 if (uri->scheme != NULL) xmlFree(uri->scheme);
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000947 /* !!! strndup */
948 uri->scheme = xmlURIUnescapeString(*str, cur - *str, NULL);
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000949 }
950 *str = cur;
951 return(0);
952}
953
954/**
955 * xmlParseURIOpaquePart:
956 * @uri: pointer to an URI structure
957 * @str: pointer to the string to analyze
958 *
959 * Parse an URI opaque part
960 *
961 * opaque_part = uric_no_slash *uric
962 *
963 * Returns 0 or the error code
964 */
965int
966xmlParseURIOpaquePart(xmlURIPtr uri, const char **str) {
967 const char *cur;
968
969 if (str == NULL)
970 return(-1);
971
972 cur = *str;
973 if (!IS_URIC_NO_SLASH(cur)) {
974 return(3);
975 }
976 NEXT(cur);
977 while (IS_URIC(cur)) NEXT(cur);
978 if (uri != NULL) {
979 if (uri->opaque != NULL) xmlFree(uri->opaque);
Daniel Veillard361d8452000-04-03 19:48:13 +0000980 uri->opaque = xmlURIUnescapeString(*str, cur - *str, NULL);
Daniel Veillard3dd82e72000-03-20 11:48:04 +0000981 }
982 *str = cur;
983 return(0);
984}
985
986/**
Daniel Veillard361d8452000-04-03 19:48:13 +0000987 * xmlParseURIServer:
988 * @uri: pointer to an URI structure
989 * @str: pointer to the string to analyze
990 *
991 * Parse a server subpart of an URI, it's a finer grain analysis
992 * of the authority part.
993 *
994 * server = [ [ userinfo "@" ] hostport ]
995 * userinfo = *( unreserved | escaped |
996 * ";" | ":" | "&" | "=" | "+" | "$" | "," )
997 * hostport = host [ ":" port ]
998 * host = hostname | IPv4address
999 * hostname = *( domainlabel "." ) toplabel [ "." ]
1000 * domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
1001 * toplabel = alpha | alpha *( alphanum | "-" ) alphanum
1002 * IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
1003 * port = *digit
1004 *
1005 * Returns 0 or the error code
1006 */
1007int
1008xmlParseURIServer(xmlURIPtr uri, const char **str) {
1009 const char *cur;
1010 const char *host, *tmp;
1011
1012 if (str == NULL)
1013 return(-1);
1014
1015 cur = *str;
1016
1017 /*
1018 * is there an userinfo ?
1019 */
1020 while (IS_USERINFO(cur)) NEXT(cur);
1021 if (*cur == '@') {
1022 if (uri != NULL) {
1023 if (uri->user != NULL) xmlFree(uri->user);
1024 uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
1025 }
1026 cur++;
1027 } else {
1028 if (uri != NULL) {
1029 if (uri->user != NULL) xmlFree(uri->user);
1030 uri->user = NULL;
1031 }
1032 cur = *str;
1033 }
1034 /*
Daniel Veillard740abf52000-10-02 23:04:54 +00001035 * This can be empty in the case where there is no server
1036 */
1037 host = cur;
1038 if (*cur == '/') {
1039 if (uri != NULL) {
1040 if (uri->authority != NULL) xmlFree(uri->authority);
1041 uri->authority = NULL;
1042 if (uri->server != NULL) xmlFree(uri->server);
1043 uri->server = NULL;
1044 uri->port = 0;
1045 }
1046 return(0);
1047 }
1048 /*
Daniel Veillard361d8452000-04-03 19:48:13 +00001049 * host part of hostport can derive either an IPV4 address
1050 * or an unresolved name. Check the IP first, it easier to detect
1051 * errors if wrong one
1052 */
Daniel Veillard361d8452000-04-03 19:48:13 +00001053 if (IS_DIGIT(*cur)) {
1054 while(IS_DIGIT(*cur)) cur++;
1055 if (*cur != '.')
1056 goto host_name;
1057 cur++;
1058 if (!IS_DIGIT(*cur))
1059 goto host_name;
1060 while(IS_DIGIT(*cur)) cur++;
1061 if (*cur != '.')
1062 goto host_name;
1063 cur++;
1064 if (!IS_DIGIT(*cur))
1065 goto host_name;
1066 while(IS_DIGIT(*cur)) cur++;
1067 if (*cur != '.')
1068 goto host_name;
1069 cur++;
1070 if (!IS_DIGIT(*cur))
1071 goto host_name;
1072 while(IS_DIGIT(*cur)) cur++;
1073 if (uri != NULL) {
1074 if (uri->authority != NULL) xmlFree(uri->authority);
1075 uri->authority = NULL;
1076 if (uri->server != NULL) xmlFree(uri->server);
1077 uri->server = xmlURIUnescapeString(host, cur - host, NULL);
1078 }
1079 goto host_done;
1080 }
1081host_name:
1082 /*
1083 * the hostname production as-is is a parser nightmare.
1084 * simplify it to
1085 * hostname = *( domainlabel "." ) domainlabel [ "." ]
1086 * and just make sure the last label starts with a non numeric char.
1087 */
1088 if (!IS_ALPHANUM(*cur))
1089 return(6);
1090 while (IS_ALPHANUM(*cur)) {
1091 while ((IS_ALPHANUM(*cur)) || (*cur == '-')) cur++;
1092 if (*cur == '.')
1093 cur++;
1094 }
1095 tmp = cur;
1096 tmp--;
1097 while (IS_ALPHANUM(*tmp) && (*tmp != '.') && (tmp >= host)) tmp--;
1098 tmp++;
1099 if (!IS_ALPHA(*tmp))
1100 return(7);
1101 if (uri != NULL) {
1102 if (uri->authority != NULL) xmlFree(uri->authority);
1103 uri->authority = NULL;
1104 if (uri->server != NULL) xmlFree(uri->server);
1105 uri->server = xmlURIUnescapeString(host, cur - host, NULL);
1106 }
1107
1108host_done:
1109
1110 /*
1111 * finish by checking for a port presence.
1112 */
1113 if (*cur == ':') {
1114 cur++;
1115 if (IS_DIGIT(*cur)) {
1116 if (uri != NULL)
1117 uri->port = 0;
1118 while (IS_DIGIT(*cur)) {
1119 if (uri != NULL)
1120 uri->port = uri->port * 10 + (*cur - '0');
1121 cur++;
1122 }
1123 }
1124 }
1125 *str = cur;
1126 return(0);
1127}
1128
1129/**
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001130 * xmlParseURIRelSegment:
1131 * @uri: pointer to an URI structure
1132 * @str: pointer to the string to analyze
1133 *
1134 * Parse an URI relative segment
1135 *
1136 * rel_segment = 1*( unreserved | escaped | ";" | "@" | "&" | "=" |
1137 * "+" | "$" | "," )
1138 *
1139 * Returns 0 or the error code
1140 */
1141int
1142xmlParseURIRelSegment(xmlURIPtr uri, const char **str) {
1143 const char *cur;
1144
1145 if (str == NULL)
1146 return(-1);
1147
1148 cur = *str;
1149 if (!IS_SEGMENT(cur)) {
1150 return(3);
1151 }
1152 NEXT(cur);
1153 while (IS_SEGMENT(cur)) NEXT(cur);
1154 if (uri != NULL) {
1155 if (uri->path != NULL) xmlFree(uri->path);
Daniel Veillard361d8452000-04-03 19:48:13 +00001156 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001157 }
1158 *str = cur;
1159 return(0);
1160}
1161
1162/**
1163 * xmlParseURIPathSegments:
1164 * @uri: pointer to an URI structure
1165 * @str: pointer to the string to analyze
1166 * @slash: should we add a leading slash
1167 *
1168 * Parse an URI set of path segments
1169 *
1170 * path_segments = segment *( "/" segment )
1171 * segment = *pchar *( ";" param )
1172 * param = *pchar
1173 *
1174 * Returns 0 or the error code
1175 */
1176int
1177xmlParseURIPathSegments(xmlURIPtr uri, const char **str, int slash) {
1178 const char *cur;
1179
1180 if (str == NULL)
1181 return(-1);
1182
1183 cur = *str;
1184
1185 do {
1186 while (IS_PCHAR(cur)) NEXT(cur);
1187 if (*cur == ';') {
1188 cur++;
1189 while (IS_PCHAR(cur)) NEXT(cur);
1190 }
1191 if (*cur != '/') break;
1192 cur++;
1193 } while (1);
1194 if (uri != NULL) {
1195 int len, len2 = 0;
1196 char *path;
1197
1198 /*
1199 * Concat the set of path segments to the current path
1200 */
1201 len = cur - *str;
1202 if (slash)
1203 len++;
1204
1205 if (uri->path != NULL) {
1206 len2 = strlen(uri->path);
1207 len += len2;
1208 }
1209 path = (char *) xmlMalloc(len + 1);
1210 if (path == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001211 xmlGenericError(xmlGenericErrorContext,
1212 "xmlParseURIPathSegments: out of memory\n");
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001213 *str = cur;
1214 return(-1);
1215 }
1216 if (uri->path != NULL)
1217 memcpy(path, uri->path, len2);
1218 if (slash) {
1219 path[len2] = '/';
1220 len2++;
1221 }
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001222 path[len2] = 0;
1223 if (cur - *str > 0)
1224 xmlURIUnescapeString(*str, cur - *str, &path[len2]);
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001225 if (uri->path != NULL)
1226 xmlFree(uri->path);
1227 uri->path = path;
1228 }
1229 *str = cur;
1230 return(0);
1231}
1232
1233/**
1234 * xmlParseURIAuthority:
1235 * @uri: pointer to an URI structure
1236 * @str: pointer to the string to analyze
1237 *
1238 * Parse the authority part of an URI.
1239 *
1240 * authority = server | reg_name
1241 * server = [ [ userinfo "@" ] hostport ]
1242 * reg_name = 1*( unreserved | escaped | "$" | "," | ";" | ":" |
1243 * "@" | "&" | "=" | "+" )
1244 *
1245 * Note : this is completely ambiguous since reg_name is allowed to
1246 * use the full set of chars in use by server:
1247 *
1248 * 3.2.1. Registry-based Naming Authority
1249 *
1250 * The structure of a registry-based naming authority is specific
1251 * to the URI scheme, but constrained to the allowed characters
1252 * for an authority component.
1253 *
1254 * Returns 0 or the error code
1255 */
1256int
1257xmlParseURIAuthority(xmlURIPtr uri, const char **str) {
1258 const char *cur;
Daniel Veillard361d8452000-04-03 19:48:13 +00001259 int ret;
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001260
1261 if (str == NULL)
1262 return(-1);
1263
1264 cur = *str;
Daniel Veillard361d8452000-04-03 19:48:13 +00001265
1266 /*
1267 * try first to parse it as a server string.
1268 */
1269 ret = xmlParseURIServer(uri, str);
1270 if (ret == 0)
1271 return(0);
1272
1273 /*
1274 * failed, fallback to reg_name
1275 */
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001276 if (!IS_REG_NAME(cur)) {
1277 return(5);
1278 }
1279 NEXT(cur);
1280 while (IS_REG_NAME(cur)) NEXT(cur);
1281 if (uri != NULL) {
Daniel Veillard361d8452000-04-03 19:48:13 +00001282 if (uri->server != NULL) xmlFree(uri->server);
1283 uri->server = NULL;
1284 if (uri->user != NULL) xmlFree(uri->user);
1285 uri->user = NULL;
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001286 if (uri->authority != NULL) xmlFree(uri->authority);
Daniel Veillard361d8452000-04-03 19:48:13 +00001287 uri->authority = xmlURIUnescapeString(*str, cur - *str, NULL);
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001288 }
1289 *str = cur;
1290 return(0);
1291}
1292
1293/**
1294 * xmlParseURIHierPart:
1295 * @uri: pointer to an URI structure
1296 * @str: pointer to the string to analyze
1297 *
1298 * Parse an URI hirarchical part
1299 *
1300 * hier_part = ( net_path | abs_path ) [ "?" query ]
1301 * abs_path = "/" path_segments
1302 * net_path = "//" authority [ abs_path ]
1303 *
1304 * Returns 0 or the error code
1305 */
1306int
1307xmlParseURIHierPart(xmlURIPtr uri, const char **str) {
1308 int ret;
1309 const char *cur;
1310
1311 if (str == NULL)
1312 return(-1);
1313
1314 cur = *str;
1315
1316 if ((cur[0] == '/') && (cur[1] == '/')) {
1317 cur += 2;
1318 ret = xmlParseURIAuthority(uri, &cur);
1319 if (ret != 0)
1320 return(ret);
1321 if (cur[0] == '/') {
1322 cur++;
1323 ret = xmlParseURIPathSegments(uri, &cur, 1);
1324 }
1325 } else if (cur[0] == '/') {
1326 cur++;
1327 ret = xmlParseURIPathSegments(uri, &cur, 1);
1328 } else {
1329 return(4);
1330 }
1331 if (ret != 0)
1332 return(ret);
1333 if (*cur == '?') {
1334 cur++;
1335 ret = xmlParseURIQuery(uri, &cur);
1336 if (ret != 0)
1337 return(ret);
1338 }
1339 *str = cur;
1340 return(0);
1341}
1342
1343/**
1344 * xmlParseAbsoluteURI:
1345 * @uri: pointer to an URI structure
1346 * @str: pointer to the string to analyze
1347 *
1348 * Parse an URI reference string and fills in the appropriate fields
1349 * of the @uri structure
1350 *
1351 * absoluteURI = scheme ":" ( hier_part | opaque_part )
1352 *
1353 * Returns 0 or the error code
1354 */
1355int
1356xmlParseAbsoluteURI(xmlURIPtr uri, const char **str) {
1357 int ret;
1358
1359 if (str == NULL)
1360 return(-1);
1361
1362 ret = xmlParseURIScheme(uri, str);
1363 if (ret != 0) return(ret);
1364 if (**str != ':')
1365 return(1);
1366 (*str)++;
1367 if (**str == '/')
1368 return(xmlParseURIHierPart(uri, str));
1369 return(xmlParseURIOpaquePart(uri, str));
1370}
1371
1372/**
1373 * xmlParseRelativeURI:
1374 * @uri: pointer to an URI structure
1375 * @str: pointer to the string to analyze
1376 *
1377 * Parse an relative URI string and fills in the appropriate fields
1378 * of the @uri structure
1379 *
1380 * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
1381 * abs_path = "/" path_segments
1382 * net_path = "//" authority [ abs_path ]
1383 * rel_path = rel_segment [ abs_path ]
1384 *
1385 * Returns 0 or the error code
1386 */
1387int
1388xmlParseRelativeURI(xmlURIPtr uri, const char **str) {
1389 int ret = 0;
1390 const char *cur;
1391
1392 if (str == NULL)
1393 return(-1);
1394
1395 cur = *str;
1396 if ((cur[0] == '/') && (cur[1] == '/')) {
1397 cur += 2;
1398 ret = xmlParseURIAuthority(uri, &cur);
1399 if (ret != 0)
1400 return(ret);
1401 if (cur[0] == '/') {
1402 cur++;
1403 ret = xmlParseURIPathSegments(uri, &cur, 1);
1404 }
1405 } else if (cur[0] == '/') {
1406 cur++;
1407 ret = xmlParseURIPathSegments(uri, &cur, 1);
Daniel Veillard98a79162000-09-04 11:15:39 +00001408 } else if (cur[0] != '#' && cur[0] != '?') {
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001409 ret = xmlParseURIRelSegment(uri, &cur);
1410 if (ret != 0)
1411 return(ret);
1412 if (cur[0] == '/') {
1413 cur++;
1414 ret = xmlParseURIPathSegments(uri, &cur, 1);
1415 }
1416 }
1417 if (ret != 0)
1418 return(ret);
1419 if (*cur == '?') {
1420 cur++;
1421 ret = xmlParseURIQuery(uri, &cur);
1422 if (ret != 0)
1423 return(ret);
1424 }
1425 *str = cur;
1426 return(ret);
1427}
1428
1429/**
1430 * xmlParseURIReference:
1431 * @uri: pointer to an URI structure
1432 * @str: the string to analyze
1433 *
1434 * Parse an URI reference string and fills in the appropriate fields
1435 * of the @uri structure
1436 *
1437 * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
1438 *
1439 * Returns 0 or the error code
1440 */
1441int
1442xmlParseURIReference(xmlURIPtr uri, const char *str) {
1443 int ret;
1444 const char *tmp = str;
1445
1446 if (str == NULL)
1447 return(-1);
1448 xmlCleanURI(uri);
1449
1450 /*
1451 * Try first to parse aboslute refs, then fallback to relative if
1452 * it fails.
1453 */
1454 ret = xmlParseAbsoluteURI(uri, &str);
1455 if (ret != 0) {
1456 xmlCleanURI(uri);
1457 str = tmp;
1458 ret = xmlParseRelativeURI(uri, &str);
1459 }
1460 if (ret != 0) {
1461 xmlCleanURI(uri);
1462 return(ret);
1463 }
1464
1465 if (*str == '#') {
1466 str++;
1467 ret = xmlParseURIFragment(uri, &str);
1468 if (ret != 0) return(ret);
1469 }
1470 if (*str != 0) {
1471 xmlCleanURI(uri);
1472 return(1);
1473 }
1474 return(0);
1475}
1476
1477/**
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001478 * xmlParseURI:
1479 * @str: the URI string to analyze
1480 *
1481 * Parse an URI
1482 *
1483 * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
1484 *
1485 * Returns a newly build xmlURIPtr or NULL in case of error
1486 */
1487xmlURIPtr
1488xmlParseURI(const char *str) {
1489 xmlURIPtr uri;
1490 int ret;
1491
1492 if (str == NULL)
1493 return(NULL);
1494 uri = xmlCreateURI();
1495 if (uri != NULL) {
1496 ret = xmlParseURIReference(uri, str);
1497 if (ret) {
1498 xmlFreeURI(uri);
1499 return(NULL);
1500 }
1501 }
1502 return(uri);
1503}
1504
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00001505/************************************************************************
1506 * *
1507 * Public functions *
1508 * *
1509 ************************************************************************/
Daniel Veillardec303412000-03-24 13:41:54 +00001510
1511/**
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001512 * xmlBuildURI:
1513 * @URI: the URI instance found in the document
1514 * @base: the base value
1515 *
1516 * Computes he final URI of the reference done by checking that
1517 * the given URI is valid, and building the final URI using the
1518 * base URI. This is processed according to section 5.2 of the
1519 * RFC 2396
1520 *
1521 * 5.2. Resolving Relative References to Absolute Form
1522 *
Daniel Veillardec303412000-03-24 13:41:54 +00001523 * Returns a new URI string (to be freed by the caller) or NULL in case
1524 * of error.
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001525 */
1526xmlChar *
1527xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
Daniel Veillardec303412000-03-24 13:41:54 +00001528 xmlChar *val = NULL;
Daniel Veillardbd20df72000-10-29 17:53:40 +00001529 int ret, len, index, cur, out;
Daniel Veillardec303412000-03-24 13:41:54 +00001530 xmlURIPtr ref = NULL;
1531 xmlURIPtr bas = NULL;
1532 xmlURIPtr res = NULL;
1533
Daniel Veillardec303412000-03-24 13:41:54 +00001534 /*
1535 * 1) The URI reference is parsed into the potential four components and
1536 * fragment identifier, as described in Section 4.3.
Daniel Veillard90e11312000-09-05 10:42:32 +00001537 *
1538 * NOTE that a completely empty URI is treated by modern browsers
1539 * as a reference to "." rather than as a synonym for the current
1540 * URI. Should we do that here?
Daniel Veillardec303412000-03-24 13:41:54 +00001541 */
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001542 if (URI == NULL)
1543 ret = -1;
1544 else {
Daniel Veillardbd20df72000-10-29 17:53:40 +00001545 if (*URI) {
1546 ref = xmlCreateURI();
1547 if (ref == NULL)
1548 goto done;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001549 ret = xmlParseURIReference(ref, (const char *) URI);
Daniel Veillardbd20df72000-10-29 17:53:40 +00001550 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001551 else
Daniel Veillardbd20df72000-10-29 17:53:40 +00001552 ret = 0;
Daniel Veillard98a79162000-09-04 11:15:39 +00001553 }
Daniel Veillardbd20df72000-10-29 17:53:40 +00001554 if (ret != 0)
1555 goto done;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001556 if (base == NULL)
Daniel Veillardbd20df72000-10-29 17:53:40 +00001557 ret = -1;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001558 else {
1559 bas = xmlCreateURI();
1560 if (bas == NULL)
1561 goto done;
Daniel Veillardbd20df72000-10-29 17:53:40 +00001562 ret = xmlParseURIReference(bas, (const char *) base);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001563 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001564 if (ret != 0) {
Daniel Veillardbd20df72000-10-29 17:53:40 +00001565 if (ref)
1566 val = xmlSaveUri(ref);
1567 goto done;
1568 }
1569 if (ref == NULL) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001570 /*
1571 * the base fragment must be ignored
1572 */
1573 if (bas->fragment != NULL) {
1574 xmlFree(bas->fragment);
1575 bas->fragment = NULL;
1576 }
1577 val = xmlSaveUri(bas);
Daniel Veillardec303412000-03-24 13:41:54 +00001578 goto done;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001579 }
Daniel Veillardec303412000-03-24 13:41:54 +00001580
1581 /*
1582 * 2) If the path component is empty and the scheme, authority, and
1583 * query components are undefined, then it is a reference to the
Daniel Veillard90e11312000-09-05 10:42:32 +00001584 * current document and we are done. Otherwise, the reference URI's
1585 * query and fragment components are defined as found (or not found)
1586 * within the URI reference and not inherited from the base URI.
Daniel Veillard98a79162000-09-04 11:15:39 +00001587 *
Daniel Veillard90e11312000-09-05 10:42:32 +00001588 * NOTE that in modern browsers, the parsing differs from the above
1589 * in the following aspect: the query component is allowed to be
1590 * defined while still treating this as a reference to the current
1591 * document.
Daniel Veillardec303412000-03-24 13:41:54 +00001592 */
1593 res = xmlCreateURI();
1594 if (res == NULL)
1595 goto done;
1596 if ((ref->scheme == NULL) && (ref->path == NULL) &&
Daniel Veillard90e11312000-09-05 10:42:32 +00001597 ((ref->authority == NULL) && (ref->server == NULL))) {
1598 if (bas->scheme != NULL)
1599 res->scheme = xmlMemStrdup(bas->scheme);
1600 if (bas->authority != NULL)
1601 res->authority = xmlMemStrdup(bas->authority);
1602 else if (bas->server != NULL) {
1603 res->server = xmlMemStrdup(bas->server);
1604 if (bas->user != NULL)
1605 res->user = xmlMemStrdup(bas->user);
1606 res->port = bas->port;
1607 }
1608 if (bas->path != NULL)
1609 res->path = xmlMemStrdup(bas->path);
1610 if (ref->query != NULL)
1611 res->query = xmlMemStrdup(ref->query);
1612 else if (bas->query != NULL)
1613 res->query = xmlMemStrdup(bas->query);
1614 if (ref->fragment != NULL)
1615 res->fragment = xmlMemStrdup(ref->fragment);
1616 goto step_7;
Daniel Veillardec303412000-03-24 13:41:54 +00001617 }
Daniel Veillard98a79162000-09-04 11:15:39 +00001618
Daniel Veillard90e11312000-09-05 10:42:32 +00001619 if (ref->query != NULL)
1620 res->query = xmlMemStrdup(ref->query);
1621 if (ref->fragment != NULL)
1622 res->fragment = xmlMemStrdup(ref->fragment);
Daniel Veillardec303412000-03-24 13:41:54 +00001623
1624 /*
1625 * 3) If the scheme component is defined, indicating that the reference
1626 * starts with a scheme name, then the reference is interpreted as an
1627 * absolute URI and we are done. Otherwise, the reference URI's
1628 * scheme is inherited from the base URI's scheme component.
1629 */
1630 if (ref->scheme != NULL) {
1631 val = xmlSaveUri(ref);
1632 goto done;
1633 }
Daniel Veillardbe803962000-06-28 23:40:59 +00001634 if (bas->scheme != NULL)
1635 res->scheme = xmlMemStrdup(bas->scheme);
Daniel Veillardec303412000-03-24 13:41:54 +00001636
1637 /*
1638 * 4) If the authority component is defined, then the reference is a
1639 * network-path and we skip to step 7. Otherwise, the reference
1640 * URI's authority is inherited from the base URI's authority
1641 * component, which will also be undefined if the URI scheme does not
1642 * use an authority component.
1643 */
Daniel Veillard361d8452000-04-03 19:48:13 +00001644 if ((ref->authority != NULL) || (ref->server != NULL)) {
1645 if (ref->authority != NULL)
1646 res->authority = xmlMemStrdup(ref->authority);
1647 else {
1648 res->server = xmlMemStrdup(ref->server);
1649 if (ref->user != NULL)
1650 res->user = xmlMemStrdup(ref->user);
1651 res->port = ref->port;
1652 }
Daniel Veillardec303412000-03-24 13:41:54 +00001653 if (ref->path != NULL)
1654 res->path = xmlMemStrdup(ref->path);
Daniel Veillardec303412000-03-24 13:41:54 +00001655 goto step_7;
1656 }
1657 if (bas->authority != NULL)
1658 res->authority = xmlMemStrdup(bas->authority);
Daniel Veillard361d8452000-04-03 19:48:13 +00001659 else if (bas->server != NULL) {
1660 res->server = xmlMemStrdup(bas->server);
1661 if (bas->user != NULL)
1662 res->user = xmlMemStrdup(bas->user);
1663 res->port = bas->port;
1664 }
Daniel Veillardec303412000-03-24 13:41:54 +00001665
1666 /*
1667 * 5) If the path component begins with a slash character ("/"), then
1668 * the reference is an absolute-path and we skip to step 7.
1669 */
Daniel Veillard90e11312000-09-05 10:42:32 +00001670 if ((ref->path != NULL) && (ref->path[0] == '/')) {
Daniel Veillardec303412000-03-24 13:41:54 +00001671 res->path = xmlMemStrdup(ref->path);
Daniel Veillardec303412000-03-24 13:41:54 +00001672 goto step_7;
1673 }
1674
1675
1676 /*
1677 * 6) If this step is reached, then we are resolving a relative-path
1678 * reference. The relative path needs to be merged with the base
1679 * URI's path. Although there are many ways to do this, we will
1680 * describe a simple method using a separate string buffer.
1681 *
1682 * Allocate a buffer large enough for the result string.
1683 */
1684 len = 2; /* extra / and 0 */
1685 if (ref->path != NULL)
1686 len += strlen(ref->path);
1687 if (bas->path != NULL)
1688 len += strlen(bas->path);
1689 res->path = (char *) xmlMalloc(len);
1690 if (res->path == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001691 xmlGenericError(xmlGenericErrorContext,
1692 "xmlBuildURI: out of memory\n");
Daniel Veillardec303412000-03-24 13:41:54 +00001693 goto done;
1694 }
1695 res->path[0] = 0;
1696
1697 /*
1698 * a) All but the last segment of the base URI's path component is
1699 * copied to the buffer. In other words, any characters after the
1700 * last (right-most) slash character, if any, are excluded.
1701 */
1702 cur = 0;
1703 out = 0;
1704 if (bas->path != NULL) {
1705 while (bas->path[cur] != 0) {
1706 while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
1707 cur++;
1708 if (bas->path[cur] == 0)
1709 break;
1710
1711 cur++;
1712 while (out < cur) {
1713 res->path[out] = bas->path[out];
1714 out++;
1715 }
1716 }
1717 }
1718 res->path[out] = 0;
1719
1720 /*
1721 * b) The reference's path component is appended to the buffer
1722 * string.
1723 */
Daniel Veillard8ddb5a72000-09-23 10:28:52 +00001724 if (ref->path != NULL && ref->path[0] != 0) {
Daniel Veillardec303412000-03-24 13:41:54 +00001725 index = 0;
Daniel Veillard52402ce2000-08-22 23:36:12 +00001726 /*
1727 * Ensure the path includes a '/'
1728 */
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001729 if ((out == 0) && (bas->server != NULL))
Daniel Veillard52402ce2000-08-22 23:36:12 +00001730 res->path[out++] = '/';
Daniel Veillardec303412000-03-24 13:41:54 +00001731 while (ref->path[index] != 0) {
1732 res->path[out++] = ref->path[index++];
1733 }
1734 }
1735 res->path[out] = 0;
1736
1737 /*
1738 * Steps c) to h) are really path normalization steps
1739 */
1740 xmlNormalizeURIPath(res->path);
1741
1742step_7:
1743
1744 /*
1745 * 7) The resulting URI components, including any inherited from the
1746 * base URI, are recombined to give the absolute form of the URI
1747 * reference.
1748 */
1749 val = xmlSaveUri(res);
1750
1751done:
1752 if (ref != NULL)
1753 xmlFreeURI(ref);
Daniel Veillard39c7d712000-09-10 16:14:55 +00001754 if (bas != NULL)
Daniel Veillardec303412000-03-24 13:41:54 +00001755 xmlFreeURI(bas);
1756 if (res != NULL)
1757 xmlFreeURI(res);
1758 return(val);
Daniel Veillard3dd82e72000-03-20 11:48:04 +00001759}
1760
1761