uri.c
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:40k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/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@w3.org
  9.  */
  10. #ifdef WIN32
  11. #define INCLUDE_WINSOCK
  12. #include "win32config.h"
  13. #else
  14. #include "config.h"
  15. #endif
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <libxml/xmlmemory.h>
  19. #include <libxml/uri.h>
  20. /**
  21.  * alpha    = lowalpha | upalpha
  22.  */
  23. #define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
  24. /**
  25.  * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
  26.  *            "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
  27.  *            "u" | "v" | "w" | "x" | "y" | "z"
  28.  */
  29. #define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
  30. /**
  31.  * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
  32.  *           "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
  33.  *           "U" | "V" | "W" | "X" | "Y" | "Z"
  34.  */
  35. #define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
  36. /**
  37.  * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
  38.  */
  39. #define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
  40. /**
  41.  * alphanum = alpha | digit
  42.  */
  43. #define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
  44. /**
  45.  * he(x) = digit | "A" | "B" | "C" | "D" | "E" | "F" |
  46.  *               "a" | "b" | "c" | "d" | "e" | "f"
  47.  */
  48. #define IS_HEX(x) ((IS_DIGIT(x)) || (((x) >= 'a') && ((x) <= 'f')) || 
  49.     (((x) >= 'A') && ((x) <= 'F')))
  50. /**
  51.  * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
  52.  */
  53. #define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') ||
  54.     ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == ''') ||
  55.     ((x) == '(') || ((x) == ')'))
  56. /**
  57.  * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
  58.  */
  59. #define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') ||
  60.         ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') ||
  61. ((x) == '+') || ((x) == '$') || ((x) == ','))
  62. /**
  63.  * unreserved = alphanum | mark
  64.  */
  65. #define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
  66. /**
  67.  * escaped = "%" hex hex
  68.  */
  69. #define IS_ESCAPED(p) ((*(p) == '%') && (IS_HEX((p)[1])) &&
  70.     (IS_HEX((p)[2])))
  71. /**
  72.  * uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
  73.  *                        "&" | "=" | "+" | "$" | ","
  74.  */
  75. #define IS_URIC_NO_SLASH(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||
  76.         ((*(p) == ';')) || ((*(p) == '?')) || ((*(p) == ':')) ||
  77.         ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||
  78.         ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ',')))
  79. /**
  80.  * pchar = unreserved | escaped | ":" | "@" | "&" | "=" | "+" | "$" | ","
  81.  */
  82. #define IS_PCHAR(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||
  83.         ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
  84.         ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
  85.         ((*(p) == ',')))
  86. /**
  87.  * rel_segment   = 1*( unreserved | escaped |
  88.  *                 ";" | "@" | "&" | "=" | "+" | "$" | "," )
  89.  */
  90. #define IS_SEGMENT(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||
  91.           ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
  92.   ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
  93.   ((*(p) == ',')))
  94. /**
  95.  * scheme = alpha *( alpha | digit | "+" | "-" | "." )
  96.  */
  97. #define IS_SCHEME(x) ((IS_ALPHA(x)) || (IS_DIGIT(x)) ||
  98.               ((x) == '+') || ((x) == '-') || ((x) == '.'))
  99. /**
  100.  * reg_name = 1*( unreserved | escaped | "$" | "," |
  101.  *                ";" | ":" | "@" | "&" | "=" | "+" )
  102.  */
  103. #define IS_REG_NAME(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||
  104.        ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
  105.        ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
  106.        ((*(p) == '=')) || ((*(p) == '+')))
  107. /**
  108.  * userinfo = *( unreserved | escaped | ";" | ":" | "&" | "=" |
  109.  *                      "+" | "$" | "," )
  110.  */
  111. #define IS_USERINFO(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||
  112.        ((*(p) == ';')) || ((*(p) == ':')) || ((*(p) == '&')) ||
  113.        ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
  114.        ((*(p) == ',')))
  115. /**
  116.  * uric = reserved | unreserved | escaped
  117.  */
  118. #define IS_URIC(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||
  119.             (IS_RESERVED(*(p))))
  120. /**
  121.  * Skip to next pointer char, handle escaped sequences
  122.  */
  123. #define NEXT(p) ((*p == '%')? p += 3 : p++)
  124. /**
  125.  * Productions from the spec.
  126.  *
  127.  *    authority     = server | reg_name
  128.  *    reg_name      = 1*( unreserved | escaped | "$" | "," |
  129.  *                        ";" | ":" | "@" | "&" | "=" | "+" )
  130.  *
  131.  * path          = [ abs_path | opaque_part ]
  132.  */
  133. /**
  134.  * xmlCreateURI:
  135.  *
  136.  * Simply creates an empty xmlURI
  137.  *
  138.  * Returns the new structure or NULL in case of error
  139.  */
  140. xmlURIPtr
  141. xmlCreateURI(void) {
  142.     xmlURIPtr ret;
  143.     ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI));
  144.     if (ret == NULL) {
  145. fprintf(stderr, "xmlCreateURI: out of memoryn");
  146. return(NULL);
  147.     }
  148.     memset(ret, 0, sizeof(xmlURI));
  149.     return(ret);
  150. }
  151. /**
  152.  * xmlSaveUri:
  153.  * @uri:  pointer to an xmlURI
  154.  *
  155.  * Save the URI as an escaped string
  156.  *
  157.  * Returns a new string (to be deallocated by caller)
  158.  */
  159. xmlChar *
  160. xmlSaveUri(xmlURIPtr uri) {
  161.     xmlChar *ret = NULL;
  162.     const char *p;
  163.     int len;
  164.     int max;
  165.     if (uri == NULL) return(NULL);
  166.     max = 80;
  167.     ret = xmlMalloc((max + 1) * sizeof(xmlChar));
  168.     if (ret == NULL) {
  169. fprintf(stderr, "xmlSaveUri: out of memoryn");
  170. return(NULL);
  171.     }
  172.     len = 0;
  173.     if (uri->scheme != NULL) {
  174. p = uri->scheme;
  175. while (*p != 0) {
  176.     if (len >= max) {
  177. max *= 2;
  178. ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  179. if (ret == NULL) {
  180.     fprintf(stderr, "xmlSaveUri: out of memoryn");
  181.     return(NULL);
  182. }
  183.     }
  184.     ret[len++] = *p++;
  185. }
  186. if (len >= max) {
  187.     max *= 2;
  188.     ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  189.     if (ret == NULL) {
  190. fprintf(stderr, "xmlSaveUri: out of memoryn");
  191. return(NULL);
  192.     }
  193. }
  194. ret[len++] = ':';
  195.     }
  196.     if (uri->opaque != NULL) {
  197. p = uri->opaque;
  198. while (*p != 0) {
  199.     if (len + 3 >= max) {
  200. max *= 2;
  201. ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  202. if (ret == NULL) {
  203.     fprintf(stderr, "xmlSaveUri: out of memoryn");
  204.     return(NULL);
  205. }
  206.     }
  207.     if ((IS_UNRESERVED(*(p))) ||
  208.         ((*(p) == ';')) || ((*(p) == '?')) || ((*(p) == ':')) ||
  209.         ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||
  210.         ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ',')))
  211. ret[len++] = *p++;
  212.     else {
  213. int val = *p++;
  214. ret[len++] = '%';
  215. switch (val / 0x10) {
  216.     case 0xF: ret[len++] = 'F'; break;
  217.     case 0xE: ret[len++] = 'E'; break;
  218.     case 0xD: ret[len++] = 'D'; break;
  219.     case 0xC: ret[len++] = 'C'; break;
  220.     case 0xB: ret[len++] = 'B'; break;
  221.     case 0xA: ret[len++] = 'A'; break;
  222.     default: ret[len++] = '0' + (val / 0x10);
  223. }
  224. switch (val % 0x10) {
  225.     case 0xF: ret[len++] = 'F'; break;
  226.     case 0xE: ret[len++] = 'E'; break;
  227.     case 0xD: ret[len++] = 'D'; break;
  228.     case 0xC: ret[len++] = 'C'; break;
  229.     case 0xB: ret[len++] = 'B'; break;
  230.     case 0xA: ret[len++] = 'A'; break;
  231.     default: ret[len++] = '0' + (val % 0x10);
  232. }
  233.     }
  234. }
  235. if (len >= max) {
  236.     max *= 2;
  237.     ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  238.     if (ret == NULL) {
  239. fprintf(stderr, "xmlSaveUri: out of memoryn");
  240. return(NULL);
  241.     }
  242. }
  243. ret[len++] = 0;
  244.     } else {
  245. if (uri->server != NULL) {
  246.     if (len + 3 >= max) {
  247. max *= 2;
  248. ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  249. if (ret == NULL) {
  250.     fprintf(stderr, "xmlSaveUri: out of memoryn");
  251.     return(NULL);
  252. }
  253.     }
  254.     ret[len++] = '/';
  255.     ret[len++] = '/';
  256.     if (uri->user != NULL) {
  257. p = uri->user;
  258. while (*p != 0) {
  259.     if (len + 3 >= max) {
  260. max *= 2;
  261. ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  262. if (ret == NULL) {
  263.     fprintf(stderr, "xmlSaveUri: out of memoryn");
  264.     return(NULL);
  265. }
  266.     }
  267.     if ((IS_UNRESERVED(*(p))) ||
  268. ((*(p) == ';')) || ((*(p) == ':')) || ((*(p) == '&')) ||
  269. ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
  270. ((*(p) == ',')))
  271. ret[len++] = *p++;
  272.     else {
  273. int val = *p++;
  274. ret[len++] = '%';
  275. switch (val / 0x10) {
  276.     case 0xF: ret[len++] = 'F'; break;
  277.     case 0xE: ret[len++] = 'E'; break;
  278.     case 0xD: ret[len++] = 'D'; break;
  279.     case 0xC: ret[len++] = 'C'; break;
  280.     case 0xB: ret[len++] = 'B'; break;
  281.     case 0xA: ret[len++] = 'A'; break;
  282.     default: ret[len++] = '0' + (val / 0x10);
  283. }
  284. switch (val % 0x10) {
  285.     case 0xF: ret[len++] = 'F'; break;
  286.     case 0xE: ret[len++] = 'E'; break;
  287.     case 0xD: ret[len++] = 'D'; break;
  288.     case 0xC: ret[len++] = 'C'; break;
  289.     case 0xB: ret[len++] = 'B'; break;
  290.     case 0xA: ret[len++] = 'A'; break;
  291.     default: ret[len++] = '0' + (val % 0x10);
  292. }
  293.     }
  294. }
  295. if (len + 3 >= max) {
  296.     max *= 2;
  297.     ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  298.     if (ret == NULL) {
  299. fprintf(stderr, "xmlSaveUri: out of memoryn");
  300. return(NULL);
  301.     }
  302. }
  303. ret[len++] = '@';
  304.     }
  305.     p = uri->server;
  306.     while (*p != 0) {
  307. if (len >= max) {
  308.     max *= 2;
  309.     ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  310.     if (ret == NULL) {
  311. fprintf(stderr, "xmlSaveUri: out of memoryn");
  312. return(NULL);
  313.     }
  314. }
  315. ret[len++] = *p++;
  316.     }
  317.     if (uri->port > 0) {
  318. if (len + 10 >= max) {
  319.     max *= 2;
  320.     ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  321.     if (ret == NULL) {
  322. fprintf(stderr, "xmlSaveUri: out of memoryn");
  323. return(NULL);
  324.     }
  325. }
  326. len += sprintf((char *) &ret[len], ":%d", uri->port);
  327.     }
  328. } else if (uri->authority != NULL) {
  329.     if (len + 3 >= max) {
  330. max *= 2;
  331. ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  332. if (ret == NULL) {
  333.     fprintf(stderr, "xmlSaveUri: out of memoryn");
  334.     return(NULL);
  335. }
  336.     }
  337.     ret[len++] = '/';
  338.     ret[len++] = '/';
  339.     p = uri->authority;
  340.     while (*p != 0) {
  341. if (len + 3 >= max) {
  342.     max *= 2;
  343.     ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  344.     if (ret == NULL) {
  345. fprintf(stderr, "xmlSaveUri: out of memoryn");
  346. return(NULL);
  347.     }
  348. }
  349. if ((IS_UNRESERVED(*(p))) ||
  350.                     ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
  351.                     ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
  352.                     ((*(p) == '=')) || ((*(p) == '+')))
  353.     ret[len++] = *p++;
  354. else {
  355.     int val = *p++;
  356.     ret[len++] = '%';
  357.     switch (val / 0x10) {
  358. case 0xF: ret[len++] = 'F'; break;
  359. case 0xE: ret[len++] = 'E'; break;
  360. case 0xD: ret[len++] = 'D'; break;
  361. case 0xC: ret[len++] = 'C'; break;
  362. case 0xB: ret[len++] = 'B'; break;
  363. case 0xA: ret[len++] = 'A'; break;
  364. default: ret[len++] = '0' + (val / 0x10);
  365.     }
  366.     switch (val % 0x10) {
  367. case 0xF: ret[len++] = 'F'; break;
  368. case 0xE: ret[len++] = 'E'; break;
  369. case 0xD: ret[len++] = 'D'; break;
  370. case 0xC: ret[len++] = 'C'; break;
  371. case 0xB: ret[len++] = 'B'; break;
  372. case 0xA: ret[len++] = 'A'; break;
  373. default: ret[len++] = '0' + (val % 0x10);
  374.     }
  375. }
  376.     }
  377. }
  378. if (uri->path != NULL) {
  379.     p = uri->path;
  380.     while (*p != 0) {
  381. if (len + 3 >= max) {
  382.     max *= 2;
  383.     ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  384.     if (ret == NULL) {
  385. fprintf(stderr, "xmlSaveUri: out of memoryn");
  386. return(NULL);
  387.     }
  388. }
  389. if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
  390.                     ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
  391.             ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
  392.             ((*(p) == ',')))
  393.     ret[len++] = *p++;
  394. else {
  395.     int val = *p++;
  396.     ret[len++] = '%';
  397.     switch (val / 0x10) {
  398. case 0xF: ret[len++] = 'F'; break;
  399. case 0xE: ret[len++] = 'E'; break;
  400. case 0xD: ret[len++] = 'D'; break;
  401. case 0xC: ret[len++] = 'C'; break;
  402. case 0xB: ret[len++] = 'B'; break;
  403. case 0xA: ret[len++] = 'A'; break;
  404. default: ret[len++] = '0' + (val / 0x10);
  405.     }
  406.     switch (val % 0x10) {
  407. case 0xF: ret[len++] = 'F'; break;
  408. case 0xE: ret[len++] = 'E'; break;
  409. case 0xD: ret[len++] = 'D'; break;
  410. case 0xC: ret[len++] = 'C'; break;
  411. case 0xB: ret[len++] = 'B'; break;
  412. case 0xA: ret[len++] = 'A'; break;
  413. default: ret[len++] = '0' + (val % 0x10);
  414.     }
  415. }
  416.     }
  417. }
  418. if (uri->query != NULL) {
  419.     if (len + 3 >= max) {
  420. max *= 2;
  421. ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  422. if (ret == NULL) {
  423.     fprintf(stderr, "xmlSaveUri: out of memoryn");
  424.     return(NULL);
  425. }
  426.     }
  427.     ret[len++] = '?';
  428.     p = uri->query;
  429.     while (*p != 0) {
  430. if (len + 3 >= max) {
  431.     max *= 2;
  432.     ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  433.     if (ret == NULL) {
  434. fprintf(stderr, "xmlSaveUri: out of memoryn");
  435. return(NULL);
  436.     }
  437. }
  438. if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) 
  439.     ret[len++] = *p++;
  440. else {
  441.     int val = *p++;
  442.     ret[len++] = '%';
  443.     switch (val / 0x10) {
  444. case 0xF: ret[len++] = 'F'; break;
  445. case 0xE: ret[len++] = 'E'; break;
  446. case 0xD: ret[len++] = 'D'; break;
  447. case 0xC: ret[len++] = 'C'; break;
  448. case 0xB: ret[len++] = 'B'; break;
  449. case 0xA: ret[len++] = 'A'; break;
  450. default: ret[len++] = '0' + (val / 0x10);
  451.     }
  452.     switch (val % 0x10) {
  453. case 0xF: ret[len++] = 'F'; break;
  454. case 0xE: ret[len++] = 'E'; break;
  455. case 0xD: ret[len++] = 'D'; break;
  456. case 0xC: ret[len++] = 'C'; break;
  457. case 0xB: ret[len++] = 'B'; break;
  458. case 0xA: ret[len++] = 'A'; break;
  459. default: ret[len++] = '0' + (val % 0x10);
  460.     }
  461. }
  462.     }
  463. }
  464. if (uri->fragment != NULL) {
  465.     if (len + 3 >= max) {
  466. max *= 2;
  467. ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  468. if (ret == NULL) {
  469.     fprintf(stderr, "xmlSaveUri: out of memoryn");
  470.     return(NULL);
  471. }
  472.     }
  473.     ret[len++] = '#';
  474.     p = uri->fragment;
  475.     while (*p != 0) {
  476. if (len + 3 >= max) {
  477.     max *= 2;
  478.     ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  479.     if (ret == NULL) {
  480. fprintf(stderr, "xmlSaveUri: out of memoryn");
  481. return(NULL);
  482.     }
  483. }
  484. if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) 
  485.     ret[len++] = *p++;
  486. else {
  487.     int val = *p++;
  488.     ret[len++] = '%';
  489.     switch (val / 0x10) {
  490. case 0xF: ret[len++] = 'F'; break;
  491. case 0xE: ret[len++] = 'E'; break;
  492. case 0xD: ret[len++] = 'D'; break;
  493. case 0xC: ret[len++] = 'C'; break;
  494. case 0xB: ret[len++] = 'B'; break;
  495. case 0xA: ret[len++] = 'A'; break;
  496. default: ret[len++] = '0' + (val / 0x10);
  497.     }
  498.     switch (val % 0x10) {
  499. case 0xF: ret[len++] = 'F'; break;
  500. case 0xE: ret[len++] = 'E'; break;
  501. case 0xD: ret[len++] = 'D'; break;
  502. case 0xC: ret[len++] = 'C'; break;
  503. case 0xB: ret[len++] = 'B'; break;
  504. case 0xA: ret[len++] = 'A'; break;
  505. default: ret[len++] = '0' + (val % 0x10);
  506.     }
  507. }
  508.     }
  509. }
  510. if (len >= max) {
  511.     max *= 2;
  512.     ret = xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
  513.     if (ret == NULL) {
  514. fprintf(stderr, "xmlSaveUri: out of memoryn");
  515. return(NULL);
  516.     }
  517. }
  518. ret[len++] = 0;
  519.     }
  520.     return(ret);
  521. }
  522. /**
  523.  * xmlPrintURI:
  524.  * @stream:  a FILE* for the output
  525.  * @uri:  pointer to an xmlURI
  526.  *
  527.  * Prints the URI in the stream @steam.
  528.  */
  529. void
  530. xmlPrintURI(FILE *stream, xmlURIPtr uri) {
  531.     xmlChar *out;
  532.     out = xmlSaveUri(uri);
  533.     if (out != NULL) {
  534. fprintf(stream, "%s", out);
  535. xmlFree(out);
  536.     }
  537. }
  538. /**
  539.  * xmlCleanURI:
  540.  * @uri:  pointer to an xmlURI
  541.  *
  542.  * Make sure the xmlURI struct is free of content
  543.  */
  544. void
  545. xmlCleanURI(xmlURIPtr uri) {
  546.     if (uri == NULL) return;
  547.     if (uri->scheme != NULL) xmlFree(uri->scheme);
  548.     uri->scheme = NULL;
  549.     if (uri->server != NULL) xmlFree(uri->server);
  550.     uri->server = NULL;
  551.     if (uri->user != NULL) xmlFree(uri->user);
  552.     uri->user = NULL;
  553.     if (uri->path != NULL) xmlFree(uri->path);
  554.     uri->path = NULL;
  555.     if (uri->fragment != NULL) xmlFree(uri->fragment);
  556.     uri->fragment = NULL;
  557.     if (uri->opaque != NULL) xmlFree(uri->opaque);
  558.     uri->opaque = NULL;
  559.     if (uri->authority != NULL) xmlFree(uri->authority);
  560.     uri->authority = NULL;
  561.     if (uri->query != NULL) xmlFree(uri->query);
  562.     uri->query = NULL;
  563. }
  564. /**
  565.  * xmlFreeURI:
  566.  * @uri:  pointer to an xmlURI
  567.  *
  568.  * Free up the xmlURI struct
  569.  */
  570. void
  571. xmlFreeURI(xmlURIPtr uri) {
  572.     if (uri == NULL) return;
  573.     if (uri->scheme != NULL) xmlFree(uri->scheme);
  574.     if (uri->server != NULL) xmlFree(uri->server);
  575.     if (uri->user != NULL) xmlFree(uri->user);
  576.     if (uri->path != NULL) xmlFree(uri->path);
  577.     if (uri->fragment != NULL) xmlFree(uri->fragment);
  578.     if (uri->opaque != NULL) xmlFree(uri->opaque);
  579.     if (uri->authority != NULL) xmlFree(uri->authority);
  580.     if (uri->query != NULL) xmlFree(uri->query);
  581.     memset(uri, -1, sizeof(xmlURI));
  582.     xmlFree(uri);
  583. }
  584. /**
  585.  * xmlURIUnescapeString:
  586.  * @str:  the string to unescape
  587.  * @len:   the lenght in bytes to unescape (or <= 0 to indicate full string)
  588.  * @target:  optionnal destination buffer
  589.  *
  590.  * Unescaping routine, does not do validity checks !
  591.  * Output is direct unsigned char translation of %XX values (no encoding)
  592.  *
  593.  * Returns an copy of the string, but unescaped
  594.  */
  595. char *
  596. xmlURIUnescapeString(const char *str, int len, char *target) {
  597.     char *ret, *out;
  598.     const char *in;
  599.     if (str == NULL)
  600. return(NULL);
  601.     if (len <= 0) len = strlen(str);
  602.     if (len <= 0) return(NULL);
  603.     if (target == NULL) {
  604. ret = (char *) xmlMalloc(len + 1);
  605. if (ret == NULL) {
  606.     fprintf(stderr, "xmlURIUnescapeString: out of memoryn");
  607.     return(NULL);
  608. }
  609.     } else
  610. ret = target;
  611.     in = str;
  612.     out = ret;
  613.     while(len > 0) {
  614. if (*in == '%') {
  615.     in++;
  616.     if ((*in >= '0') && (*in <= '9')) 
  617.         *out = (*in - '0');
  618.     else if ((*in >= 'a') && (*in <= 'f'))
  619.         *out = (*in - 'a') + 10;
  620.     else if ((*in >= 'A') && (*in <= 'F'))
  621.         *out = (*in - 'A') + 10;
  622.     in++;
  623.     if ((*in >= '0') && (*in <= '9')) 
  624.         *out = *out * 16 + (*in - '0');
  625.     else if ((*in >= 'a') && (*in <= 'f'))
  626.         *out = *out * 16 + (*in - 'a') + 10;
  627.     else if ((*in >= 'A') && (*in <= 'F'))
  628.         *out = *out * 16 + (*in - 'A') + 10;
  629.     in++;
  630.     len -= 3;
  631.     out++;
  632. } else {
  633.     *out++ = *in++;
  634.     len--;
  635. }
  636.     }
  637.     *out = 0;
  638.     return(ret);
  639. }
  640. /**
  641.  * xmlParseURIFragment:
  642.  * @uri:  pointer to an URI structure
  643.  * @str:  pointer to the string to analyze
  644.  *
  645.  * Parse an URI fragment string and fills in the appropriate fields
  646.  * of the @uri structure.
  647.  * 
  648.  * fragment = *uric
  649.  *
  650.  * Returns 0 or the error code
  651.  */
  652. int
  653. xmlParseURIFragment(xmlURIPtr uri, const char **str) {
  654.     const char *cur = *str;
  655.     if (str == NULL) return(-1);
  656.     while (IS_URIC(cur)) NEXT(cur);
  657.     if (uri != NULL) {
  658. if (uri->fragment != NULL) xmlFree(uri->fragment);
  659. uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
  660.     }
  661.     *str = cur;
  662.     return(0);
  663. }
  664. /**
  665.  * xmlParseURIQuery:
  666.  * @uri:  pointer to an URI structure
  667.  * @str:  pointer to the string to analyze
  668.  *
  669.  * Parse the query part of an URI
  670.  * 
  671.  * query = *uric
  672.  *
  673.  * Returns 0 or the error code
  674.  */
  675. int
  676. xmlParseURIQuery(xmlURIPtr uri, const char **str) {
  677.     const char *cur = *str;
  678.     if (str == NULL) return(-1);
  679.     while (IS_URIC(cur)) NEXT(cur);
  680.     if (uri != NULL) {
  681. if (uri->query != NULL) xmlFree(uri->query);
  682. uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
  683.     }
  684.     *str = cur;
  685.     return(0);
  686. }
  687. /**
  688.  * xmlParseURIScheme:
  689.  * @uri:  pointer to an URI structure
  690.  * @str:  pointer to the string to analyze
  691.  *
  692.  * Parse an URI scheme
  693.  * 
  694.  * scheme = alpha *( alpha | digit | "+" | "-" | "." )
  695.  *
  696.  * Returns 0 or the error code
  697.  */
  698. int
  699. xmlParseURIScheme(xmlURIPtr uri, const char **str) {
  700.     const char *cur;
  701.     if (str == NULL)
  702. return(-1);
  703.     
  704.     cur = *str;
  705.     if (!IS_ALPHA(*cur))
  706. return(2);
  707.     cur++;
  708.     while (IS_SCHEME(*cur)) cur++;
  709.     if (uri != NULL) {
  710. if (uri->scheme != NULL) xmlFree(uri->scheme);
  711. uri->scheme = xmlURIUnescapeString(*str, cur - *str, NULL); /* !!! strndup */
  712.     }
  713.     *str = cur;
  714.     return(0);
  715. }
  716. /**
  717.  * xmlParseURIOpaquePart:
  718.  * @uri:  pointer to an URI structure
  719.  * @str:  pointer to the string to analyze
  720.  *
  721.  * Parse an URI opaque part
  722.  * 
  723.  * opaque_part = uric_no_slash *uric
  724.  *
  725.  * Returns 0 or the error code
  726.  */
  727. int
  728. xmlParseURIOpaquePart(xmlURIPtr uri, const char **str) {
  729.     const char *cur;
  730.     if (str == NULL)
  731. return(-1);
  732.     
  733.     cur = *str;
  734.     if (!IS_URIC_NO_SLASH(cur)) {
  735. return(3);
  736.     }
  737.     NEXT(cur);
  738.     while (IS_URIC(cur)) NEXT(cur);
  739.     if (uri != NULL) {
  740. if (uri->opaque != NULL) xmlFree(uri->opaque);
  741. uri->opaque = xmlURIUnescapeString(*str, cur - *str, NULL);
  742.     }
  743.     *str = cur;
  744.     return(0);
  745. }
  746. /**
  747.  * xmlParseURIServer:
  748.  * @uri:  pointer to an URI structure
  749.  * @str:  pointer to the string to analyze
  750.  *
  751.  * Parse a server subpart of an URI, it's a finer grain analysis
  752.  * of the authority part.
  753.  * 
  754.  * server        = [ [ userinfo "@" ] hostport ]
  755.  * userinfo      = *( unreserved | escaped |
  756.  *                       ";" | ":" | "&" | "=" | "+" | "$" | "," )
  757.  * hostport      = host [ ":" port ]
  758.  * host          = hostname | IPv4address
  759.  * hostname      = *( domainlabel "." ) toplabel [ "." ]
  760.  * domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
  761.  * toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
  762.  * IPv4address   = 1*digit "." 1*digit "." 1*digit "." 1*digit
  763.  * port          = *digit
  764.  *
  765.  * Returns 0 or the error code
  766.  */
  767. int
  768. xmlParseURIServer(xmlURIPtr uri, const char **str) {
  769.     const char *cur;
  770.     const char *host, *tmp;
  771.     if (str == NULL)
  772. return(-1);
  773.     
  774.     cur = *str;
  775.     /*
  776.      * is there an userinfo ?
  777.      */
  778.     while (IS_USERINFO(cur)) NEXT(cur);
  779.     if (*cur == '@') {
  780. if (uri != NULL) {
  781.     if (uri->user != NULL) xmlFree(uri->user);
  782.     uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
  783. }
  784. cur++;
  785.     } else {
  786. if (uri != NULL) {
  787.     if (uri->user != NULL) xmlFree(uri->user);
  788.     uri->user = NULL;
  789. }
  790.         cur = *str;
  791.     }
  792.     /*
  793.      * host part of hostport can derive either an IPV4 address
  794.      * or an unresolved name. Check the IP first, it easier to detect
  795.      * errors if wrong one
  796.      */
  797.     host = cur;
  798.     if (IS_DIGIT(*cur)) {
  799.         while(IS_DIGIT(*cur)) cur++;
  800. if (*cur != '.')
  801.     goto host_name;
  802. cur++;
  803. if (!IS_DIGIT(*cur))
  804.     goto host_name;
  805.         while(IS_DIGIT(*cur)) cur++;
  806. if (*cur != '.')
  807.     goto host_name;
  808. cur++;
  809. if (!IS_DIGIT(*cur))
  810.     goto host_name;
  811.         while(IS_DIGIT(*cur)) cur++;
  812. if (*cur != '.')
  813.     goto host_name;
  814. cur++;
  815. if (!IS_DIGIT(*cur))
  816.     goto host_name;
  817.         while(IS_DIGIT(*cur)) cur++;
  818. if (uri != NULL) {
  819.     if (uri->authority != NULL) xmlFree(uri->authority);
  820.     uri->authority = NULL;
  821.     if (uri->server != NULL) xmlFree(uri->server);
  822.     uri->server = xmlURIUnescapeString(host, cur - host, NULL);
  823. }
  824. goto host_done;
  825.     }
  826. host_name:
  827.     /*
  828.      * the hostname production as-is is a parser nightmare.
  829.      * simplify it to 
  830.      * hostname = *( domainlabel "." ) domainlabel [ "." ]
  831.      * and just make sure the last label starts with a non numeric char.
  832.      */
  833.     if (!IS_ALPHANUM(*cur))
  834.         return(6);
  835.     while (IS_ALPHANUM(*cur)) {
  836.         while ((IS_ALPHANUM(*cur)) || (*cur == '-')) cur++;
  837. if (*cur == '.')
  838.     cur++;
  839.     }
  840.     tmp = cur;
  841.     tmp--;
  842.     while (IS_ALPHANUM(*tmp) && (*tmp != '.') && (tmp >= host)) tmp--;
  843.     tmp++;
  844.     if (!IS_ALPHA(*tmp))
  845.         return(7);
  846.     if (uri != NULL) {
  847. if (uri->authority != NULL) xmlFree(uri->authority);
  848. uri->authority = NULL;
  849. if (uri->server != NULL) xmlFree(uri->server);
  850. uri->server = xmlURIUnescapeString(host, cur - host, NULL);
  851.     }
  852. host_done:
  853.     /*
  854.      * finish by checking for a port presence.
  855.      */
  856.     if (*cur == ':') {
  857.         cur++;
  858. if (IS_DIGIT(*cur)) {
  859.     if (uri != NULL)
  860.         uri->port = 0;
  861.     while (IS_DIGIT(*cur)) {
  862.         if (uri != NULL)
  863.     uri->port = uri->port * 10 + (*cur - '0');
  864. cur++;
  865.     }
  866. }
  867.     }
  868.     *str = cur;
  869.     return(0);
  870. }
  871. /**
  872.  * xmlParseURIRelSegment:
  873.  * @uri:  pointer to an URI structure
  874.  * @str:  pointer to the string to analyze
  875.  *
  876.  * Parse an URI relative segment
  877.  * 
  878.  * rel_segment = 1*( unreserved | escaped | ";" | "@" | "&" | "=" |
  879.  *                          "+" | "$" | "," )
  880.  *
  881.  * Returns 0 or the error code
  882.  */
  883. int
  884. xmlParseURIRelSegment(xmlURIPtr uri, const char **str) {
  885.     const char *cur;
  886.     if (str == NULL)
  887. return(-1);
  888.     
  889.     cur = *str;
  890.     if (!IS_SEGMENT(cur)) {
  891. return(3);
  892.     }
  893.     NEXT(cur);
  894.     while (IS_SEGMENT(cur)) NEXT(cur);
  895.     if (uri != NULL) {
  896. if (uri->path != NULL) xmlFree(uri->path);
  897. uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
  898.     }
  899.     *str = cur;
  900.     return(0);
  901. }
  902. /**
  903.  * xmlParseURIPathSegments:
  904.  * @uri:  pointer to an URI structure
  905.  * @str:  pointer to the string to analyze
  906.  * @slash:  should we add a leading slash
  907.  *
  908.  * Parse an URI set of path segments
  909.  * 
  910.  * path_segments = segment *( "/" segment )
  911.  * segment       = *pchar *( ";" param )
  912.  * param         = *pchar
  913.  *
  914.  * Returns 0 or the error code
  915.  */
  916. int
  917. xmlParseURIPathSegments(xmlURIPtr uri, const char **str, int slash) {
  918.     const char *cur;
  919.     if (str == NULL)
  920. return(-1);
  921.     
  922.     cur = *str;
  923.     do {
  924. while (IS_PCHAR(cur)) NEXT(cur);
  925. if (*cur == ';') {
  926.     cur++;
  927.     while (IS_PCHAR(cur)) NEXT(cur);
  928. }
  929. if (*cur != '/') break;
  930. cur++;
  931.     } while (1);
  932.     if (uri != NULL) {
  933. int len, len2 = 0;
  934. char *path;
  935. /*
  936.  * Concat the set of path segments to the current path
  937.  */
  938. len = cur - *str;
  939. if (slash)
  940.     len++;
  941. if (uri->path != NULL) {
  942.     len2 = strlen(uri->path);
  943.     len += len2;
  944. }
  945.         path = (char *) xmlMalloc(len + 1);
  946. if (path == NULL) {
  947.     fprintf(stderr, "xmlParseURIPathSegments: out of memoryn");
  948.     *str = cur;
  949.     return(-1);
  950. }
  951. if (uri->path != NULL)
  952.     memcpy(path, uri->path, len2);
  953. if (slash) {
  954.     path[len2] = '/';
  955.     len2++;
  956. }
  957. xmlURIUnescapeString(*str, cur - *str, &path[len2]);
  958. if (uri->path != NULL)
  959.     xmlFree(uri->path);
  960. uri->path = path;
  961.     }
  962.     *str = cur;
  963.     return(0);
  964. }
  965. /**
  966.  * xmlParseURIAuthority:
  967.  * @uri:  pointer to an URI structure
  968.  * @str:  pointer to the string to analyze
  969.  *
  970.  * Parse the authority part of an URI.
  971.  * 
  972.  * authority = server | reg_name
  973.  * server    = [ [ userinfo "@" ] hostport ]
  974.  * reg_name  = 1*( unreserved | escaped | "$" | "," | ";" | ":" |
  975.  *                        "@" | "&" | "=" | "+" )
  976.  *
  977.  * Note : this is completely ambiguous since reg_name is allowed to
  978.  *        use the full set of chars in use by server:
  979.  *
  980.  *        3.2.1. Registry-based Naming Authority
  981.  *
  982.  *        The structure of a registry-based naming authority is specific
  983.  *        to the URI scheme, but constrained to the allowed characters
  984.  *        for an authority component.
  985.  *
  986.  * Returns 0 or the error code
  987.  */
  988. int
  989. xmlParseURIAuthority(xmlURIPtr uri, const char **str) {
  990.     const char *cur;
  991.     int ret;
  992.     if (str == NULL)
  993. return(-1);
  994.     
  995.     cur = *str;
  996.     /*
  997.      * try first to parse it as a server string.
  998.      */
  999.     ret = xmlParseURIServer(uri, str);
  1000.     if (ret == 0)
  1001.         return(0);
  1002.     /*
  1003.      * failed, fallback to reg_name
  1004.      */
  1005.     if (!IS_REG_NAME(cur)) {
  1006. return(5);
  1007.     }
  1008.     NEXT(cur);
  1009.     while (IS_REG_NAME(cur)) NEXT(cur);
  1010.     if (uri != NULL) {
  1011. if (uri->server != NULL) xmlFree(uri->server);
  1012. uri->server = NULL;
  1013. if (uri->user != NULL) xmlFree(uri->user);
  1014. uri->user = NULL;
  1015. if (uri->authority != NULL) xmlFree(uri->authority);
  1016. uri->authority = xmlURIUnescapeString(*str, cur - *str, NULL);
  1017.     }
  1018.     *str = cur;
  1019.     return(0);
  1020. }
  1021. /**
  1022.  * xmlParseURIHierPart:
  1023.  * @uri:  pointer to an URI structure
  1024.  * @str:  pointer to the string to analyze
  1025.  *
  1026.  * Parse an URI hirarchical part
  1027.  * 
  1028.  * hier_part = ( net_path | abs_path ) [ "?" query ]
  1029.  * abs_path = "/"  path_segments
  1030.  * net_path = "//" authority [ abs_path ]
  1031.  *
  1032.  * Returns 0 or the error code
  1033.  */
  1034. int
  1035. xmlParseURIHierPart(xmlURIPtr uri, const char **str) {
  1036.     int ret;
  1037.     const char *cur;
  1038.     if (str == NULL)
  1039. return(-1);
  1040.     
  1041.     cur = *str;
  1042.     if ((cur[0] == '/') && (cur[1] == '/')) {
  1043. cur += 2;
  1044. ret = xmlParseURIAuthority(uri, &cur);
  1045. if (ret != 0)
  1046.     return(ret);
  1047. if (cur[0] == '/') {
  1048.     cur++;
  1049.     ret = xmlParseURIPathSegments(uri, &cur, 1);
  1050. }
  1051.     } else if (cur[0] == '/') {
  1052. cur++;
  1053. ret = xmlParseURIPathSegments(uri, &cur, 1);
  1054.     } else {
  1055. return(4);
  1056.     }
  1057.     if (ret != 0)
  1058. return(ret);
  1059.     if (*cur == '?') {
  1060. cur++;
  1061. ret = xmlParseURIQuery(uri, &cur);
  1062. if (ret != 0)
  1063.     return(ret);
  1064.     }
  1065.     *str = cur;
  1066.     return(0);
  1067. }
  1068. /**
  1069.  * xmlParseAbsoluteURI:
  1070.  * @uri:  pointer to an URI structure
  1071.  * @str:  pointer to the string to analyze
  1072.  *
  1073.  * Parse an URI reference string and fills in the appropriate fields
  1074.  * of the @uri structure
  1075.  * 
  1076.  * absoluteURI   = scheme ":" ( hier_part | opaque_part )
  1077.  *
  1078.  * Returns 0 or the error code
  1079.  */
  1080. int
  1081. xmlParseAbsoluteURI(xmlURIPtr uri, const char **str) {
  1082.     int ret;
  1083.     if (str == NULL)
  1084. return(-1);
  1085.     
  1086.     ret = xmlParseURIScheme(uri, str);
  1087.     if (ret != 0) return(ret);
  1088.     if (**str != ':')
  1089. return(1);
  1090.     (*str)++;
  1091.     if (**str == '/')
  1092. return(xmlParseURIHierPart(uri, str));
  1093.     return(xmlParseURIOpaquePart(uri, str));
  1094. }
  1095. /**
  1096.  * xmlParseRelativeURI:
  1097.  * @uri:  pointer to an URI structure
  1098.  * @str:  pointer to the string to analyze
  1099.  *
  1100.  * Parse an relative URI string and fills in the appropriate fields
  1101.  * of the @uri structure
  1102.  * 
  1103.  * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
  1104.  * abs_path = "/"  path_segments
  1105.  * net_path = "//" authority [ abs_path ]
  1106.  * rel_path = rel_segment [ abs_path ]
  1107.  *
  1108.  * Returns 0 or the error code
  1109.  */
  1110. int
  1111. xmlParseRelativeURI(xmlURIPtr uri, const char **str) {
  1112.     int ret = 0;
  1113.     const char *cur;
  1114.     if (str == NULL)
  1115. return(-1);
  1116.     
  1117.     cur = *str;
  1118.     if ((cur[0] == '/') && (cur[1] == '/')) {
  1119. cur += 2;
  1120. ret = xmlParseURIAuthority(uri, &cur);
  1121. if (ret != 0)
  1122.     return(ret);
  1123. if (cur[0] == '/') {
  1124.     cur++;
  1125.     ret = xmlParseURIPathSegments(uri, &cur, 1);
  1126. }
  1127.     } else if (cur[0] == '/') {
  1128. cur++;
  1129. ret = xmlParseURIPathSegments(uri, &cur, 1);
  1130.     } else {
  1131. ret = xmlParseURIRelSegment(uri, &cur);
  1132. if (ret != 0)
  1133.     return(ret);
  1134. if (cur[0] == '/') {
  1135.     cur++;
  1136.     ret = xmlParseURIPathSegments(uri, &cur, 1);
  1137. }
  1138.     }
  1139.     if (ret != 0)
  1140. return(ret);
  1141.     if (*cur == '?') {
  1142. cur++;
  1143. ret = xmlParseURIQuery(uri, &cur);
  1144. if (ret != 0)
  1145.     return(ret);
  1146.     }
  1147.     *str = cur;
  1148.     return(ret);
  1149. }
  1150. /**
  1151.  * xmlParseURIReference:
  1152.  * @uri:  pointer to an URI structure
  1153.  * @str:  the string to analyze
  1154.  *
  1155.  * Parse an URI reference string and fills in the appropriate fields
  1156.  * of the @uri structure
  1157.  * 
  1158.  * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
  1159.  *
  1160.  * Returns 0 or the error code
  1161.  */
  1162. int
  1163. xmlParseURIReference(xmlURIPtr uri, const char *str) {
  1164.     int ret;
  1165.     const char *tmp = str;
  1166.     if (str == NULL)
  1167. return(-1);
  1168.     xmlCleanURI(uri);
  1169.     /*
  1170.      * Try first to parse aboslute refs, then fallback to relative if
  1171.      * it fails.
  1172.      */
  1173.     ret = xmlParseAbsoluteURI(uri, &str);
  1174.     if (ret != 0) {
  1175. xmlCleanURI(uri);
  1176. str = tmp;
  1177.         ret = xmlParseRelativeURI(uri, &str);
  1178.     }
  1179.     if (ret != 0) {
  1180. xmlCleanURI(uri);
  1181. return(ret);
  1182.     }
  1183.     if (*str == '#') {
  1184. str++;
  1185. ret = xmlParseURIFragment(uri, &str);
  1186. if (ret != 0) return(ret);
  1187.     }
  1188.     if (*str != 0) {
  1189. xmlCleanURI(uri);
  1190. return(1);
  1191.     }
  1192.     return(0);
  1193. }
  1194. /**
  1195.  * xmlNormalizeURIPath:
  1196.  * @path:  pointer to the path string
  1197.  *
  1198.  * applies the 5 normalization steps to a path string
  1199.  * Normalization occurs directly on the string, no new allocation is done
  1200.  *
  1201.  * Returns 0 or an error code
  1202.  */
  1203. int
  1204. xmlNormalizeURIPath(char *path) {
  1205.     int cur, out;
  1206.     if (path == NULL)
  1207. return(-1);
  1208.     cur = 0;
  1209.     out = 0;
  1210.     while ((path[cur] != 0) && (path[cur] != '/')) cur++;
  1211.     if (path[cur] == 0)
  1212. return(0);
  1213.     /* we are positionned at the beginning of the first segment */
  1214.     cur++;
  1215.     out = cur;
  1216.     /*
  1217.      * Analyze each segment in sequence.
  1218.      */
  1219.     while (path[cur] != 0) {
  1220. /*
  1221.  * c) All occurrences of "./", where "." is a complete path segment,
  1222.  *    are removed from the buffer string.
  1223.  */
  1224. if ((path[cur] == '.') && (path[cur + 1] == '/')) {
  1225.     cur += 2;
  1226.     continue;
  1227. }
  1228. /*
  1229.  * d) If the buffer string ends with "." as a complete path segment,
  1230.  *    that "." is removed.
  1231.  */
  1232. if ((path[cur] == '.') && (path[cur + 1] == 0)) {
  1233.     path[out] = 0;
  1234.     break;
  1235. }
  1236. /* read the segment */
  1237. while ((path[cur] != 0) && (path[cur] != '/')) {
  1238.     path[out++] = path[cur++];
  1239. }
  1240. path[out++] = path[cur];
  1241. if (path[cur] != 0) {
  1242.     cur++;
  1243. }
  1244.     }
  1245.     cur = 0;
  1246.     out = 0;
  1247.     while ((path[cur] != 0) && (path[cur] != '/')) cur++;
  1248.     if (path[cur] == 0)
  1249. return(0);
  1250.     /* we are positionned at the beginning of the first segment */
  1251.     cur++;
  1252.     out = cur;
  1253.     /*
  1254.      * Analyze each segment in sequence.
  1255.      */
  1256.     while (path[cur] != 0) {
  1257. /*
  1258.  * e) All occurrences of "<segment>/../", where <segment> is a
  1259.  *    complete path segment not equal to "..", are removed from the
  1260.  *    buffer string.  Removal of these path segments is performed
  1261.  *    iteratively, removing the leftmost matching pattern on each
  1262.  *    iteration, until no matching pattern remains.
  1263.  */
  1264. if ((cur > 1) && (out > 1) &&
  1265.     (path[cur] == '/') && (path[cur + 1] == '.') &&
  1266.     (path[cur + 2] == '.') && (path[cur + 3] == '/') &&
  1267.     ((path[out] != '.') || (path[out - 1] != '.') ||
  1268.      (path[out - 2] != '/'))) {
  1269.     cur += 3;
  1270.     out --;
  1271.     while ((out > 0) && (path[out] != '/')) { out --; }
  1272.     path[out] = 0;
  1273.             continue;
  1274. }
  1275. /*
  1276.  * f) If the buffer string ends with "<segment>/..", where <segment>
  1277.  *    is a complete path segment not equal to "..", that
  1278.  *    "<segment>/.." is removed.
  1279.  */
  1280. if ((path[cur] == '/') && (path[cur + 1] == '.') &&
  1281.     (path[cur + 2] == '.') && (path[cur + 3] == 0) &&
  1282.     ((path[out] != '.') || (path[out - 1] != '.') ||
  1283.      (path[out - 2] != '/'))) {
  1284.     cur += 4;
  1285.     out --;
  1286.     while ((out > 0) && (path[out - 1] != '/')) { out --; }
  1287.     path[out] = 0;
  1288.             continue;
  1289. }
  1290.         
  1291. path[out++] = path[cur++]; /* / or 0 */
  1292.     }
  1293.     path[out] = 0;
  1294.     /*
  1295.      * g) If the resulting buffer string still begins with one or more
  1296.      *    complete path segments of "..", then the reference is 
  1297.      *    considered to be in error. Implementations may handle this
  1298.      *    error by retaining these components in the resolved path (i.e.,
  1299.      *    treating them as part of the final URI), by removing them from
  1300.      *    the resolved path (i.e., discarding relative levels above the
  1301.      *    root), or by avoiding traversal of the reference.
  1302.      *
  1303.      * We discard them from the final path.
  1304.      */
  1305.     cur = 0;
  1306.     while ((path[cur] == '/') && (path[cur + 1] == '.') &&
  1307.    (path[cur + 2] == '.'))
  1308. cur += 3;
  1309.     if (cur != 0) {
  1310. out = 0;
  1311. while (path[cur] != 0) path[out++] = path[cur++];
  1312. path[out] = 0;
  1313.     }
  1314.     return(0);
  1315. }
  1316. /**
  1317.  * xmlBuildURI:
  1318.  * @URI:  the URI instance found in the document
  1319.  * @base:  the base value
  1320.  *
  1321.  * Computes he final URI of the reference done by checking that
  1322.  * the given URI is valid, and building the final URI using the
  1323.  * base URI. This is processed according to section 5.2 of the 
  1324.  * RFC 2396
  1325.  *
  1326.  * 5.2. Resolving Relative References to Absolute Form
  1327.  *
  1328.  * Returns a new URI string (to be freed by the caller) or NULL in case
  1329.  *         of error.
  1330.  */
  1331. xmlChar *
  1332. xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
  1333.     xmlChar *val = NULL;
  1334.     int ret, len, index, cur, out;
  1335.     xmlURIPtr ref = NULL;
  1336.     xmlURIPtr bas = NULL;
  1337.     xmlURIPtr res = NULL;
  1338.     /*
  1339.      * 1) The URI reference is parsed into the potential four components and
  1340.      *    fragment identifier, as described in Section 4.3.
  1341.      */
  1342.     ref = xmlCreateURI();
  1343.     if (ref == NULL)
  1344. goto done;
  1345.     ret = xmlParseURIReference(ref, (const char *) URI);
  1346.     if (ret != 0)
  1347. goto done;
  1348.     bas = xmlCreateURI();
  1349.     if (bas == NULL)
  1350. goto done;
  1351.     ret = xmlParseURIReference(bas, (const char *) base);
  1352.     if (ret != 0)
  1353. goto done;
  1354.     /*
  1355.      * 2) If the path component is empty and the scheme, authority, and
  1356.      *    query components are undefined, then it is a reference to the
  1357.      *    current document and we are done.  Otherwise, the reference URI's
  1358.      *    query and fragment components are defined as found (or not found)
  1359.      *    within the URI reference and not inherited from the base URI.
  1360.      */
  1361.     res = xmlCreateURI();
  1362.     if (res == NULL)
  1363. goto done;
  1364.     if ((ref->scheme == NULL) && (ref->path == NULL) &&
  1365. ((ref->authority == NULL) && (ref->server == NULL)) &&
  1366. (ref->query == NULL)) {
  1367. if (ref->fragment == NULL)
  1368.     goto done;
  1369.         res->fragment = xmlMemStrdup(ref->fragment);
  1370. val = xmlSaveUri(res);
  1371. goto done;
  1372.     }
  1373.     /*
  1374.      * 3) If the scheme component is defined, indicating that the reference
  1375.      *    starts with a scheme name, then the reference is interpreted as an
  1376.      *    absolute URI and we are done.  Otherwise, the reference URI's
  1377.      *    scheme is inherited from the base URI's scheme component.
  1378.      */
  1379.     if (ref->scheme != NULL) {
  1380. val = xmlSaveUri(ref);
  1381. goto done;
  1382.     }
  1383.     res->scheme = xmlMemStrdup(bas->scheme);
  1384.     /*
  1385.      * 4) If the authority component is defined, then the reference is a
  1386.      *    network-path and we skip to step 7.  Otherwise, the reference
  1387.      *    URI's authority is inherited from the base URI's authority
  1388.      *    component, which will also be undefined if the URI scheme does not
  1389.      *    use an authority component.
  1390.      */
  1391.     if ((ref->authority != NULL) || (ref->server != NULL)) {
  1392. if (ref->authority != NULL)
  1393.     res->authority = xmlMemStrdup(ref->authority);
  1394. else {
  1395.     res->server = xmlMemStrdup(ref->server);
  1396.     if (ref->user != NULL)
  1397. res->user = xmlMemStrdup(ref->user);
  1398.             res->port = ref->port;
  1399. }
  1400. if (ref->path != NULL)
  1401.     res->path = xmlMemStrdup(ref->path);
  1402. if (ref->query != NULL)
  1403.     res->query = xmlMemStrdup(ref->query);
  1404. if (ref->fragment != NULL)
  1405.     res->fragment = xmlMemStrdup(ref->fragment);
  1406. goto step_7;
  1407.     }
  1408.     if (bas->authority != NULL)
  1409. res->authority = xmlMemStrdup(bas->authority);
  1410.     else if (bas->server != NULL) {
  1411. res->server = xmlMemStrdup(bas->server);
  1412. if (bas->user != NULL)
  1413.     res->user = xmlMemStrdup(bas->user);
  1414. res->port = bas->port;
  1415.     }
  1416.     /*
  1417.      * 5) If the path component begins with a slash character ("/"), then
  1418.      *    the reference is an absolute-path and we skip to step 7.
  1419.      */
  1420.     if ((ref->path != NULL) && (ref->path[0] == '/')) {
  1421. res->path = xmlMemStrdup(ref->path);
  1422. if (ref->query != NULL)
  1423.     res->query = xmlMemStrdup(ref->query);
  1424. if (ref->fragment != NULL)
  1425.     res->fragment = xmlMemStrdup(ref->fragment);
  1426. goto step_7;
  1427.     }
  1428.     /*
  1429.      * 6) If this step is reached, then we are resolving a relative-path
  1430.      *    reference.  The relative path needs to be merged with the base
  1431.      *    URI's path.  Although there are many ways to do this, we will
  1432.      *    describe a simple method using a separate string buffer.
  1433.      *
  1434.      * Allocate a buffer large enough for the result string.
  1435.      */
  1436.     len = 2; /* extra / and 0 */
  1437.     if (ref->path != NULL)
  1438. len += strlen(ref->path);
  1439.     if (bas->path != NULL)
  1440. len += strlen(bas->path);
  1441.     res->path = (char *) xmlMalloc(len);
  1442.     if (res->path == NULL) {
  1443. fprintf(stderr, "xmlBuildURI: out of memoryn");
  1444. goto done;
  1445.     }
  1446.     res->path[0] = 0;
  1447.     /*
  1448.      * a) All but the last segment of the base URI's path component is
  1449.      *    copied to the buffer.  In other words, any characters after the
  1450.      *    last (right-most) slash character, if any, are excluded.
  1451.      */
  1452.     cur = 0;
  1453.     out = 0;
  1454.     if (bas->path != NULL) {
  1455. while (bas->path[cur] != 0) {
  1456.     while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
  1457. cur++;
  1458.     if (bas->path[cur] == 0)
  1459. break;
  1460.     cur++;
  1461.     while (out < cur) {
  1462. res->path[out] = bas->path[out];
  1463. out++;
  1464.     }
  1465. }
  1466.     }
  1467.     res->path[out] = 0;
  1468.     /*
  1469.      * b) The reference's path component is appended to the buffer
  1470.      *    string.
  1471.      */
  1472.     if (ref->path != NULL) {
  1473. index = 0;
  1474. while (ref->path[index] != 0) {
  1475.     res->path[out++] = ref->path[index++];
  1476. }
  1477.     }
  1478.     res->path[out] = 0;
  1479.     /*
  1480.      * Steps c) to h) are really path normalization steps
  1481.      */
  1482.     xmlNormalizeURIPath(res->path);
  1483. step_7:
  1484.     /*
  1485.      * 7) The resulting URI components, including any inherited from the
  1486.      *    base URI, are recombined to give the absolute form of the URI
  1487.      *    reference.
  1488.      */
  1489.     val = xmlSaveUri(res);
  1490. done:
  1491.     if (ref != NULL)
  1492. xmlFreeURI(ref);
  1493.     if (base != NULL)
  1494. xmlFreeURI(bas);
  1495.     if (res != NULL)
  1496. xmlFreeURI(res);
  1497.     return(val);
  1498. }