updated libxml2 to 2.5.10
[TestXSLT.git] / libxml2 / uri.c
1 /**
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.com
9  */
10
11 #define IN_LIBXML
12 #include "libxml.h"
13
14 #include <string.h>
15
16 #include <libxml/xmlmemory.h>
17 #include <libxml/uri.h>
18 #include <libxml/globals.h>
19 #include <libxml/xmlerror.h>
20
21 /************************************************************************
22  *                                                                      *
23  *              Macros to differentiate various character type          *
24  *                      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
49 /*
50  * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
51  */
52
53 #define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
54
55 /*
56  * alphanum = alpha | digit
57  */
58
59 #define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
60
61 /*
62  * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
63  *               "a" | "b" | "c" | "d" | "e" | "f"
64  */
65
66 #define IS_HEX(x) ((IS_DIGIT(x)) || (((x) >= 'a') && ((x) <= 'f')) || \
67             (((x) >= 'A') && ((x) <= 'F')))
68
69 /*
70  * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
71  */
72
73 #define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') ||     \
74     ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') ||    \
75     ((x) == '(') || ((x) == ')'))
76
77
78 /*
79  * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
80  */
81
82 #define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
83         ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
84         ((x) == '+') || ((x) == '$') || ((x) == ','))
85
86 /*
87  * unreserved = alphanum | mark
88  */
89
90 #define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
91
92 /*
93  * escaped = "%" hex hex
94  */
95
96 #define IS_ESCAPED(p) ((*(p) == '%') && (IS_HEX((p)[1])) &&             \
97             (IS_HEX((p)[2])))
98
99 /*
100  * uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
101  *                        "&" | "=" | "+" | "$" | ","
102  */
103 #define IS_URIC_NO_SLASH(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||\
104                 ((*(p) == ';')) || ((*(p) == '?')) || ((*(p) == ':')) ||\
105                 ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||\
106                 ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ',')))
107
108 /*
109  * pchar = unreserved | escaped | ":" | "@" | "&" | "=" | "+" | "$" | ","
110  */
111 #define IS_PCHAR(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||        \
112                 ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||\
113                 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||\
114                 ((*(p) == ',')))
115
116 /*
117  * rel_segment   = 1*( unreserved | escaped |
118  *                 ";" | "@" | "&" | "=" | "+" | "$" | "," )
119  */
120
121 #define IS_SEGMENT(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||      \
122           ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||      \
123           ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||      \
124           ((*(p) == ',')))
125
126 /*
127  * scheme = alpha *( alpha | digit | "+" | "-" | "." )
128  */
129
130 #define IS_SCHEME(x) ((IS_ALPHA(x)) || (IS_DIGIT(x)) ||                 \
131                       ((x) == '+') || ((x) == '-') || ((x) == '.'))
132
133 /*
134  * reg_name = 1*( unreserved | escaped | "$" | "," |
135  *                ";" | ":" | "@" | "&" | "=" | "+" )
136  */
137
138 #define IS_REG_NAME(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||     \
139        ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||         \
140        ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||         \
141        ((*(p) == '=')) || ((*(p) == '+')))
142
143 /*
144  * userinfo = *( unreserved | escaped | ";" | ":" | "&" | "=" |
145  *                      "+" | "$" | "," )
146  */
147 #define IS_USERINFO(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||     \
148        ((*(p) == ';')) || ((*(p) == ':')) || ((*(p) == '&')) ||         \
149        ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||         \
150        ((*(p) == ',')))
151
152 /*
153  * uric = reserved | unreserved | escaped
154  */
155
156 #define IS_URIC(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||         \
157                     (IS_RESERVED(*(p))))
158
159 /*                                                                              
160 * unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
161 */                                                                             
162
163 #define IS_UNWISE(p)                                                    \
164       (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) ||         \
165        ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) ||        \
166        ((*(p) == ']')) || ((*(p) == '`')))  
167
168 /*
169  * Skip to next pointer char, handle escaped sequences
170  */
171
172 #define NEXT(p) ((*p == '%')? p += 3 : p++)
173
174 /*
175  * Productions from the spec.
176  *
177  *    authority     = server | reg_name
178  *    reg_name      = 1*( unreserved | escaped | "$" | "," |
179  *                        ";" | ":" | "@" | "&" | "=" | "+" )
180  *
181  * path          = [ abs_path | opaque_part ]
182  */
183
184 /************************************************************************
185  *                                                                      *
186  *                      Generic URI structure functions                 *
187  *                                                                      *
188  ************************************************************************/
189
190 /**
191  * xmlCreateURI:
192  *
193  * Simply creates an empty xmlURI
194  *
195  * Returns the new structure or NULL in case of error
196  */
197 xmlURIPtr
198 xmlCreateURI(void) {
199     xmlURIPtr ret;
200
201     ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI));
202     if (ret == NULL) {
203         xmlGenericError(xmlGenericErrorContext,
204                 "xmlCreateURI: out of memory\n");
205         return(NULL);
206     }
207     memset(ret, 0, sizeof(xmlURI));
208     return(ret);
209 }
210
211 /**
212  * xmlSaveUri:
213  * @uri:  pointer to an xmlURI
214  *
215  * Save the URI as an escaped string
216  *
217  * Returns a new string (to be deallocated by caller)
218  */
219 xmlChar *
220 xmlSaveUri(xmlURIPtr uri) {
221     xmlChar *ret = NULL;
222     const char *p;
223     int len;
224     int max;
225
226     if (uri == NULL) return(NULL);
227
228
229     max = 80;
230     ret = (xmlChar *) xmlMallocAtomic((max + 1) * sizeof(xmlChar));
231     if (ret == NULL) {
232         xmlGenericError(xmlGenericErrorContext,
233                 "xmlSaveUri: out of memory\n");
234         return(NULL);
235     }
236     len = 0;
237
238     if (uri->scheme != NULL) {
239         p = uri->scheme;
240         while (*p != 0) {
241             if (len >= max) {
242                 max *= 2;
243                 ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
244                 if (ret == NULL) {
245                     xmlGenericError(xmlGenericErrorContext,
246                             "xmlSaveUri: out of memory\n");
247                     return(NULL);
248                 }
249             }
250             ret[len++] = *p++;
251         }
252         if (len >= max) {
253             max *= 2;
254             ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
255             if (ret == NULL) {
256                 xmlGenericError(xmlGenericErrorContext,
257                         "xmlSaveUri: out of memory\n");
258                 return(NULL);
259             }
260         }
261         ret[len++] = ':';
262     }
263     if (uri->opaque != NULL) {
264         p = uri->opaque;
265         while (*p != 0) {
266             if (len + 3 >= max) {
267                 max *= 2;
268                 ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
269                 if (ret == NULL) {
270                     xmlGenericError(xmlGenericErrorContext,
271                             "xmlSaveUri: out of memory\n");
272                     return(NULL);
273                 }
274             }
275             if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
276                 ret[len++] = *p++;
277             else {
278                 int val = *(unsigned char *)p++;
279                 int hi = val / 0x10, lo = val % 0x10;
280                 ret[len++] = '%';
281                 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
282                 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
283             }
284         }
285     } else {
286         if (uri->server != NULL) {
287             if (len + 3 >= max) {
288                 max *= 2;
289                 ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
290                 if (ret == NULL) {
291                     xmlGenericError(xmlGenericErrorContext,
292                             "xmlSaveUri: out of memory\n");
293                     return(NULL);
294                 }
295             }
296             ret[len++] = '/';
297             ret[len++] = '/';
298             if (uri->user != NULL) {
299                 p = uri->user;
300                 while (*p != 0) {
301                     if (len + 3 >= max) {
302                         max *= 2;
303                         ret = (xmlChar *) xmlRealloc(ret,
304                                 (max + 1) * sizeof(xmlChar));
305                         if (ret == NULL) {
306                             xmlGenericError(xmlGenericErrorContext,
307                                     "xmlSaveUri: out of memory\n");
308                             return(NULL);
309                         }
310                     }
311                     if ((IS_UNRESERVED(*(p))) ||
312                         ((*(p) == ';')) || ((*(p) == ':')) ||
313                         ((*(p) == '&')) || ((*(p) == '=')) ||
314                         ((*(p) == '+')) || ((*(p) == '$')) ||
315                         ((*(p) == ',')))
316                         ret[len++] = *p++;
317                     else {
318                         int val = *(unsigned char *)p++;
319                         int hi = val / 0x10, lo = val % 0x10;
320                         ret[len++] = '%';
321                         ret[len++] = hi + (hi > 9? 'A'-10 : '0');
322                         ret[len++] = lo + (lo > 9? 'A'-10 : '0');
323                     }
324                 }
325                 if (len + 3 >= max) {
326                     max *= 2;
327                     ret = (xmlChar *) xmlRealloc(ret,
328                             (max + 1) * sizeof(xmlChar));
329                     if (ret == NULL) {
330                         xmlGenericError(xmlGenericErrorContext,
331                                 "xmlSaveUri: out of memory\n");
332                         return(NULL);
333                     }
334                 }
335                 ret[len++] = '@';
336             }
337             p = uri->server;
338             while (*p != 0) {
339                 if (len >= max) {
340                     max *= 2;
341                     ret = (xmlChar *) xmlRealloc(ret,
342                             (max + 1) * sizeof(xmlChar));
343                     if (ret == NULL) {
344                         xmlGenericError(xmlGenericErrorContext,
345                                 "xmlSaveUri: out of memory\n");
346                         return(NULL);
347                     }
348                 }
349                 ret[len++] = *p++;
350             }
351             if (uri->port > 0) {
352                 if (len + 10 >= max) {
353                     max *= 2;
354                     ret = (xmlChar *) xmlRealloc(ret,
355                             (max + 1) * sizeof(xmlChar));
356                     if (ret == NULL) {
357                         xmlGenericError(xmlGenericErrorContext,
358                                 "xmlSaveUri: out of memory\n");
359                         return(NULL);
360                     }
361                 }
362                 len += snprintf((char *) &ret[len], max - len, ":%d", uri->port);
363             }
364         } else if (uri->authority != NULL) {
365             if (len + 3 >= max) {
366                 max *= 2;
367                 ret = (xmlChar *) xmlRealloc(ret,
368                         (max + 1) * sizeof(xmlChar));
369                 if (ret == NULL) {
370                     xmlGenericError(xmlGenericErrorContext,
371                             "xmlSaveUri: out of memory\n");
372                     return(NULL);
373                 }
374             }
375             ret[len++] = '/';
376             ret[len++] = '/';
377             p = uri->authority;
378             while (*p != 0) {
379                 if (len + 3 >= max) {
380                     max *= 2;
381                     ret = (xmlChar *) xmlRealloc(ret,
382                             (max + 1) * sizeof(xmlChar));
383                     if (ret == NULL) {
384                         xmlGenericError(xmlGenericErrorContext,
385                                 "xmlSaveUri: out of memory\n");
386                         return(NULL);
387                     }
388                 }
389                 if ((IS_UNRESERVED(*(p))) ||
390                     ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
391                     ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
392                     ((*(p) == '=')) || ((*(p) == '+')))
393                     ret[len++] = *p++;
394                 else {
395                     int val = *(unsigned char *)p++;
396                     int hi = val / 0x10, lo = val % 0x10;
397                     ret[len++] = '%';
398                     ret[len++] = hi + (hi > 9? 'A'-10 : '0');
399                     ret[len++] = lo + (lo > 9? 'A'-10 : '0');
400                 }
401             }
402         } else if (uri->scheme != NULL) {
403             if (len + 3 >= max) {
404                 max *= 2;
405                 ret = (xmlChar *) xmlRealloc(ret,
406                         (max + 1) * sizeof(xmlChar));
407                 if (ret == NULL) {
408                     xmlGenericError(xmlGenericErrorContext,
409                             "xmlSaveUri: out of memory\n");
410                     return(NULL);
411                 }
412             }
413             ret[len++] = '/';
414             ret[len++] = '/';
415         }
416         if (uri->path != NULL) {
417             p = uri->path;
418             while (*p != 0) {
419                 if (len + 3 >= max) {
420                     max *= 2;
421                     ret = (xmlChar *) xmlRealloc(ret,
422                             (max + 1) * sizeof(xmlChar));
423                     if (ret == NULL) {
424                         xmlGenericError(xmlGenericErrorContext,
425                                 "xmlSaveUri: out of memory\n");
426                         return(NULL);
427                     }
428                 }
429                 if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
430                     ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
431                     ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
432                     ((*(p) == ',')))
433                     ret[len++] = *p++;
434                 else {
435                     int val = *(unsigned char *)p++;
436                     int hi = val / 0x10, lo = val % 0x10;
437                     ret[len++] = '%';
438                     ret[len++] = hi + (hi > 9? 'A'-10 : '0');
439                     ret[len++] = lo + (lo > 9? 'A'-10 : '0');
440                 }
441             }
442         }
443         if (uri->query != NULL) {
444             if (len + 3 >= max) {
445                 max *= 2;
446                 ret = (xmlChar *) xmlRealloc(ret,
447                         (max + 1) * sizeof(xmlChar));
448                 if (ret == NULL) {
449                     xmlGenericError(xmlGenericErrorContext,
450                             "xmlSaveUri: out of memory\n");
451                     return(NULL);
452                 }
453             }
454             ret[len++] = '?';
455             p = uri->query;
456             while (*p != 0) {
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                 if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) 
468                     ret[len++] = *p++;
469                 else {
470                     int val = *(unsigned char *)p++;
471                     int hi = val / 0x10, lo = val % 0x10;
472                     ret[len++] = '%';
473                     ret[len++] = hi + (hi > 9? 'A'-10 : '0');
474                     ret[len++] = lo + (lo > 9? 'A'-10 : '0');
475                 }
476             }
477         }
478     }
479     if (uri->fragment != NULL) {
480         if (len + 3 >= max) {
481             max *= 2;
482             ret = (xmlChar *) xmlRealloc(ret,
483                     (max + 1) * sizeof(xmlChar));
484             if (ret == NULL) {
485                 xmlGenericError(xmlGenericErrorContext,
486                         "xmlSaveUri: out of memory\n");
487                 return(NULL);
488             }
489         }
490         ret[len++] = '#';
491         p = uri->fragment;
492         while (*p != 0) {
493             if (len + 3 >= max) {
494                 max *= 2;
495                 ret = (xmlChar *) xmlRealloc(ret,
496                         (max + 1) * sizeof(xmlChar));
497                 if (ret == NULL) {
498                     xmlGenericError(xmlGenericErrorContext,
499                             "xmlSaveUri: out of memory\n");
500                     return(NULL);
501                 }
502             }
503             if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) 
504                 ret[len++] = *p++;
505             else {
506                 int val = *(unsigned char *)p++;
507                 int hi = val / 0x10, lo = val % 0x10;
508                 ret[len++] = '%';
509                 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
510                 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
511             }
512         }
513     }
514     if (len >= max) {
515         max *= 2;
516         ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
517         if (ret == NULL) {
518             xmlGenericError(xmlGenericErrorContext,
519                     "xmlSaveUri: out of memory\n");
520             return(NULL);
521         }
522     }
523     ret[len++] = 0;
524     return(ret);
525 }
526
527 /**
528  * xmlPrintURI:
529  * @stream:  a FILE* for the output
530  * @uri:  pointer to an xmlURI
531  *
532  * Prints the URI in the stream @steam.
533  */
534 void
535 xmlPrintURI(FILE *stream, xmlURIPtr uri) {
536     xmlChar *out;
537
538     out = xmlSaveUri(uri);
539     if (out != NULL) {
540         fprintf(stream, "%s", (char *) out);
541         xmlFree(out);
542     }
543 }
544
545 /**
546  * xmlCleanURI:
547  * @uri:  pointer to an xmlURI
548  *
549  * Make sure the xmlURI struct is free of content
550  */
551 static void
552 xmlCleanURI(xmlURIPtr uri) {
553     if (uri == NULL) return;
554
555     if (uri->scheme != NULL) xmlFree(uri->scheme);
556     uri->scheme = NULL;
557     if (uri->server != NULL) xmlFree(uri->server);
558     uri->server = NULL;
559     if (uri->user != NULL) xmlFree(uri->user);
560     uri->user = NULL;
561     if (uri->path != NULL) xmlFree(uri->path);
562     uri->path = NULL;
563     if (uri->fragment != NULL) xmlFree(uri->fragment);
564     uri->fragment = NULL;
565     if (uri->opaque != NULL) xmlFree(uri->opaque);
566     uri->opaque = NULL;
567     if (uri->authority != NULL) xmlFree(uri->authority);
568     uri->authority = NULL;
569     if (uri->query != NULL) xmlFree(uri->query);
570     uri->query = NULL;
571 }
572
573 /**
574  * xmlFreeURI:
575  * @uri:  pointer to an xmlURI
576  *
577  * Free up the xmlURI struct
578  */
579 void
580 xmlFreeURI(xmlURIPtr uri) {
581     if (uri == NULL) return;
582
583     if (uri->scheme != NULL) xmlFree(uri->scheme);
584     if (uri->server != NULL) xmlFree(uri->server);
585     if (uri->user != NULL) xmlFree(uri->user);
586     if (uri->path != NULL) xmlFree(uri->path);
587     if (uri->fragment != NULL) xmlFree(uri->fragment);
588     if (uri->opaque != NULL) xmlFree(uri->opaque);
589     if (uri->authority != NULL) xmlFree(uri->authority);
590     if (uri->query != NULL) xmlFree(uri->query);
591     xmlFree(uri);
592 }
593
594 /************************************************************************
595  *                                                                      *
596  *                      Helper functions                                *
597  *                                                                      *
598  ************************************************************************/
599
600 /**
601  * xmlNormalizeURIPath:
602  * @path:  pointer to the path string
603  *
604  * Applies the 5 normalization steps to a path string--that is, RFC 2396
605  * Section 5.2, steps 6.c through 6.g.
606  *
607  * Normalization occurs directly on the string, no new allocation is done
608  *
609  * Returns 0 or an error code
610  */
611 int
612 xmlNormalizeURIPath(char *path) {
613     char *cur, *out;
614
615     if (path == NULL)
616         return(-1);
617
618     /* Skip all initial "/" chars.  We want to get to the beginning of the
619      * first non-empty segment.
620      */
621     cur = path;
622     while (cur[0] == '/')
623       ++cur;
624     if (cur[0] == '\0')
625       return(0);
626
627     /* Keep everything we've seen so far.  */
628     out = cur;
629
630     /*
631      * Analyze each segment in sequence for cases (c) and (d).
632      */
633     while (cur[0] != '\0') {
634         /*
635          * c) All occurrences of "./", where "." is a complete path segment,
636          *    are removed from the buffer string.
637          */
638         if ((cur[0] == '.') && (cur[1] == '/')) {
639             cur += 2;
640             /* '//' normalization should be done at this point too */
641             while (cur[0] == '/')
642                 cur++;
643             continue;
644         }
645
646         /*
647          * d) If the buffer string ends with "." as a complete path segment,
648          *    that "." is removed.
649          */
650         if ((cur[0] == '.') && (cur[1] == '\0'))
651             break;
652
653         /* Otherwise keep the segment.  */
654         while (cur[0] != '/') {
655             if (cur[0] == '\0')
656               goto done_cd;
657             (out++)[0] = (cur++)[0];
658         }
659         /* nomalize // */
660         while ((cur[0] == '/') && (cur[1] == '/'))
661             cur++;
662
663         (out++)[0] = (cur++)[0];
664     }
665  done_cd:
666     out[0] = '\0';
667
668     /* Reset to the beginning of the first segment for the next sequence.  */
669     cur = path;
670     while (cur[0] == '/')
671       ++cur;
672     if (cur[0] == '\0')
673         return(0);
674
675     /*
676      * Analyze each segment in sequence for cases (e) and (f).
677      *
678      * e) All occurrences of "<segment>/../", where <segment> is a
679      *    complete path segment not equal to "..", are removed from the
680      *    buffer string.  Removal of these path segments is performed
681      *    iteratively, removing the leftmost matching pattern on each
682      *    iteration, until no matching pattern remains.
683      *
684      * f) If the buffer string ends with "<segment>/..", where <segment>
685      *    is a complete path segment not equal to "..", that
686      *    "<segment>/.." is removed.
687      *
688      * To satisfy the "iterative" clause in (e), we need to collapse the
689      * string every time we find something that needs to be removed.  Thus,
690      * we don't need to keep two pointers into the string: we only need a
691      * "current position" pointer.
692      */
693     while (1) {
694         char *segp, *tmp;
695
696         /* At the beginning of each iteration of this loop, "cur" points to
697          * the first character of the segment we want to examine.
698          */
699
700         /* Find the end of the current segment.  */
701         segp = cur;
702         while ((segp[0] != '/') && (segp[0] != '\0'))
703           ++segp;
704
705         /* If this is the last segment, we're done (we need at least two
706          * segments to meet the criteria for the (e) and (f) cases).
707          */
708         if (segp[0] == '\0')
709           break;
710
711         /* If the first segment is "..", or if the next segment _isn't_ "..",
712          * keep this segment and try the next one.
713          */
714         ++segp;
715         if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
716             || ((segp[0] != '.') || (segp[1] != '.')
717                 || ((segp[2] != '/') && (segp[2] != '\0')))) {
718           cur = segp;
719           continue;
720         }
721
722         /* If we get here, remove this segment and the next one and back up
723          * to the previous segment (if there is one), to implement the
724          * "iteratively" clause.  It's pretty much impossible to back up
725          * while maintaining two pointers into the buffer, so just compact
726          * the whole buffer now.
727          */
728
729         /* If this is the end of the buffer, we're done.  */
730         if (segp[2] == '\0') {
731           cur[0] = '\0';
732           break;
733         }
734         /* Valgrind complained, strcpy(cur, segp + 3); */
735         /* string will overlap, do not use strcpy */
736         tmp = cur;
737         segp += 3;
738         while ((*tmp++ = *segp++) != 0);
739
740         /* If there are no previous segments, then keep going from here.  */
741         segp = cur;
742         while ((segp > path) && ((--segp)[0] == '/'))
743           ;
744         if (segp == path)
745           continue;
746
747         /* "segp" is pointing to the end of a previous segment; find it's
748          * start.  We need to back up to the previous segment and start
749          * over with that to handle things like "foo/bar/../..".  If we
750          * don't do this, then on the first pass we'll remove the "bar/..",
751          * but be pointing at the second ".." so we won't realize we can also
752          * remove the "foo/..".
753          */
754         cur = segp;
755         while ((cur > path) && (cur[-1] != '/'))
756           --cur;
757     }
758     out[0] = '\0';
759
760     /*
761      * g) If the resulting buffer string still begins with one or more
762      *    complete path segments of "..", then the reference is
763      *    considered to be in error. Implementations may handle this
764      *    error by retaining these components in the resolved path (i.e.,
765      *    treating them as part of the final URI), by removing them from
766      *    the resolved path (i.e., discarding relative levels above the
767      *    root), or by avoiding traversal of the reference.
768      *
769      * We discard them from the final path.
770      */
771     if (path[0] == '/') {
772       cur = path;
773       while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
774              && ((cur[3] == '/') || (cur[3] == '\0')))
775         cur += 3;
776
777       if (cur != path) {
778         out = path;
779         while (cur[0] != '\0')
780           (out++)[0] = (cur++)[0];
781         out[0] = 0;
782       }
783     }
784
785     return(0);
786 }
787
788 /**
789  * xmlURIUnescapeString:
790  * @str:  the string to unescape
791  * @len:   the length in bytes to unescape (or <= 0 to indicate full string)
792  * @target:  optional destination buffer
793  *
794  * Unescaping routine, does not do validity checks !
795  * Output is direct unsigned char translation of %XX values (no encoding)
796  *
797  * Returns an copy of the string, but unescaped
798  */
799 char *
800 xmlURIUnescapeString(const char *str, int len, char *target) {
801     char *ret, *out;
802     const char *in;
803
804     if (str == NULL)
805         return(NULL);
806     if (len <= 0) len = strlen(str);
807     if (len < 0) return(NULL);
808
809     if (target == NULL) {
810         ret = (char *) xmlMallocAtomic(len + 1);
811         if (ret == NULL) {
812             xmlGenericError(xmlGenericErrorContext,
813                     "xmlURIUnescapeString: out of memory\n");
814             return(NULL);
815         }
816     } else
817         ret = target;
818     in = str;
819     out = ret;
820     while(len > 0) {
821         if (*in == '%') {
822             in++;
823             if ((*in >= '0') && (*in <= '9')) 
824                 *out = (*in - '0');
825             else if ((*in >= 'a') && (*in <= 'f'))
826                 *out = (*in - 'a') + 10;
827             else if ((*in >= 'A') && (*in <= 'F'))
828                 *out = (*in - 'A') + 10;
829             in++;
830             if ((*in >= '0') && (*in <= '9')) 
831                 *out = *out * 16 + (*in - '0');
832             else if ((*in >= 'a') && (*in <= 'f'))
833                 *out = *out * 16 + (*in - 'a') + 10;
834             else if ((*in >= 'A') && (*in <= 'F'))
835                 *out = *out * 16 + (*in - 'A') + 10;
836             in++;
837             len -= 3;
838             out++;
839         } else {
840             *out++ = *in++;
841             len--;
842         }
843     }
844     *out = 0;
845     return(ret);
846 }
847
848 /**
849  * xmlURIEscapeStr:
850  * @str:  string to escape
851  * @list: exception list string of chars not to escape
852  *
853  * This routine escapes a string to hex, ignoring reserved characters (a-z)
854  * and the characters in the exception list.
855  *
856  * Returns a new escaped string or NULL in case of error.
857  */
858 xmlChar *
859 xmlURIEscapeStr(const xmlChar *str, const xmlChar *list) {
860     xmlChar *ret, ch;
861     const xmlChar *in;
862
863     unsigned int len, out;
864
865     if (str == NULL)
866         return(NULL);
867     len = xmlStrlen(str);
868     if (!(len > 0)) return(NULL);
869
870     len += 20;
871     ret = (xmlChar *) xmlMallocAtomic(len);
872     if (ret == NULL) {
873         xmlGenericError(xmlGenericErrorContext,
874                 "xmlURIEscapeStr: out of memory\n");
875         return(NULL);
876     }
877     in = (const xmlChar *) str;
878     out = 0;
879     while(*in != 0) {
880         if (len - out <= 3) {
881             len += 20;
882             ret = (xmlChar *) xmlRealloc(ret, len);
883             if (ret == NULL) {
884                 xmlGenericError(xmlGenericErrorContext,
885                         "xmlURIEscapeStr: out of memory\n");
886                 return(NULL);
887             }
888         }
889
890         ch = *in;
891
892         if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!xmlStrchr(list, ch))) {
893             unsigned char val;
894             ret[out++] = '%';
895             val = ch >> 4;
896             if (val <= 9)
897                 ret[out++] = '0' + val;
898             else
899                 ret[out++] = 'A' + val - 0xA;
900             val = ch & 0xF;
901             if (val <= 9)
902                 ret[out++] = '0' + val;
903             else
904                 ret[out++] = 'A' + val - 0xA;
905             in++;
906         } else {
907             ret[out++] = *in++;
908         }
909
910     }
911     ret[out] = 0;
912     return(ret);
913 }
914
915 /**
916  * xmlURIEscape:
917  * @str:  the string of the URI to escape
918  *
919  * Escaping routine, does not do validity checks !
920  * It will try to escape the chars needing this, but this is heuristic
921  * based it's impossible to be sure.
922  *
923  * Returns an copy of the string, but escaped
924  *
925  * 25 May 2001
926  * Uses xmlParseURI and xmlURIEscapeStr to try to escape correctly
927  * according to RFC2396.
928  *   - Carl Douglas
929  */
930 xmlChar *
931 xmlURIEscape(const xmlChar * str)
932 {
933     xmlChar *ret, *segment = NULL;
934     xmlURIPtr uri;
935     int ret2;
936
937 #define NULLCHK(p) if(!p) { \
938                    xmlGenericError(xmlGenericErrorContext, \
939                         "xmlURIEscape: out of memory\n"); \
940                    return NULL; }
941
942     if (str == NULL)
943         return (NULL);
944
945     uri = xmlCreateURI();
946     if (uri != NULL) {
947         /*
948          * Allow escaping errors in the unescaped form
949          */
950         uri->cleanup = 1;
951         ret2 = xmlParseURIReference(uri, (const char *)str);
952         if (ret2) {
953             xmlFreeURI(uri);
954             return (NULL);
955         }
956     }
957
958     if (!uri)
959         return NULL;
960
961     ret = NULL;
962
963     if (uri->scheme) {
964         segment = xmlURIEscapeStr(BAD_CAST uri->scheme, BAD_CAST "+-.");
965         NULLCHK(segment)
966         ret = xmlStrcat(ret, segment);
967         ret = xmlStrcat(ret, BAD_CAST ":");
968         xmlFree(segment);
969     }
970
971     if (uri->authority) {
972         segment =
973             xmlURIEscapeStr(BAD_CAST uri->authority, BAD_CAST "/?;:@");
974         NULLCHK(segment)
975         ret = xmlStrcat(ret, BAD_CAST "//");
976         ret = xmlStrcat(ret, segment);
977         xmlFree(segment);
978     }
979
980     if (uri->user) {
981         segment = xmlURIEscapeStr(BAD_CAST uri->user, BAD_CAST ";:&=+$,");
982         NULLCHK(segment)
983         ret = xmlStrcat(ret, segment);
984         ret = xmlStrcat(ret, BAD_CAST "@");
985         xmlFree(segment);
986     }
987
988     if (uri->server) {
989         segment = xmlURIEscapeStr(BAD_CAST uri->server, BAD_CAST "/?;:@");
990         NULLCHK(segment)
991         ret = xmlStrcat(ret, BAD_CAST "//");
992         ret = xmlStrcat(ret, segment);
993         xmlFree(segment);
994     }
995
996     if (uri->port) {
997         xmlChar port[10];
998
999         snprintf((char *) port, 10, "%d", uri->port);
1000         ret = xmlStrcat(ret, BAD_CAST ":");
1001         ret = xmlStrcat(ret, port);
1002     }
1003
1004     if (uri->path) {
1005         segment =
1006             xmlURIEscapeStr(BAD_CAST uri->path, BAD_CAST ":@&=+$,/?;");
1007         NULLCHK(segment)
1008         ret = xmlStrcat(ret, segment);
1009         xmlFree(segment);
1010     }
1011
1012     if (uri->query) {
1013         segment =
1014             xmlURIEscapeStr(BAD_CAST uri->query, BAD_CAST ";/?:@&=+,$");
1015         NULLCHK(segment)
1016         ret = xmlStrcat(ret, BAD_CAST "?");
1017         ret = xmlStrcat(ret, segment);
1018         xmlFree(segment);
1019     }
1020
1021     if (uri->opaque) {
1022         segment = xmlURIEscapeStr(BAD_CAST uri->opaque, BAD_CAST "");
1023         NULLCHK(segment)
1024         ret = xmlStrcat(ret, segment);
1025         xmlFree(segment);
1026     }
1027
1028     if (uri->fragment) {
1029         segment = xmlURIEscapeStr(BAD_CAST uri->fragment, BAD_CAST "#");
1030         NULLCHK(segment)
1031         ret = xmlStrcat(ret, BAD_CAST "#");
1032         ret = xmlStrcat(ret, segment);
1033         xmlFree(segment);
1034     }
1035
1036     xmlFreeURI(uri);
1037 #undef NULLCHK
1038
1039     return (ret);
1040 }
1041
1042 /************************************************************************
1043  *                                                                      *
1044  *                      Escaped URI parsing                             *
1045  *                                                                      *
1046  ************************************************************************/
1047
1048 /**
1049  * xmlParseURIFragment:
1050  * @uri:  pointer to an URI structure
1051  * @str:  pointer to the string to analyze
1052  *
1053  * Parse an URI fragment string and fills in the appropriate fields
1054  * of the @uri structure.
1055  * 
1056  * fragment = *uric
1057  *
1058  * Returns 0 or the error code
1059  */
1060 static int
1061 xmlParseURIFragment(xmlURIPtr uri, const char **str)
1062 {
1063     const char *cur = *str;
1064
1065     if (str == NULL)
1066         return (-1);
1067
1068     while (IS_URIC(cur) || IS_UNWISE(cur))
1069         NEXT(cur);
1070     if (uri != NULL) {
1071         if (uri->fragment != NULL)
1072             xmlFree(uri->fragment);
1073         uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
1074     }
1075     *str = cur;
1076     return (0);
1077 }
1078
1079 /**
1080  * xmlParseURIQuery:
1081  * @uri:  pointer to an URI structure
1082  * @str:  pointer to the string to analyze
1083  *
1084  * Parse the query part of an URI
1085  * 
1086  * query = *uric
1087  *
1088  * Returns 0 or the error code
1089  */
1090 static int
1091 xmlParseURIQuery(xmlURIPtr uri, const char **str)
1092 {
1093     const char *cur = *str;
1094
1095     if (str == NULL)
1096         return (-1);
1097
1098     while (IS_URIC(cur) || ((uri != NULL) && (uri->cleanup) && (IS_UNWISE(cur))))
1099         NEXT(cur);
1100     if (uri != NULL) {
1101         if (uri->query != NULL)
1102             xmlFree(uri->query);
1103         uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
1104     }
1105     *str = cur;
1106     return (0);
1107 }
1108
1109 /**
1110  * xmlParseURIScheme:
1111  * @uri:  pointer to an URI structure
1112  * @str:  pointer to the string to analyze
1113  *
1114  * Parse an URI scheme
1115  * 
1116  * scheme = alpha *( alpha | digit | "+" | "-" | "." )
1117  *
1118  * Returns 0 or the error code
1119  */
1120 static int
1121 xmlParseURIScheme(xmlURIPtr uri, const char **str) {
1122     const char *cur;
1123
1124     if (str == NULL)
1125         return(-1);
1126     
1127     cur = *str;
1128     if (!IS_ALPHA(*cur))
1129         return(2);
1130     cur++;
1131     while (IS_SCHEME(*cur)) cur++;
1132     if (uri != NULL) {
1133         if (uri->scheme != NULL) xmlFree(uri->scheme);
1134         /* !!! strndup */
1135         uri->scheme = xmlURIUnescapeString(*str, cur - *str, NULL);
1136     }
1137     *str = cur;
1138     return(0);
1139 }
1140
1141 /**
1142  * xmlParseURIOpaquePart:
1143  * @uri:  pointer to an URI structure
1144  * @str:  pointer to the string to analyze
1145  *
1146  * Parse an URI opaque part
1147  * 
1148  * opaque_part = uric_no_slash *uric
1149  *
1150  * Returns 0 or the error code
1151  */
1152 static int
1153 xmlParseURIOpaquePart(xmlURIPtr uri, const char **str)
1154 {
1155     const char *cur;
1156
1157     if (str == NULL)
1158         return (-1);
1159
1160     cur = *str;
1161     if (!(IS_URIC_NO_SLASH(cur) || ((uri != NULL) && (uri->cleanup) && (IS_UNWISE(cur))))) {
1162         return (3);
1163     }
1164     NEXT(cur);
1165     while (IS_URIC(cur) || ((uri != NULL) && (uri->cleanup) && (IS_UNWISE(cur))))
1166         NEXT(cur);
1167     if (uri != NULL) {
1168         if (uri->opaque != NULL)
1169             xmlFree(uri->opaque);
1170         uri->opaque = xmlURIUnescapeString(*str, cur - *str, NULL);
1171     }
1172     *str = cur;
1173     return (0);
1174 }
1175
1176 /**
1177  * xmlParseURIServer:
1178  * @uri:  pointer to an URI structure
1179  * @str:  pointer to the string to analyze
1180  *
1181  * Parse a server subpart of an URI, it's a finer grain analysis
1182  * of the authority part.
1183  * 
1184  * server        = [ [ userinfo "@" ] hostport ]
1185  * userinfo      = *( unreserved | escaped |
1186  *                       ";" | ":" | "&" | "=" | "+" | "$" | "," )
1187  * hostport      = host [ ":" port ]
1188  * host          = hostname | IPv4address
1189  * hostname      = *( domainlabel "." ) toplabel [ "." ]
1190  * domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
1191  * toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
1192  * IPv4address   = 1*digit "." 1*digit "." 1*digit "." 1*digit
1193  * port          = *digit
1194  *
1195  * Returns 0 or the error code
1196  */
1197 static int
1198 xmlParseURIServer(xmlURIPtr uri, const char **str) {
1199     const char *cur;
1200     const char *host, *tmp;
1201     const int IPmax = 4;
1202     int oct;
1203
1204     if (str == NULL)
1205         return(-1);
1206     
1207     cur = *str;
1208
1209     /*
1210      * is there an userinfo ?
1211      */
1212     while (IS_USERINFO(cur)) NEXT(cur);
1213     if (*cur == '@') {
1214         if (uri != NULL) {
1215             if (uri->user != NULL) xmlFree(uri->user);
1216             uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
1217         }
1218         cur++;
1219     } else {
1220         if (uri != NULL) {
1221             if (uri->user != NULL) xmlFree(uri->user);
1222             uri->user = NULL;
1223         }
1224         cur = *str;
1225     }
1226     /*
1227      * This can be empty in the case where there is no server
1228      */
1229     host = cur;
1230     if (*cur == '/') {
1231         if (uri != NULL) {
1232             if (uri->authority != NULL) xmlFree(uri->authority);
1233             uri->authority = NULL;
1234             if (uri->server != NULL) xmlFree(uri->server);
1235             uri->server = NULL;
1236             uri->port = 0;
1237         }
1238         return(0);
1239     }
1240     /*
1241      * host part of hostport can derive either an IPV4 address
1242      * or an unresolved name. Check the IP first, it easier to detect
1243      * errors if wrong one
1244      */
1245     for (oct = 0; oct < IPmax; ++oct) {
1246         if (*cur == '.')
1247             return(3); /* e.g. http://.xml/ or http://18.29..30/ */
1248         while(IS_DIGIT(*cur)) cur++;
1249         if (oct == (IPmax-1))
1250             continue;
1251         if (*cur != '.')
1252             break;
1253         cur++;
1254     }
1255     if (oct < IPmax || (*cur == '.' && cur++) || IS_ALPHA(*cur)) {
1256         /* maybe host_name */
1257         if (!IS_ALPHANUM(*cur))
1258             return(4); /* e.g. http://xml.$oft */
1259         do {
1260             do ++cur; while (IS_ALPHANUM(*cur));
1261             if (*cur == '-') {
1262                 --cur;
1263                 if (*cur == '.')
1264                     return(5); /* e.g. http://xml.-soft */
1265                 ++cur;
1266                 continue;
1267             }
1268             if (*cur == '.') {
1269                 --cur;
1270                 if (*cur == '-')
1271                     return(6); /* e.g. http://xml-.soft */
1272                 if (*cur == '.')
1273                     return(7); /* e.g. http://xml..soft */
1274                 ++cur;
1275                 continue;
1276             }
1277             break;
1278         } while (1);
1279         tmp = cur;
1280         if (tmp[-1] == '.')
1281             --tmp; /* e.g. http://xml.$Oft/ */
1282         do --tmp; while (tmp >= host && IS_ALPHANUM(*tmp));
1283         if ((++tmp == host || tmp[-1] == '.') && !IS_ALPHA(*tmp))
1284             return(8); /* e.g. http://xmlsOft.0rg/ */
1285     }
1286     if (uri != NULL) {
1287         if (uri->authority != NULL) xmlFree(uri->authority);
1288         uri->authority = NULL;
1289         if (uri->server != NULL) xmlFree(uri->server);
1290         uri->server = xmlURIUnescapeString(host, cur - host, NULL);
1291     }
1292     /*
1293      * finish by checking for a port presence.
1294      */
1295     if (*cur == ':') {
1296         cur++;
1297         if (IS_DIGIT(*cur)) {
1298             if (uri != NULL)
1299                 uri->port = 0;
1300             while (IS_DIGIT(*cur)) {
1301                 if (uri != NULL)
1302                     uri->port = uri->port * 10 + (*cur - '0');
1303                 cur++;
1304             }
1305         }
1306     }
1307     *str = cur;
1308     return(0);
1309 }       
1310
1311 /**
1312  * xmlParseURIRelSegment:
1313  * @uri:  pointer to an URI structure
1314  * @str:  pointer to the string to analyze
1315  *
1316  * Parse an URI relative segment
1317  * 
1318  * rel_segment = 1*( unreserved | escaped | ";" | "@" | "&" | "=" |
1319  *                          "+" | "$" | "," )
1320  *
1321  * Returns 0 or the error code
1322  */
1323 static int
1324 xmlParseURIRelSegment(xmlURIPtr uri, const char **str)
1325 {
1326     const char *cur;
1327
1328     if (str == NULL)
1329         return (-1);
1330
1331     cur = *str;
1332     if (!(IS_SEGMENT(cur) || ((uri != NULL) && (uri->cleanup) && (IS_UNWISE(cur))))) {
1333         return (3);
1334     }
1335     NEXT(cur);
1336     while (IS_SEGMENT(cur) || ((uri != NULL) && (uri->cleanup) && (IS_UNWISE(cur))))
1337         NEXT(cur);
1338     if (uri != NULL) {
1339         if (uri->path != NULL)
1340             xmlFree(uri->path);
1341         uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
1342     }
1343     *str = cur;
1344     return (0);
1345 }
1346
1347 /**
1348  * xmlParseURIPathSegments:
1349  * @uri:  pointer to an URI structure
1350  * @str:  pointer to the string to analyze
1351  * @slash:  should we add a leading slash
1352  *
1353  * Parse an URI set of path segments
1354  * 
1355  * path_segments = segment *( "/" segment )
1356  * segment       = *pchar *( ";" param )
1357  * param         = *pchar
1358  *
1359  * Returns 0 or the error code
1360  */
1361 static int
1362 xmlParseURIPathSegments(xmlURIPtr uri, const char **str, int slash)
1363 {
1364     const char *cur;
1365
1366     if (str == NULL)
1367         return (-1);
1368
1369     cur = *str;
1370
1371     do {
1372         while (IS_PCHAR(cur) || ((uri != NULL) && (uri->cleanup) && (IS_UNWISE(cur))))
1373             NEXT(cur);
1374         while (*cur == ';') {
1375             cur++;
1376             while (IS_PCHAR(cur) || ((uri != NULL) && (uri->cleanup) && (IS_UNWISE(cur))))
1377                 NEXT(cur);
1378         }
1379         if (*cur != '/')
1380             break;
1381         cur++;
1382     } while (1);
1383     if (uri != NULL) {
1384         int len, len2 = 0;
1385         char *path;
1386
1387         /*
1388          * Concat the set of path segments to the current path
1389          */
1390         len = cur - *str;
1391         if (slash)
1392             len++;
1393
1394         if (uri->path != NULL) {
1395             len2 = strlen(uri->path);
1396             len += len2;
1397         }
1398         path = (char *) xmlMallocAtomic(len + 1);
1399         if (path == NULL) {
1400             xmlGenericError(xmlGenericErrorContext,
1401                             "xmlParseURIPathSegments: out of memory\n");
1402             *str = cur;
1403             return (-1);
1404         }
1405         if (uri->path != NULL)
1406             memcpy(path, uri->path, len2);
1407         if (slash) {
1408             path[len2] = '/';
1409             len2++;
1410         }
1411         path[len2] = 0;
1412         if (cur - *str > 0)
1413             xmlURIUnescapeString(*str, cur - *str, &path[len2]);
1414         if (uri->path != NULL)
1415             xmlFree(uri->path);
1416         uri->path = path;
1417     }
1418     *str = cur;
1419     return (0);
1420 }
1421
1422 /**
1423  * xmlParseURIAuthority:
1424  * @uri:  pointer to an URI structure
1425  * @str:  pointer to the string to analyze
1426  *
1427  * Parse the authority part of an URI.
1428  * 
1429  * authority = server | reg_name
1430  * server    = [ [ userinfo "@" ] hostport ]
1431  * reg_name  = 1*( unreserved | escaped | "$" | "," | ";" | ":" |
1432  *                        "@" | "&" | "=" | "+" )
1433  *
1434  * Note : this is completely ambiguous since reg_name is allowed to
1435  *        use the full set of chars in use by server:
1436  *
1437  *        3.2.1. Registry-based Naming Authority
1438  *
1439  *        The structure of a registry-based naming authority is specific
1440  *        to the URI scheme, but constrained to the allowed characters
1441  *        for an authority component.
1442  *
1443  * Returns 0 or the error code
1444  */
1445 static int
1446 xmlParseURIAuthority(xmlURIPtr uri, const char **str) {
1447     const char *cur;
1448     int ret;
1449
1450     if (str == NULL)
1451         return(-1);
1452     
1453     cur = *str;
1454
1455     /*
1456      * try first to parse it as a server string.
1457      */
1458     ret = xmlParseURIServer(uri, str);
1459     if ((ret == 0) && (*str != NULL) &&
1460         ((**str == 0) || (**str == '/') || (**str == '?')))
1461         return(0);
1462     *str = cur;
1463
1464     /*
1465      * failed, fallback to reg_name
1466      */
1467     if (!IS_REG_NAME(cur)) {
1468         return(5);
1469     }
1470     NEXT(cur);
1471     while (IS_REG_NAME(cur)) NEXT(cur);
1472     if (uri != NULL) {
1473         if (uri->server != NULL) xmlFree(uri->server);
1474         uri->server = NULL;
1475         if (uri->user != NULL) xmlFree(uri->user);
1476         uri->user = NULL;
1477         if (uri->authority != NULL) xmlFree(uri->authority);
1478         uri->authority = xmlURIUnescapeString(*str, cur - *str, NULL);
1479     }
1480     *str = cur;
1481     return(0);
1482 }
1483
1484 /**
1485  * xmlParseURIHierPart:
1486  * @uri:  pointer to an URI structure
1487  * @str:  pointer to the string to analyze
1488  *
1489  * Parse an URI hierarchical part
1490  * 
1491  * hier_part = ( net_path | abs_path ) [ "?" query ]
1492  * abs_path = "/"  path_segments
1493  * net_path = "//" authority [ abs_path ]
1494  *
1495  * Returns 0 or the error code
1496  */
1497 static int
1498 xmlParseURIHierPart(xmlURIPtr uri, const char **str) {
1499     int ret;
1500     const char *cur;
1501
1502     if (str == NULL)
1503         return(-1);
1504     
1505     cur = *str;
1506
1507     if ((cur[0] == '/') && (cur[1] == '/')) {
1508         cur += 2;
1509         ret = xmlParseURIAuthority(uri, &cur);
1510         if (ret != 0)
1511             return(ret);
1512         if (cur[0] == '/') {
1513             cur++;
1514             ret = xmlParseURIPathSegments(uri, &cur, 1);
1515         }
1516     } else if (cur[0] == '/') {
1517         cur++;
1518         ret = xmlParseURIPathSegments(uri, &cur, 1);
1519     } else {
1520         return(4);
1521     }
1522     if (ret != 0)
1523         return(ret);
1524     if (*cur == '?') {
1525         cur++;
1526         ret = xmlParseURIQuery(uri, &cur);
1527         if (ret != 0)
1528             return(ret);
1529     }
1530     *str = cur;
1531     return(0);
1532 }
1533
1534 /**
1535  * xmlParseAbsoluteURI:
1536  * @uri:  pointer to an URI structure
1537  * @str:  pointer to the string to analyze
1538  *
1539  * Parse an URI reference string and fills in the appropriate fields
1540  * of the @uri structure
1541  * 
1542  * absoluteURI   = scheme ":" ( hier_part | opaque_part )
1543  *
1544  * Returns 0 or the error code
1545  */
1546 static int
1547 xmlParseAbsoluteURI(xmlURIPtr uri, const char **str) {
1548     int ret;
1549     const char *cur;
1550
1551     if (str == NULL)
1552         return(-1);
1553     
1554     cur = *str;
1555
1556     ret = xmlParseURIScheme(uri, str);
1557     if (ret != 0) return(ret);
1558     if (**str != ':') {
1559         *str = cur;
1560         return(1);
1561     }
1562     (*str)++;
1563     if (**str == '/')
1564         return(xmlParseURIHierPart(uri, str));
1565     return(xmlParseURIOpaquePart(uri, str));
1566 }
1567
1568 /**
1569  * xmlParseRelativeURI:
1570  * @uri:  pointer to an URI structure
1571  * @str:  pointer to the string to analyze
1572  *
1573  * Parse an relative URI string and fills in the appropriate fields
1574  * of the @uri structure
1575  * 
1576  * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
1577  * abs_path = "/"  path_segments
1578  * net_path = "//" authority [ abs_path ]
1579  * rel_path = rel_segment [ abs_path ]
1580  *
1581  * Returns 0 or the error code
1582  */
1583 static int
1584 xmlParseRelativeURI(xmlURIPtr uri, const char **str) {
1585     int ret = 0;
1586     const char *cur;
1587
1588     if (str == NULL)
1589         return(-1);
1590     
1591     cur = *str;
1592     if ((cur[0] == '/') && (cur[1] == '/')) {
1593         cur += 2;
1594         ret = xmlParseURIAuthority(uri, &cur);
1595         if (ret != 0)
1596             return(ret);
1597         if (cur[0] == '/') {
1598             cur++;
1599             ret = xmlParseURIPathSegments(uri, &cur, 1);
1600         }
1601     } else if (cur[0] == '/') {
1602         cur++;
1603         ret = xmlParseURIPathSegments(uri, &cur, 1);
1604     } else if (cur[0] != '#' && cur[0] != '?') {
1605         ret = xmlParseURIRelSegment(uri, &cur);
1606         if (ret != 0)
1607             return(ret);
1608         if (cur[0] == '/') {
1609             cur++;
1610             ret = xmlParseURIPathSegments(uri, &cur, 1);
1611         }
1612     }
1613     if (ret != 0)
1614         return(ret);
1615     if (*cur == '?') {
1616         cur++;
1617         ret = xmlParseURIQuery(uri, &cur);
1618         if (ret != 0)
1619             return(ret);
1620     }
1621     *str = cur;
1622     return(ret);
1623 }
1624
1625 /**
1626  * xmlParseURIReference:
1627  * @uri:  pointer to an URI structure
1628  * @str:  the string to analyze
1629  *
1630  * Parse an URI reference string and fills in the appropriate fields
1631  * of the @uri structure
1632  * 
1633  * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
1634  *
1635  * Returns 0 or the error code
1636  */
1637 int
1638 xmlParseURIReference(xmlURIPtr uri, const char *str) {
1639     int ret;
1640     const char *tmp = str;
1641
1642     if (str == NULL)
1643         return(-1);
1644     xmlCleanURI(uri);
1645
1646     /*
1647      * Try first to parse absolute refs, then fallback to relative if
1648      * it fails.
1649      */
1650     ret = xmlParseAbsoluteURI(uri, &str);
1651     if (ret != 0) {
1652         xmlCleanURI(uri);
1653         str = tmp;
1654         ret = xmlParseRelativeURI(uri, &str);
1655     }
1656     if (ret != 0) {
1657         xmlCleanURI(uri);
1658         return(ret);
1659     }
1660
1661     if (*str == '#') {
1662         str++;
1663         ret = xmlParseURIFragment(uri, &str);
1664         if (ret != 0) return(ret);
1665     }
1666     if (*str != 0) {
1667         xmlCleanURI(uri);
1668         return(1);
1669     }
1670     return(0);
1671 }
1672
1673 /**
1674  * xmlParseURI:
1675  * @str:  the URI string to analyze
1676  *
1677  * Parse an URI 
1678  * 
1679  * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
1680  *
1681  * Returns a newly build xmlURIPtr or NULL in case of error
1682  */
1683 xmlURIPtr
1684 xmlParseURI(const char *str) {
1685     xmlURIPtr uri;
1686     int ret;
1687
1688     if (str == NULL)
1689         return(NULL);
1690     uri = xmlCreateURI();
1691     if (uri != NULL) {
1692         ret = xmlParseURIReference(uri, str);
1693         if (ret) {
1694             xmlFreeURI(uri);
1695             return(NULL);
1696         }
1697     }
1698     return(uri);
1699 }
1700
1701 /************************************************************************
1702  *                                                                      *
1703  *                      Public functions                                *
1704  *                                                                      *
1705  ************************************************************************/
1706
1707 /**
1708  * xmlBuildURI:
1709  * @URI:  the URI instance found in the document
1710  * @base:  the base value
1711  *
1712  * Computes he final URI of the reference done by checking that
1713  * the given URI is valid, and building the final URI using the
1714  * base URI. This is processed according to section 5.2 of the 
1715  * RFC 2396
1716  *
1717  * 5.2. Resolving Relative References to Absolute Form
1718  *
1719  * Returns a new URI string (to be freed by the caller) or NULL in case
1720  *         of error.
1721  */
1722 xmlChar *
1723 xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
1724     xmlChar *val = NULL;
1725     int ret, len, indx, cur, out;
1726     xmlURIPtr ref = NULL;
1727     xmlURIPtr bas = NULL;
1728     xmlURIPtr res = NULL;
1729
1730     /*
1731      * 1) The URI reference is parsed into the potential four components and
1732      *    fragment identifier, as described in Section 4.3.
1733      *
1734      *    NOTE that a completely empty URI is treated by modern browsers
1735      *    as a reference to "." rather than as a synonym for the current
1736      *    URI.  Should we do that here?
1737      */
1738     if (URI == NULL) 
1739         ret = -1;
1740     else {
1741         if (*URI) {
1742             ref = xmlCreateURI();
1743             if (ref == NULL)
1744                 goto done;
1745             ret = xmlParseURIReference(ref, (const char *) URI);
1746         }
1747         else
1748             ret = 0;
1749     }
1750     if (ret != 0)
1751         goto done;
1752     if ((ref != NULL) && (ref->scheme != NULL)) {
1753         /*
1754          * The URI is absolute don't modify.
1755          */
1756         val = xmlStrdup(URI);
1757         goto done;
1758     }
1759     if (base == NULL)
1760         ret = -1;
1761     else {
1762         bas = xmlCreateURI();
1763         if (bas == NULL)
1764             goto done;
1765         ret = xmlParseURIReference(bas, (const char *) base);
1766     }
1767     if (ret != 0) {
1768         if (ref)
1769             val = xmlSaveUri(ref);
1770         goto done;
1771     }
1772     if (ref == NULL) {
1773         /*
1774          * the base fragment must be ignored
1775          */
1776         if (bas->fragment != NULL) {
1777             xmlFree(bas->fragment);
1778             bas->fragment = NULL;
1779         }
1780         val = xmlSaveUri(bas);
1781         goto done;
1782     }
1783
1784     /*
1785      * 2) If the path component is empty and the scheme, authority, and
1786      *    query components are undefined, then it is a reference to the
1787      *    current document and we are done.  Otherwise, the reference URI's
1788      *    query and fragment components are defined as found (or not found)
1789      *    within the URI reference and not inherited from the base URI.
1790      *
1791      *    NOTE that in modern browsers, the parsing differs from the above
1792      *    in the following aspect:  the query component is allowed to be
1793      *    defined while still treating this as a reference to the current
1794      *    document.
1795      */
1796     res = xmlCreateURI();
1797     if (res == NULL)
1798         goto done;
1799     if ((ref->scheme == NULL) && (ref->path == NULL) &&
1800         ((ref->authority == NULL) && (ref->server == NULL))) {
1801         if (bas->scheme != NULL)
1802             res->scheme = xmlMemStrdup(bas->scheme);
1803         if (bas->authority != NULL)
1804             res->authority = xmlMemStrdup(bas->authority);
1805         else if (bas->server != NULL) {
1806             res->server = xmlMemStrdup(bas->server);
1807             if (bas->user != NULL)
1808                 res->user = xmlMemStrdup(bas->user);
1809             res->port = bas->port;              
1810         }
1811         if (bas->path != NULL)
1812             res->path = xmlMemStrdup(bas->path);
1813         if (ref->query != NULL)
1814             res->query = xmlMemStrdup(ref->query);
1815         else if (bas->query != NULL)
1816             res->query = xmlMemStrdup(bas->query);
1817         if (ref->fragment != NULL)
1818             res->fragment = xmlMemStrdup(ref->fragment);
1819         goto step_7;
1820     }
1821
1822     /*
1823      * 3) If the scheme component is defined, indicating that the reference
1824      *    starts with a scheme name, then the reference is interpreted as an
1825      *    absolute URI and we are done.  Otherwise, the reference URI's
1826      *    scheme is inherited from the base URI's scheme component.
1827      */
1828     if (ref->scheme != NULL) {
1829         val = xmlSaveUri(ref);
1830         goto done;
1831     }
1832     if (bas->scheme != NULL)
1833         res->scheme = xmlMemStrdup(bas->scheme);
1834  
1835     if (ref->query != NULL)
1836         res->query = xmlMemStrdup(ref->query);
1837     if (ref->fragment != NULL)
1838         res->fragment = xmlMemStrdup(ref->fragment);
1839
1840     /*
1841      * 4) If the authority component is defined, then the reference is a
1842      *    network-path and we skip to step 7.  Otherwise, the reference
1843      *    URI's authority is inherited from the base URI's authority
1844      *    component, which will also be undefined if the URI scheme does not
1845      *    use an authority component.
1846      */
1847     if ((ref->authority != NULL) || (ref->server != NULL)) {
1848         if (ref->authority != NULL)
1849             res->authority = xmlMemStrdup(ref->authority);
1850         else {
1851             res->server = xmlMemStrdup(ref->server);
1852             if (ref->user != NULL)
1853                 res->user = xmlMemStrdup(ref->user);
1854             res->port = ref->port;              
1855         }
1856         if (ref->path != NULL)
1857             res->path = xmlMemStrdup(ref->path);
1858         goto step_7;
1859     }
1860     if (bas->authority != NULL)
1861         res->authority = xmlMemStrdup(bas->authority);
1862     else if (bas->server != NULL) {
1863         res->server = xmlMemStrdup(bas->server);
1864         if (bas->user != NULL)
1865             res->user = xmlMemStrdup(bas->user);
1866         res->port = bas->port;          
1867     }
1868
1869     /*
1870      * 5) If the path component begins with a slash character ("/"), then
1871      *    the reference is an absolute-path and we skip to step 7.
1872      */
1873     if ((ref->path != NULL) && (ref->path[0] == '/')) {
1874         res->path = xmlMemStrdup(ref->path);
1875         goto step_7;
1876     }
1877
1878
1879     /*
1880      * 6) If this step is reached, then we are resolving a relative-path
1881      *    reference.  The relative path needs to be merged with the base
1882      *    URI's path.  Although there are many ways to do this, we will
1883      *    describe a simple method using a separate string buffer.
1884      *
1885      * Allocate a buffer large enough for the result string.
1886      */
1887     len = 2; /* extra / and 0 */
1888     if (ref->path != NULL)
1889         len += strlen(ref->path);
1890     if (bas->path != NULL)
1891         len += strlen(bas->path);
1892     res->path = (char *) xmlMallocAtomic(len);
1893     if (res->path == NULL) {
1894         xmlGenericError(xmlGenericErrorContext,
1895                 "xmlBuildURI: out of memory\n");
1896         goto done;
1897     }
1898     res->path[0] = 0;
1899
1900     /*
1901      * a) All but the last segment of the base URI's path component is
1902      *    copied to the buffer.  In other words, any characters after the
1903      *    last (right-most) slash character, if any, are excluded.
1904      */
1905     cur = 0;
1906     out = 0;
1907     if (bas->path != NULL) {
1908         while (bas->path[cur] != 0) {
1909             while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
1910                 cur++;
1911             if (bas->path[cur] == 0)
1912                 break;
1913
1914             cur++;
1915             while (out < cur) {
1916                 res->path[out] = bas->path[out];
1917                 out++;
1918             }
1919         }
1920     }
1921     res->path[out] = 0;
1922
1923     /*
1924      * b) The reference's path component is appended to the buffer
1925      *    string.
1926      */
1927     if (ref->path != NULL && ref->path[0] != 0) {
1928         indx = 0;
1929         /*
1930          * Ensure the path includes a '/'
1931          */
1932         if ((out == 0) && (bas->server != NULL))
1933             res->path[out++] = '/';
1934         while (ref->path[indx] != 0) {
1935             res->path[out++] = ref->path[indx++];
1936         }
1937     }
1938     res->path[out] = 0;
1939
1940     /*
1941      * Steps c) to h) are really path normalization steps
1942      */
1943     xmlNormalizeURIPath(res->path);
1944
1945 step_7:
1946
1947     /*
1948      * 7) The resulting URI components, including any inherited from the
1949      *    base URI, are recombined to give the absolute form of the URI
1950      *    reference.
1951      */
1952     val = xmlSaveUri(res);
1953
1954 done:
1955     if (ref != NULL)
1956         xmlFreeURI(ref);
1957     if (bas != NULL)
1958         xmlFreeURI(bas);
1959     if (res != NULL)
1960         xmlFreeURI(res);
1961     return(val);
1962 }
1963
1964 /**
1965  * xmlCanonicPath:
1966  * @path:  the resource locator in a filesystem notation
1967  *
1968  * Constructs a canonic path from the specified path. 
1969  *
1970  * Returns a new canonic path, or a duplicate of the path parameter if the 
1971  * construction fails. The caller is responsible for freeing the memory occupied
1972  * by the returned string. If there is insufficient memory available, or the 
1973  * argument is NULL, the function returns NULL.
1974  */
1975 #define IS_WINDOWS_PATH(p)                                      \
1976         ((p != NULL) &&                                         \
1977          (((p[0] >= 'a') && (p[0] <= 'z')) ||                   \
1978           ((p[0] >= 'A') && (p[0] <= 'Z'))) &&                  \
1979          (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))
1980 xmlChar*
1981 xmlCanonicPath(const xmlChar *path)
1982 {
1983 #if defined(_WIN32) && !defined(__CYGWIN__)    
1984     int len = 0;
1985     int i = 0;
1986     xmlChar *p = NULL;
1987 #endif
1988     xmlChar *ret;
1989     xmlURIPtr uri;
1990
1991     if (path == NULL)
1992         return(NULL);
1993     if ((uri = xmlParseURI((const char *) path)) != NULL) {
1994         xmlFreeURI(uri);
1995         return xmlStrdup(path);
1996     }
1997
1998     uri = xmlCreateURI();
1999     if (uri == NULL) {
2000         return(NULL);
2001     }
2002
2003 #if defined(_WIN32) && !defined(__CYGWIN__)    
2004     len = xmlStrlen(path);
2005     if ((len > 2) && IS_WINDOWS_PATH(path)) {
2006         uri->scheme = xmlStrdup(BAD_CAST "file");
2007         uri->path = xmlMallocAtomic(len + 2);
2008         uri->path[0] = '/';
2009         p = uri->path + 1;
2010         strncpy(p, path, len + 1);
2011     } else {
2012         uri->path = xmlStrdup(path);
2013         p = uri->path;
2014     }
2015     while (*p != '\0') {
2016         if (*p == '\\')
2017             *p = '/';
2018         p++;
2019     }
2020 #else
2021     uri->path = (char *) xmlStrdup((const xmlChar *) path);
2022 #endif
2023     
2024     ret = xmlSaveUri(uri);
2025     xmlFreeURI(uri);
2026     return(ret);
2027 }
2028