uri.c 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574
  1. /**
  2. * uri.c: set of generic URI related routines
  3. *
  4. * Reference: RFCs 3986, 2732 and 2373
  5. *
  6. * See Copyright for the status of this software.
  7. *
  8. * daniel@veillard.com
  9. */
  10. #define IN_LIBXML
  11. #include "libxml.h"
  12. #include <limits.h>
  13. #include <string.h>
  14. #include <libxml/xmlmemory.h>
  15. #include <libxml/uri.h>
  16. #include <libxml/xmlerror.h>
  17. #include "private/error.h"
  18. /**
  19. * MAX_URI_LENGTH:
  20. *
  21. * The definition of the URI regexp in the above RFC has no size limit
  22. * In practice they are usually relatively short except for the
  23. * data URI scheme as defined in RFC 2397. Even for data URI the usual
  24. * maximum size before hitting random practical limits is around 64 KB
  25. * and 4KB is usually a maximum admitted limit for proper operations.
  26. * The value below is more a security limit than anything else and
  27. * really should never be hit by 'normal' operations
  28. * Set to 1 MByte in 2012, this is only enforced on output
  29. */
  30. #define MAX_URI_LENGTH 1024 * 1024
  31. #define PORT_EMPTY 0
  32. #define PORT_EMPTY_SERVER -1
  33. static void
  34. xmlURIErrMemory(const char *extra)
  35. {
  36. if (extra)
  37. __xmlRaiseError(NULL, NULL, NULL,
  38. NULL, NULL, XML_FROM_URI,
  39. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  40. extra, NULL, NULL, 0, 0,
  41. "Memory allocation failed : %s\n", extra);
  42. else
  43. __xmlRaiseError(NULL, NULL, NULL,
  44. NULL, NULL, XML_FROM_URI,
  45. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  46. NULL, NULL, NULL, 0, 0,
  47. "Memory allocation failed\n");
  48. }
  49. static void xmlCleanURI(xmlURIPtr uri);
  50. /*
  51. * Old rule from 2396 used in legacy handling code
  52. * alpha = lowalpha | upalpha
  53. */
  54. #define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
  55. /*
  56. * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
  57. * "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
  58. * "u" | "v" | "w" | "x" | "y" | "z"
  59. */
  60. #define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
  61. /*
  62. * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
  63. * "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
  64. * "U" | "V" | "W" | "X" | "Y" | "Z"
  65. */
  66. #define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
  67. #ifdef IS_DIGIT
  68. #undef IS_DIGIT
  69. #endif
  70. /*
  71. * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
  72. */
  73. #define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
  74. /*
  75. * alphanum = alpha | digit
  76. */
  77. #define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
  78. /*
  79. * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
  80. */
  81. #define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') || \
  82. ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') || \
  83. ((x) == '(') || ((x) == ')'))
  84. /*
  85. * unwise = "{" | "}" | "|" | "\" | "^" | "`"
  86. */
  87. #define IS_UNWISE(p) \
  88. (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) || \
  89. ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) || \
  90. ((*(p) == ']')) || ((*(p) == '`')))
  91. /*
  92. * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
  93. * "[" | "]"
  94. */
  95. #define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
  96. ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
  97. ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
  98. ((x) == ']'))
  99. /*
  100. * unreserved = alphanum | mark
  101. */
  102. #define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
  103. /*
  104. * Skip to next pointer char, handle escaped sequences
  105. */
  106. #define NEXT(p) ((*p == '%')? p += 3 : p++)
  107. /*
  108. * Productions from the spec.
  109. *
  110. * authority = server | reg_name
  111. * reg_name = 1*( unreserved | escaped | "$" | "," |
  112. * ";" | ":" | "@" | "&" | "=" | "+" )
  113. *
  114. * path = [ abs_path | opaque_part ]
  115. */
  116. #define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n))
  117. /************************************************************************
  118. * *
  119. * RFC 3986 parser *
  120. * *
  121. ************************************************************************/
  122. #define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9'))
  123. #define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) || \
  124. ((*(p) >= 'A') && (*(p) <= 'Z')))
  125. #define ISA_HEXDIG(p) \
  126. (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) || \
  127. ((*(p) >= 'A') && (*(p) <= 'F')))
  128. /*
  129. * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
  130. * / "*" / "+" / "," / ";" / "="
  131. */
  132. #define ISA_SUB_DELIM(p) \
  133. (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) || \
  134. ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) || \
  135. ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) || \
  136. ((*(p) == '=')) || ((*(p) == '\'')))
  137. /*
  138. * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
  139. */
  140. #define ISA_GEN_DELIM(p) \
  141. (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) || \
  142. ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) || \
  143. ((*(p) == '@')))
  144. /*
  145. * reserved = gen-delims / sub-delims
  146. */
  147. #define ISA_RESERVED(p) (ISA_GEN_DELIM(p) || (ISA_SUB_DELIM(p)))
  148. /*
  149. * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
  150. */
  151. #define ISA_UNRESERVED(p) \
  152. ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) || \
  153. ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
  154. /*
  155. * pct-encoded = "%" HEXDIG HEXDIG
  156. */
  157. #define ISA_PCT_ENCODED(p) \
  158. ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
  159. /*
  160. * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
  161. */
  162. #define ISA_PCHAR(p) \
  163. (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \
  164. ((*(p) == ':')) || ((*(p) == '@')))
  165. /**
  166. * xmlParse3986Scheme:
  167. * @uri: pointer to an URI structure
  168. * @str: pointer to the string to analyze
  169. *
  170. * Parse an URI scheme
  171. *
  172. * ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
  173. *
  174. * Returns 0 or the error code
  175. */
  176. static int
  177. xmlParse3986Scheme(xmlURIPtr uri, const char **str) {
  178. const char *cur;
  179. if (str == NULL)
  180. return(-1);
  181. cur = *str;
  182. if (!ISA_ALPHA(cur))
  183. return(2);
  184. cur++;
  185. while (ISA_ALPHA(cur) || ISA_DIGIT(cur) ||
  186. (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++;
  187. if (uri != NULL) {
  188. if (uri->scheme != NULL) xmlFree(uri->scheme);
  189. uri->scheme = STRNDUP(*str, cur - *str);
  190. }
  191. *str = cur;
  192. return(0);
  193. }
  194. /**
  195. * xmlParse3986Fragment:
  196. * @uri: pointer to an URI structure
  197. * @str: pointer to the string to analyze
  198. *
  199. * Parse the query part of an URI
  200. *
  201. * fragment = *( pchar / "/" / "?" )
  202. * NOTE: the strict syntax as defined by 3986 does not allow '[' and ']'
  203. * in the fragment identifier but this is used very broadly for
  204. * xpointer scheme selection, so we are allowing it here to not break
  205. * for example all the DocBook processing chains.
  206. *
  207. * Returns 0 or the error code
  208. */
  209. static int
  210. xmlParse3986Fragment(xmlURIPtr uri, const char **str)
  211. {
  212. const char *cur;
  213. if (str == NULL)
  214. return (-1);
  215. cur = *str;
  216. while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
  217. (*cur == '[') || (*cur == ']') ||
  218. ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
  219. NEXT(cur);
  220. if (uri != NULL) {
  221. if (uri->fragment != NULL)
  222. xmlFree(uri->fragment);
  223. if (uri->cleanup & 2)
  224. uri->fragment = STRNDUP(*str, cur - *str);
  225. else
  226. uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
  227. }
  228. *str = cur;
  229. return (0);
  230. }
  231. /**
  232. * xmlParse3986Query:
  233. * @uri: pointer to an URI structure
  234. * @str: pointer to the string to analyze
  235. *
  236. * Parse the query part of an URI
  237. *
  238. * query = *uric
  239. *
  240. * Returns 0 or the error code
  241. */
  242. static int
  243. xmlParse3986Query(xmlURIPtr uri, const char **str)
  244. {
  245. const char *cur;
  246. if (str == NULL)
  247. return (-1);
  248. cur = *str;
  249. while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
  250. ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
  251. NEXT(cur);
  252. if (uri != NULL) {
  253. if (uri->query != NULL)
  254. xmlFree(uri->query);
  255. if (uri->cleanup & 2)
  256. uri->query = STRNDUP(*str, cur - *str);
  257. else
  258. uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
  259. /* Save the raw bytes of the query as well.
  260. * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114
  261. */
  262. if (uri->query_raw != NULL)
  263. xmlFree (uri->query_raw);
  264. uri->query_raw = STRNDUP (*str, cur - *str);
  265. }
  266. *str = cur;
  267. return (0);
  268. }
  269. /**
  270. * xmlParse3986Port:
  271. * @uri: pointer to an URI structure
  272. * @str: the string to analyze
  273. *
  274. * Parse a port part and fills in the appropriate fields
  275. * of the @uri structure
  276. *
  277. * port = *DIGIT
  278. *
  279. * Returns 0 or the error code
  280. */
  281. static int
  282. xmlParse3986Port(xmlURIPtr uri, const char **str)
  283. {
  284. const char *cur = *str;
  285. int port = 0;
  286. if (ISA_DIGIT(cur)) {
  287. while (ISA_DIGIT(cur)) {
  288. int digit = *cur - '0';
  289. if (port > INT_MAX / 10)
  290. return(1);
  291. port *= 10;
  292. if (port > INT_MAX - digit)
  293. return(1);
  294. port += digit;
  295. cur++;
  296. }
  297. if (uri != NULL)
  298. uri->port = port;
  299. *str = cur;
  300. return(0);
  301. }
  302. return(1);
  303. }
  304. /**
  305. * xmlParse3986Userinfo:
  306. * @uri: pointer to an URI structure
  307. * @str: the string to analyze
  308. *
  309. * Parse an user information part and fills in the appropriate fields
  310. * of the @uri structure
  311. *
  312. * userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
  313. *
  314. * Returns 0 or the error code
  315. */
  316. static int
  317. xmlParse3986Userinfo(xmlURIPtr uri, const char **str)
  318. {
  319. const char *cur;
  320. cur = *str;
  321. while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) ||
  322. ISA_SUB_DELIM(cur) || (*cur == ':'))
  323. NEXT(cur);
  324. if (*cur == '@') {
  325. if (uri != NULL) {
  326. if (uri->user != NULL) xmlFree(uri->user);
  327. if (uri->cleanup & 2)
  328. uri->user = STRNDUP(*str, cur - *str);
  329. else
  330. uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
  331. }
  332. *str = cur;
  333. return(0);
  334. }
  335. return(1);
  336. }
  337. /**
  338. * xmlParse3986DecOctet:
  339. * @str: the string to analyze
  340. *
  341. * dec-octet = DIGIT ; 0-9
  342. * / %x31-39 DIGIT ; 10-99
  343. * / "1" 2DIGIT ; 100-199
  344. * / "2" %x30-34 DIGIT ; 200-249
  345. * / "25" %x30-35 ; 250-255
  346. *
  347. * Skip a dec-octet.
  348. *
  349. * Returns 0 if found and skipped, 1 otherwise
  350. */
  351. static int
  352. xmlParse3986DecOctet(const char **str) {
  353. const char *cur = *str;
  354. if (!(ISA_DIGIT(cur)))
  355. return(1);
  356. if (!ISA_DIGIT(cur+1))
  357. cur++;
  358. else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur+2)))
  359. cur += 2;
  360. else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2)))
  361. cur += 3;
  362. else if ((*cur == '2') && (*(cur + 1) >= '0') &&
  363. (*(cur + 1) <= '4') && (ISA_DIGIT(cur + 2)))
  364. cur += 3;
  365. else if ((*cur == '2') && (*(cur + 1) == '5') &&
  366. (*(cur + 2) >= '0') && (*(cur + 1) <= '5'))
  367. cur += 3;
  368. else
  369. return(1);
  370. *str = cur;
  371. return(0);
  372. }
  373. /**
  374. * xmlParse3986Host:
  375. * @uri: pointer to an URI structure
  376. * @str: the string to analyze
  377. *
  378. * Parse an host part and fills in the appropriate fields
  379. * of the @uri structure
  380. *
  381. * host = IP-literal / IPv4address / reg-name
  382. * IP-literal = "[" ( IPv6address / IPvFuture ) "]"
  383. * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
  384. * reg-name = *( unreserved / pct-encoded / sub-delims )
  385. *
  386. * Returns 0 or the error code
  387. */
  388. static int
  389. xmlParse3986Host(xmlURIPtr uri, const char **str)
  390. {
  391. const char *cur = *str;
  392. const char *host;
  393. host = cur;
  394. /*
  395. * IPv6 and future addressing scheme are enclosed between brackets
  396. */
  397. if (*cur == '[') {
  398. cur++;
  399. while ((*cur != ']') && (*cur != 0))
  400. cur++;
  401. if (*cur != ']')
  402. return(1);
  403. cur++;
  404. goto found;
  405. }
  406. /*
  407. * try to parse an IPv4
  408. */
  409. if (ISA_DIGIT(cur)) {
  410. if (xmlParse3986DecOctet(&cur) != 0)
  411. goto not_ipv4;
  412. if (*cur != '.')
  413. goto not_ipv4;
  414. cur++;
  415. if (xmlParse3986DecOctet(&cur) != 0)
  416. goto not_ipv4;
  417. if (*cur != '.')
  418. goto not_ipv4;
  419. if (xmlParse3986DecOctet(&cur) != 0)
  420. goto not_ipv4;
  421. if (*cur != '.')
  422. goto not_ipv4;
  423. if (xmlParse3986DecOctet(&cur) != 0)
  424. goto not_ipv4;
  425. goto found;
  426. not_ipv4:
  427. cur = *str;
  428. }
  429. /*
  430. * then this should be a hostname which can be empty
  431. */
  432. while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur))
  433. NEXT(cur);
  434. found:
  435. if (uri != NULL) {
  436. if (uri->authority != NULL) xmlFree(uri->authority);
  437. uri->authority = NULL;
  438. if (uri->server != NULL) xmlFree(uri->server);
  439. if (cur != host) {
  440. if (uri->cleanup & 2)
  441. uri->server = STRNDUP(host, cur - host);
  442. else
  443. uri->server = xmlURIUnescapeString(host, cur - host, NULL);
  444. } else
  445. uri->server = NULL;
  446. }
  447. *str = cur;
  448. return(0);
  449. }
  450. /**
  451. * xmlParse3986Authority:
  452. * @uri: pointer to an URI structure
  453. * @str: the string to analyze
  454. *
  455. * Parse an authority part and fills in the appropriate fields
  456. * of the @uri structure
  457. *
  458. * authority = [ userinfo "@" ] host [ ":" port ]
  459. *
  460. * Returns 0 or the error code
  461. */
  462. static int
  463. xmlParse3986Authority(xmlURIPtr uri, const char **str)
  464. {
  465. const char *cur;
  466. int ret;
  467. cur = *str;
  468. /*
  469. * try to parse an userinfo and check for the trailing @
  470. */
  471. ret = xmlParse3986Userinfo(uri, &cur);
  472. if ((ret != 0) || (*cur != '@'))
  473. cur = *str;
  474. else
  475. cur++;
  476. ret = xmlParse3986Host(uri, &cur);
  477. if (ret != 0) return(ret);
  478. if (*cur == ':') {
  479. cur++;
  480. ret = xmlParse3986Port(uri, &cur);
  481. if (ret != 0) return(ret);
  482. }
  483. *str = cur;
  484. return(0);
  485. }
  486. /**
  487. * xmlParse3986Segment:
  488. * @str: the string to analyze
  489. * @forbid: an optional forbidden character
  490. * @empty: allow an empty segment
  491. *
  492. * Parse a segment and fills in the appropriate fields
  493. * of the @uri structure
  494. *
  495. * segment = *pchar
  496. * segment-nz = 1*pchar
  497. * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
  498. * ; non-zero-length segment without any colon ":"
  499. *
  500. * Returns 0 or the error code
  501. */
  502. static int
  503. xmlParse3986Segment(const char **str, char forbid, int empty)
  504. {
  505. const char *cur;
  506. cur = *str;
  507. if (!ISA_PCHAR(cur)) {
  508. if (empty)
  509. return(0);
  510. return(1);
  511. }
  512. while (ISA_PCHAR(cur) && (*cur != forbid))
  513. NEXT(cur);
  514. *str = cur;
  515. return (0);
  516. }
  517. /**
  518. * xmlParse3986PathAbEmpty:
  519. * @uri: pointer to an URI structure
  520. * @str: the string to analyze
  521. *
  522. * Parse an path absolute or empty and fills in the appropriate fields
  523. * of the @uri structure
  524. *
  525. * path-abempty = *( "/" segment )
  526. *
  527. * Returns 0 or the error code
  528. */
  529. static int
  530. xmlParse3986PathAbEmpty(xmlURIPtr uri, const char **str)
  531. {
  532. const char *cur;
  533. int ret;
  534. cur = *str;
  535. while (*cur == '/') {
  536. cur++;
  537. ret = xmlParse3986Segment(&cur, 0, 1);
  538. if (ret != 0) return(ret);
  539. }
  540. if (uri != NULL) {
  541. if (uri->path != NULL) xmlFree(uri->path);
  542. if (*str != cur) {
  543. if (uri->cleanup & 2)
  544. uri->path = STRNDUP(*str, cur - *str);
  545. else
  546. uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
  547. } else {
  548. uri->path = NULL;
  549. }
  550. }
  551. *str = cur;
  552. return (0);
  553. }
  554. /**
  555. * xmlParse3986PathAbsolute:
  556. * @uri: pointer to an URI structure
  557. * @str: the string to analyze
  558. *
  559. * Parse an path absolute and fills in the appropriate fields
  560. * of the @uri structure
  561. *
  562. * path-absolute = "/" [ segment-nz *( "/" segment ) ]
  563. *
  564. * Returns 0 or the error code
  565. */
  566. static int
  567. xmlParse3986PathAbsolute(xmlURIPtr uri, const char **str)
  568. {
  569. const char *cur;
  570. int ret;
  571. cur = *str;
  572. if (*cur != '/')
  573. return(1);
  574. cur++;
  575. ret = xmlParse3986Segment(&cur, 0, 0);
  576. if (ret == 0) {
  577. while (*cur == '/') {
  578. cur++;
  579. ret = xmlParse3986Segment(&cur, 0, 1);
  580. if (ret != 0) return(ret);
  581. }
  582. }
  583. if (uri != NULL) {
  584. if (uri->path != NULL) xmlFree(uri->path);
  585. if (cur != *str) {
  586. if (uri->cleanup & 2)
  587. uri->path = STRNDUP(*str, cur - *str);
  588. else
  589. uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
  590. } else {
  591. uri->path = NULL;
  592. }
  593. }
  594. *str = cur;
  595. return (0);
  596. }
  597. /**
  598. * xmlParse3986PathRootless:
  599. * @uri: pointer to an URI structure
  600. * @str: the string to analyze
  601. *
  602. * Parse an path without root and fills in the appropriate fields
  603. * of the @uri structure
  604. *
  605. * path-rootless = segment-nz *( "/" segment )
  606. *
  607. * Returns 0 or the error code
  608. */
  609. static int
  610. xmlParse3986PathRootless(xmlURIPtr uri, const char **str)
  611. {
  612. const char *cur;
  613. int ret;
  614. cur = *str;
  615. ret = xmlParse3986Segment(&cur, 0, 0);
  616. if (ret != 0) return(ret);
  617. while (*cur == '/') {
  618. cur++;
  619. ret = xmlParse3986Segment(&cur, 0, 1);
  620. if (ret != 0) return(ret);
  621. }
  622. if (uri != NULL) {
  623. if (uri->path != NULL) xmlFree(uri->path);
  624. if (cur != *str) {
  625. if (uri->cleanup & 2)
  626. uri->path = STRNDUP(*str, cur - *str);
  627. else
  628. uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
  629. } else {
  630. uri->path = NULL;
  631. }
  632. }
  633. *str = cur;
  634. return (0);
  635. }
  636. /**
  637. * xmlParse3986PathNoScheme:
  638. * @uri: pointer to an URI structure
  639. * @str: the string to analyze
  640. *
  641. * Parse an path which is not a scheme and fills in the appropriate fields
  642. * of the @uri structure
  643. *
  644. * path-noscheme = segment-nz-nc *( "/" segment )
  645. *
  646. * Returns 0 or the error code
  647. */
  648. static int
  649. xmlParse3986PathNoScheme(xmlURIPtr uri, const char **str)
  650. {
  651. const char *cur;
  652. int ret;
  653. cur = *str;
  654. ret = xmlParse3986Segment(&cur, ':', 0);
  655. if (ret != 0) return(ret);
  656. while (*cur == '/') {
  657. cur++;
  658. ret = xmlParse3986Segment(&cur, 0, 1);
  659. if (ret != 0) return(ret);
  660. }
  661. if (uri != NULL) {
  662. if (uri->path != NULL) xmlFree(uri->path);
  663. if (cur != *str) {
  664. if (uri->cleanup & 2)
  665. uri->path = STRNDUP(*str, cur - *str);
  666. else
  667. uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
  668. } else {
  669. uri->path = NULL;
  670. }
  671. }
  672. *str = cur;
  673. return (0);
  674. }
  675. /**
  676. * xmlParse3986HierPart:
  677. * @uri: pointer to an URI structure
  678. * @str: the string to analyze
  679. *
  680. * Parse an hierarchical part and fills in the appropriate fields
  681. * of the @uri structure
  682. *
  683. * hier-part = "//" authority path-abempty
  684. * / path-absolute
  685. * / path-rootless
  686. * / path-empty
  687. *
  688. * Returns 0 or the error code
  689. */
  690. static int
  691. xmlParse3986HierPart(xmlURIPtr uri, const char **str)
  692. {
  693. const char *cur;
  694. int ret;
  695. cur = *str;
  696. if ((*cur == '/') && (*(cur + 1) == '/')) {
  697. cur += 2;
  698. ret = xmlParse3986Authority(uri, &cur);
  699. if (ret != 0) return(ret);
  700. /*
  701. * An empty server is marked with a special URI value.
  702. */
  703. if ((uri->server == NULL) && (uri->port == PORT_EMPTY))
  704. uri->port = PORT_EMPTY_SERVER;
  705. ret = xmlParse3986PathAbEmpty(uri, &cur);
  706. if (ret != 0) return(ret);
  707. *str = cur;
  708. return(0);
  709. } else if (*cur == '/') {
  710. ret = xmlParse3986PathAbsolute(uri, &cur);
  711. if (ret != 0) return(ret);
  712. } else if (ISA_PCHAR(cur)) {
  713. ret = xmlParse3986PathRootless(uri, &cur);
  714. if (ret != 0) return(ret);
  715. } else {
  716. /* path-empty is effectively empty */
  717. if (uri != NULL) {
  718. if (uri->path != NULL) xmlFree(uri->path);
  719. uri->path = NULL;
  720. }
  721. }
  722. *str = cur;
  723. return (0);
  724. }
  725. /**
  726. * xmlParse3986RelativeRef:
  727. * @uri: pointer to an URI structure
  728. * @str: the string to analyze
  729. *
  730. * Parse an URI string and fills in the appropriate fields
  731. * of the @uri structure
  732. *
  733. * relative-ref = relative-part [ "?" query ] [ "#" fragment ]
  734. * relative-part = "//" authority path-abempty
  735. * / path-absolute
  736. * / path-noscheme
  737. * / path-empty
  738. *
  739. * Returns 0 or the error code
  740. */
  741. static int
  742. xmlParse3986RelativeRef(xmlURIPtr uri, const char *str) {
  743. int ret;
  744. if ((*str == '/') && (*(str + 1) == '/')) {
  745. str += 2;
  746. ret = xmlParse3986Authority(uri, &str);
  747. if (ret != 0) return(ret);
  748. ret = xmlParse3986PathAbEmpty(uri, &str);
  749. if (ret != 0) return(ret);
  750. } else if (*str == '/') {
  751. ret = xmlParse3986PathAbsolute(uri, &str);
  752. if (ret != 0) return(ret);
  753. } else if (ISA_PCHAR(str)) {
  754. ret = xmlParse3986PathNoScheme(uri, &str);
  755. if (ret != 0) return(ret);
  756. } else {
  757. /* path-empty is effectively empty */
  758. if (uri != NULL) {
  759. if (uri->path != NULL) xmlFree(uri->path);
  760. uri->path = NULL;
  761. }
  762. }
  763. if (*str == '?') {
  764. str++;
  765. ret = xmlParse3986Query(uri, &str);
  766. if (ret != 0) return(ret);
  767. }
  768. if (*str == '#') {
  769. str++;
  770. ret = xmlParse3986Fragment(uri, &str);
  771. if (ret != 0) return(ret);
  772. }
  773. if (*str != 0) {
  774. xmlCleanURI(uri);
  775. return(1);
  776. }
  777. return(0);
  778. }
  779. /**
  780. * xmlParse3986URI:
  781. * @uri: pointer to an URI structure
  782. * @str: the string to analyze
  783. *
  784. * Parse an URI string and fills in the appropriate fields
  785. * of the @uri structure
  786. *
  787. * scheme ":" hier-part [ "?" query ] [ "#" fragment ]
  788. *
  789. * Returns 0 or the error code
  790. */
  791. static int
  792. xmlParse3986URI(xmlURIPtr uri, const char *str) {
  793. int ret;
  794. ret = xmlParse3986Scheme(uri, &str);
  795. if (ret != 0) return(ret);
  796. if (*str != ':') {
  797. return(1);
  798. }
  799. str++;
  800. ret = xmlParse3986HierPart(uri, &str);
  801. if (ret != 0) return(ret);
  802. if (*str == '?') {
  803. str++;
  804. ret = xmlParse3986Query(uri, &str);
  805. if (ret != 0) return(ret);
  806. }
  807. if (*str == '#') {
  808. str++;
  809. ret = xmlParse3986Fragment(uri, &str);
  810. if (ret != 0) return(ret);
  811. }
  812. if (*str != 0) {
  813. xmlCleanURI(uri);
  814. return(1);
  815. }
  816. return(0);
  817. }
  818. /**
  819. * xmlParse3986URIReference:
  820. * @uri: pointer to an URI structure
  821. * @str: the string to analyze
  822. *
  823. * Parse an URI reference string and fills in the appropriate fields
  824. * of the @uri structure
  825. *
  826. * URI-reference = URI / relative-ref
  827. *
  828. * Returns 0 or the error code
  829. */
  830. static int
  831. xmlParse3986URIReference(xmlURIPtr uri, const char *str) {
  832. int ret;
  833. if (str == NULL)
  834. return(-1);
  835. xmlCleanURI(uri);
  836. /*
  837. * Try first to parse absolute refs, then fallback to relative if
  838. * it fails.
  839. */
  840. ret = xmlParse3986URI(uri, str);
  841. if (ret != 0) {
  842. xmlCleanURI(uri);
  843. ret = xmlParse3986RelativeRef(uri, str);
  844. if (ret != 0) {
  845. xmlCleanURI(uri);
  846. return(ret);
  847. }
  848. }
  849. return(0);
  850. }
  851. /**
  852. * xmlParseURI:
  853. * @str: the URI string to analyze
  854. *
  855. * Parse an URI based on RFC 3986
  856. *
  857. * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
  858. *
  859. * Returns a newly built xmlURIPtr or NULL in case of error
  860. */
  861. xmlURIPtr
  862. xmlParseURI(const char *str) {
  863. xmlURIPtr uri;
  864. int ret;
  865. if (str == NULL)
  866. return(NULL);
  867. uri = xmlCreateURI();
  868. if (uri != NULL) {
  869. ret = xmlParse3986URIReference(uri, str);
  870. if (ret) {
  871. xmlFreeURI(uri);
  872. return(NULL);
  873. }
  874. }
  875. return(uri);
  876. }
  877. /**
  878. * xmlParseURIReference:
  879. * @uri: pointer to an URI structure
  880. * @str: the string to analyze
  881. *
  882. * Parse an URI reference string based on RFC 3986 and fills in the
  883. * appropriate fields of the @uri structure
  884. *
  885. * URI-reference = URI / relative-ref
  886. *
  887. * Returns 0 or the error code
  888. */
  889. int
  890. xmlParseURIReference(xmlURIPtr uri, const char *str) {
  891. return(xmlParse3986URIReference(uri, str));
  892. }
  893. /**
  894. * xmlParseURIRaw:
  895. * @str: the URI string to analyze
  896. * @raw: if 1 unescaping of URI pieces are disabled
  897. *
  898. * Parse an URI but allows to keep intact the original fragments.
  899. *
  900. * URI-reference = URI / relative-ref
  901. *
  902. * Returns a newly built xmlURIPtr or NULL in case of error
  903. */
  904. xmlURIPtr
  905. xmlParseURIRaw(const char *str, int raw) {
  906. xmlURIPtr uri;
  907. int ret;
  908. if (str == NULL)
  909. return(NULL);
  910. uri = xmlCreateURI();
  911. if (uri != NULL) {
  912. if (raw) {
  913. uri->cleanup |= 2;
  914. }
  915. ret = xmlParseURIReference(uri, str);
  916. if (ret) {
  917. xmlFreeURI(uri);
  918. return(NULL);
  919. }
  920. }
  921. return(uri);
  922. }
  923. /************************************************************************
  924. * *
  925. * Generic URI structure functions *
  926. * *
  927. ************************************************************************/
  928. /**
  929. * xmlCreateURI:
  930. *
  931. * Simply creates an empty xmlURI
  932. *
  933. * Returns the new structure or NULL in case of error
  934. */
  935. xmlURIPtr
  936. xmlCreateURI(void) {
  937. xmlURIPtr ret;
  938. ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI));
  939. if (ret == NULL) {
  940. xmlURIErrMemory("creating URI structure\n");
  941. return(NULL);
  942. }
  943. memset(ret, 0, sizeof(xmlURI));
  944. ret->port = PORT_EMPTY;
  945. return(ret);
  946. }
  947. /**
  948. * xmlSaveUriRealloc:
  949. *
  950. * Function to handle properly a reallocation when saving an URI
  951. * Also imposes some limit on the length of an URI string output
  952. */
  953. static xmlChar *
  954. xmlSaveUriRealloc(xmlChar *ret, int *max) {
  955. xmlChar *temp;
  956. int tmp;
  957. if (*max > MAX_URI_LENGTH) {
  958. xmlURIErrMemory("reaching arbitrary MAX_URI_LENGTH limit\n");
  959. return(NULL);
  960. }
  961. tmp = *max * 2;
  962. temp = (xmlChar *) xmlRealloc(ret, (tmp + 1));
  963. if (temp == NULL) {
  964. xmlURIErrMemory("saving URI\n");
  965. return(NULL);
  966. }
  967. *max = tmp;
  968. return(temp);
  969. }
  970. /**
  971. * xmlSaveUri:
  972. * @uri: pointer to an xmlURI
  973. *
  974. * Save the URI as an escaped string
  975. *
  976. * Returns a new string (to be deallocated by caller)
  977. */
  978. xmlChar *
  979. xmlSaveUri(xmlURIPtr uri) {
  980. xmlChar *ret = NULL;
  981. xmlChar *temp;
  982. const char *p;
  983. int len;
  984. int max;
  985. if (uri == NULL) return(NULL);
  986. max = 80;
  987. ret = (xmlChar *) xmlMallocAtomic(max + 1);
  988. if (ret == NULL) {
  989. xmlURIErrMemory("saving URI\n");
  990. return(NULL);
  991. }
  992. len = 0;
  993. if (uri->scheme != NULL) {
  994. p = uri->scheme;
  995. while (*p != 0) {
  996. if (len >= max) {
  997. temp = xmlSaveUriRealloc(ret, &max);
  998. if (temp == NULL) goto mem_error;
  999. ret = temp;
  1000. }
  1001. ret[len++] = *p++;
  1002. }
  1003. if (len >= max) {
  1004. temp = xmlSaveUriRealloc(ret, &max);
  1005. if (temp == NULL) goto mem_error;
  1006. ret = temp;
  1007. }
  1008. ret[len++] = ':';
  1009. }
  1010. if (uri->opaque != NULL) {
  1011. p = uri->opaque;
  1012. while (*p != 0) {
  1013. if (len + 3 >= max) {
  1014. temp = xmlSaveUriRealloc(ret, &max);
  1015. if (temp == NULL) goto mem_error;
  1016. ret = temp;
  1017. }
  1018. if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
  1019. ret[len++] = *p++;
  1020. else {
  1021. int val = *(unsigned char *)p++;
  1022. int hi = val / 0x10, lo = val % 0x10;
  1023. ret[len++] = '%';
  1024. ret[len++] = hi + (hi > 9? 'A'-10 : '0');
  1025. ret[len++] = lo + (lo > 9? 'A'-10 : '0');
  1026. }
  1027. }
  1028. } else {
  1029. if ((uri->server != NULL) || (uri->port != PORT_EMPTY)) {
  1030. if (len + 3 >= max) {
  1031. temp = xmlSaveUriRealloc(ret, &max);
  1032. if (temp == NULL) goto mem_error;
  1033. ret = temp;
  1034. }
  1035. ret[len++] = '/';
  1036. ret[len++] = '/';
  1037. if (uri->user != NULL) {
  1038. p = uri->user;
  1039. while (*p != 0) {
  1040. if (len + 3 >= max) {
  1041. temp = xmlSaveUriRealloc(ret, &max);
  1042. if (temp == NULL) goto mem_error;
  1043. ret = temp;
  1044. }
  1045. if ((IS_UNRESERVED(*(p))) ||
  1046. ((*(p) == ';')) || ((*(p) == ':')) ||
  1047. ((*(p) == '&')) || ((*(p) == '=')) ||
  1048. ((*(p) == '+')) || ((*(p) == '$')) ||
  1049. ((*(p) == ',')))
  1050. ret[len++] = *p++;
  1051. else {
  1052. int val = *(unsigned char *)p++;
  1053. int hi = val / 0x10, lo = val % 0x10;
  1054. ret[len++] = '%';
  1055. ret[len++] = hi + (hi > 9? 'A'-10 : '0');
  1056. ret[len++] = lo + (lo > 9? 'A'-10 : '0');
  1057. }
  1058. }
  1059. if (len + 3 >= max) {
  1060. temp = xmlSaveUriRealloc(ret, &max);
  1061. if (temp == NULL) goto mem_error;
  1062. ret = temp;
  1063. }
  1064. ret[len++] = '@';
  1065. }
  1066. if (uri->server != NULL) {
  1067. p = uri->server;
  1068. while (*p != 0) {
  1069. if (len >= max) {
  1070. temp = xmlSaveUriRealloc(ret, &max);
  1071. if (temp == NULL) goto mem_error;
  1072. ret = temp;
  1073. }
  1074. /* TODO: escaping? */
  1075. ret[len++] = (xmlChar) *p++;
  1076. }
  1077. }
  1078. if (uri->port > 0) {
  1079. if (len + 10 >= max) {
  1080. temp = xmlSaveUriRealloc(ret, &max);
  1081. if (temp == NULL) goto mem_error;
  1082. ret = temp;
  1083. }
  1084. len += snprintf((char *) &ret[len], max - len, ":%d", uri->port);
  1085. }
  1086. } else if (uri->authority != NULL) {
  1087. if (len + 3 >= max) {
  1088. temp = xmlSaveUriRealloc(ret, &max);
  1089. if (temp == NULL) goto mem_error;
  1090. ret = temp;
  1091. }
  1092. ret[len++] = '/';
  1093. ret[len++] = '/';
  1094. p = uri->authority;
  1095. while (*p != 0) {
  1096. if (len + 3 >= max) {
  1097. temp = xmlSaveUriRealloc(ret, &max);
  1098. if (temp == NULL) goto mem_error;
  1099. ret = temp;
  1100. }
  1101. if ((IS_UNRESERVED(*(p))) ||
  1102. ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
  1103. ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
  1104. ((*(p) == '=')) || ((*(p) == '+')))
  1105. ret[len++] = *p++;
  1106. else {
  1107. int val = *(unsigned char *)p++;
  1108. int hi = val / 0x10, lo = val % 0x10;
  1109. ret[len++] = '%';
  1110. ret[len++] = hi + (hi > 9? 'A'-10 : '0');
  1111. ret[len++] = lo + (lo > 9? 'A'-10 : '0');
  1112. }
  1113. }
  1114. } else if (uri->scheme != NULL) {
  1115. if (len + 3 >= max) {
  1116. temp = xmlSaveUriRealloc(ret, &max);
  1117. if (temp == NULL) goto mem_error;
  1118. ret = temp;
  1119. }
  1120. }
  1121. if (uri->path != NULL) {
  1122. p = uri->path;
  1123. /*
  1124. * the colon in file:///d: should not be escaped or
  1125. * Windows accesses fail later.
  1126. */
  1127. if ((uri->scheme != NULL) &&
  1128. (p[0] == '/') &&
  1129. (((p[1] >= 'a') && (p[1] <= 'z')) ||
  1130. ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
  1131. (p[2] == ':') &&
  1132. (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
  1133. if (len + 3 >= max) {
  1134. temp = xmlSaveUriRealloc(ret, &max);
  1135. if (temp == NULL) goto mem_error;
  1136. ret = temp;
  1137. }
  1138. ret[len++] = *p++;
  1139. ret[len++] = *p++;
  1140. ret[len++] = *p++;
  1141. }
  1142. while (*p != 0) {
  1143. if (len + 3 >= max) {
  1144. temp = xmlSaveUriRealloc(ret, &max);
  1145. if (temp == NULL) goto mem_error;
  1146. ret = temp;
  1147. }
  1148. if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
  1149. ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
  1150. ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
  1151. ((*(p) == ',')))
  1152. ret[len++] = *p++;
  1153. else {
  1154. int val = *(unsigned char *)p++;
  1155. int hi = val / 0x10, lo = val % 0x10;
  1156. ret[len++] = '%';
  1157. ret[len++] = hi + (hi > 9? 'A'-10 : '0');
  1158. ret[len++] = lo + (lo > 9? 'A'-10 : '0');
  1159. }
  1160. }
  1161. }
  1162. if (uri->query_raw != NULL) {
  1163. if (len + 1 >= max) {
  1164. temp = xmlSaveUriRealloc(ret, &max);
  1165. if (temp == NULL) goto mem_error;
  1166. ret = temp;
  1167. }
  1168. ret[len++] = '?';
  1169. p = uri->query_raw;
  1170. while (*p != 0) {
  1171. if (len + 1 >= max) {
  1172. temp = xmlSaveUriRealloc(ret, &max);
  1173. if (temp == NULL) goto mem_error;
  1174. ret = temp;
  1175. }
  1176. ret[len++] = *p++;
  1177. }
  1178. } else if (uri->query != NULL) {
  1179. if (len + 3 >= max) {
  1180. temp = xmlSaveUriRealloc(ret, &max);
  1181. if (temp == NULL) goto mem_error;
  1182. ret = temp;
  1183. }
  1184. ret[len++] = '?';
  1185. p = uri->query;
  1186. while (*p != 0) {
  1187. if (len + 3 >= max) {
  1188. temp = xmlSaveUriRealloc(ret, &max);
  1189. if (temp == NULL) goto mem_error;
  1190. ret = temp;
  1191. }
  1192. if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
  1193. ret[len++] = *p++;
  1194. else {
  1195. int val = *(unsigned char *)p++;
  1196. int hi = val / 0x10, lo = val % 0x10;
  1197. ret[len++] = '%';
  1198. ret[len++] = hi + (hi > 9? 'A'-10 : '0');
  1199. ret[len++] = lo + (lo > 9? 'A'-10 : '0');
  1200. }
  1201. }
  1202. }
  1203. }
  1204. if (uri->fragment != NULL) {
  1205. if (len + 3 >= max) {
  1206. temp = xmlSaveUriRealloc(ret, &max);
  1207. if (temp == NULL) goto mem_error;
  1208. ret = temp;
  1209. }
  1210. ret[len++] = '#';
  1211. p = uri->fragment;
  1212. while (*p != 0) {
  1213. if (len + 3 >= max) {
  1214. temp = xmlSaveUriRealloc(ret, &max);
  1215. if (temp == NULL) goto mem_error;
  1216. ret = temp;
  1217. }
  1218. if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
  1219. ret[len++] = *p++;
  1220. else {
  1221. int val = *(unsigned char *)p++;
  1222. int hi = val / 0x10, lo = val % 0x10;
  1223. ret[len++] = '%';
  1224. ret[len++] = hi + (hi > 9? 'A'-10 : '0');
  1225. ret[len++] = lo + (lo > 9? 'A'-10 : '0');
  1226. }
  1227. }
  1228. }
  1229. if (len >= max) {
  1230. temp = xmlSaveUriRealloc(ret, &max);
  1231. if (temp == NULL) goto mem_error;
  1232. ret = temp;
  1233. }
  1234. ret[len] = 0;
  1235. return(ret);
  1236. mem_error:
  1237. xmlFree(ret);
  1238. return(NULL);
  1239. }
  1240. /**
  1241. * xmlPrintURI:
  1242. * @stream: a FILE* for the output
  1243. * @uri: pointer to an xmlURI
  1244. *
  1245. * Prints the URI in the stream @stream.
  1246. */
  1247. void
  1248. xmlPrintURI(FILE *stream, xmlURIPtr uri) {
  1249. xmlChar *out;
  1250. out = xmlSaveUri(uri);
  1251. if (out != NULL) {
  1252. fprintf(stream, "%s", (char *) out);
  1253. xmlFree(out);
  1254. }
  1255. }
  1256. /**
  1257. * xmlCleanURI:
  1258. * @uri: pointer to an xmlURI
  1259. *
  1260. * Make sure the xmlURI struct is free of content
  1261. */
  1262. static void
  1263. xmlCleanURI(xmlURIPtr uri) {
  1264. if (uri == NULL) return;
  1265. if (uri->scheme != NULL) xmlFree(uri->scheme);
  1266. uri->scheme = NULL;
  1267. if (uri->server != NULL) xmlFree(uri->server);
  1268. uri->server = NULL;
  1269. if (uri->user != NULL) xmlFree(uri->user);
  1270. uri->user = NULL;
  1271. if (uri->path != NULL) xmlFree(uri->path);
  1272. uri->path = NULL;
  1273. if (uri->fragment != NULL) xmlFree(uri->fragment);
  1274. uri->fragment = NULL;
  1275. if (uri->opaque != NULL) xmlFree(uri->opaque);
  1276. uri->opaque = NULL;
  1277. if (uri->authority != NULL) xmlFree(uri->authority);
  1278. uri->authority = NULL;
  1279. if (uri->query != NULL) xmlFree(uri->query);
  1280. uri->query = NULL;
  1281. if (uri->query_raw != NULL) xmlFree(uri->query_raw);
  1282. uri->query_raw = NULL;
  1283. }
  1284. /**
  1285. * xmlFreeURI:
  1286. * @uri: pointer to an xmlURI
  1287. *
  1288. * Free up the xmlURI struct
  1289. */
  1290. void
  1291. xmlFreeURI(xmlURIPtr uri) {
  1292. if (uri == NULL) return;
  1293. if (uri->scheme != NULL) xmlFree(uri->scheme);
  1294. if (uri->server != NULL) xmlFree(uri->server);
  1295. if (uri->user != NULL) xmlFree(uri->user);
  1296. if (uri->path != NULL) xmlFree(uri->path);
  1297. if (uri->fragment != NULL) xmlFree(uri->fragment);
  1298. if (uri->opaque != NULL) xmlFree(uri->opaque);
  1299. if (uri->authority != NULL) xmlFree(uri->authority);
  1300. if (uri->query != NULL) xmlFree(uri->query);
  1301. if (uri->query_raw != NULL) xmlFree(uri->query_raw);
  1302. xmlFree(uri);
  1303. }
  1304. /************************************************************************
  1305. * *
  1306. * Helper functions *
  1307. * *
  1308. ************************************************************************/
  1309. /**
  1310. * xmlNormalizeURIPath:
  1311. * @path: pointer to the path string
  1312. *
  1313. * Applies the 5 normalization steps to a path string--that is, RFC 2396
  1314. * Section 5.2, steps 6.c through 6.g.
  1315. *
  1316. * Normalization occurs directly on the string, no new allocation is done
  1317. *
  1318. * Returns 0 or an error code
  1319. */
  1320. int
  1321. xmlNormalizeURIPath(char *path) {
  1322. char *cur, *out;
  1323. if (path == NULL)
  1324. return(-1);
  1325. /* Skip all initial "/" chars. We want to get to the beginning of the
  1326. * first non-empty segment.
  1327. */
  1328. cur = path;
  1329. while (cur[0] == '/')
  1330. ++cur;
  1331. if (cur[0] == '\0')
  1332. return(0);
  1333. /* Keep everything we've seen so far. */
  1334. out = cur;
  1335. /*
  1336. * Analyze each segment in sequence for cases (c) and (d).
  1337. */
  1338. while (cur[0] != '\0') {
  1339. /*
  1340. * c) All occurrences of "./", where "." is a complete path segment,
  1341. * are removed from the buffer string.
  1342. */
  1343. if ((cur[0] == '.') && (cur[1] == '/')) {
  1344. cur += 2;
  1345. /* '//' normalization should be done at this point too */
  1346. while (cur[0] == '/')
  1347. cur++;
  1348. continue;
  1349. }
  1350. /*
  1351. * d) If the buffer string ends with "." as a complete path segment,
  1352. * that "." is removed.
  1353. */
  1354. if ((cur[0] == '.') && (cur[1] == '\0'))
  1355. break;
  1356. /* Otherwise keep the segment. */
  1357. while (cur[0] != '/') {
  1358. if (cur[0] == '\0')
  1359. goto done_cd;
  1360. (out++)[0] = (cur++)[0];
  1361. }
  1362. /* normalize // */
  1363. while ((cur[0] == '/') && (cur[1] == '/'))
  1364. cur++;
  1365. (out++)[0] = (cur++)[0];
  1366. }
  1367. done_cd:
  1368. out[0] = '\0';
  1369. /* Reset to the beginning of the first segment for the next sequence. */
  1370. cur = path;
  1371. while (cur[0] == '/')
  1372. ++cur;
  1373. if (cur[0] == '\0')
  1374. return(0);
  1375. /*
  1376. * Analyze each segment in sequence for cases (e) and (f).
  1377. *
  1378. * e) All occurrences of "<segment>/../", where <segment> is a
  1379. * complete path segment not equal to "..", are removed from the
  1380. * buffer string. Removal of these path segments is performed
  1381. * iteratively, removing the leftmost matching pattern on each
  1382. * iteration, until no matching pattern remains.
  1383. *
  1384. * f) If the buffer string ends with "<segment>/..", where <segment>
  1385. * is a complete path segment not equal to "..", that
  1386. * "<segment>/.." is removed.
  1387. *
  1388. * To satisfy the "iterative" clause in (e), we need to collapse the
  1389. * string every time we find something that needs to be removed. Thus,
  1390. * we don't need to keep two pointers into the string: we only need a
  1391. * "current position" pointer.
  1392. */
  1393. while (1) {
  1394. char *segp, *tmp;
  1395. /* At the beginning of each iteration of this loop, "cur" points to
  1396. * the first character of the segment we want to examine.
  1397. */
  1398. /* Find the end of the current segment. */
  1399. segp = cur;
  1400. while ((segp[0] != '/') && (segp[0] != '\0'))
  1401. ++segp;
  1402. /* If this is the last segment, we're done (we need at least two
  1403. * segments to meet the criteria for the (e) and (f) cases).
  1404. */
  1405. if (segp[0] == '\0')
  1406. break;
  1407. /* If the first segment is "..", or if the next segment _isn't_ "..",
  1408. * keep this segment and try the next one.
  1409. */
  1410. ++segp;
  1411. if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
  1412. || ((segp[0] != '.') || (segp[1] != '.')
  1413. || ((segp[2] != '/') && (segp[2] != '\0')))) {
  1414. cur = segp;
  1415. continue;
  1416. }
  1417. /* If we get here, remove this segment and the next one and back up
  1418. * to the previous segment (if there is one), to implement the
  1419. * "iteratively" clause. It's pretty much impossible to back up
  1420. * while maintaining two pointers into the buffer, so just compact
  1421. * the whole buffer now.
  1422. */
  1423. /* If this is the end of the buffer, we're done. */
  1424. if (segp[2] == '\0') {
  1425. cur[0] = '\0';
  1426. break;
  1427. }
  1428. /* Valgrind complained, strcpy(cur, segp + 3); */
  1429. /* string will overlap, do not use strcpy */
  1430. tmp = cur;
  1431. segp += 3;
  1432. while ((*tmp++ = *segp++) != 0)
  1433. ;
  1434. /* If there are no previous segments, then keep going from here. */
  1435. segp = cur;
  1436. while ((segp > path) && ((--segp)[0] == '/'))
  1437. ;
  1438. if (segp == path)
  1439. continue;
  1440. /* "segp" is pointing to the end of a previous segment; find it's
  1441. * start. We need to back up to the previous segment and start
  1442. * over with that to handle things like "foo/bar/../..". If we
  1443. * don't do this, then on the first pass we'll remove the "bar/..",
  1444. * but be pointing at the second ".." so we won't realize we can also
  1445. * remove the "foo/..".
  1446. */
  1447. cur = segp;
  1448. while ((cur > path) && (cur[-1] != '/'))
  1449. --cur;
  1450. }
  1451. out[0] = '\0';
  1452. /*
  1453. * g) If the resulting buffer string still begins with one or more
  1454. * complete path segments of "..", then the reference is
  1455. * considered to be in error. Implementations may handle this
  1456. * error by retaining these components in the resolved path (i.e.,
  1457. * treating them as part of the final URI), by removing them from
  1458. * the resolved path (i.e., discarding relative levels above the
  1459. * root), or by avoiding traversal of the reference.
  1460. *
  1461. * We discard them from the final path.
  1462. */
  1463. if (path[0] == '/') {
  1464. cur = path;
  1465. while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
  1466. && ((cur[3] == '/') || (cur[3] == '\0')))
  1467. cur += 3;
  1468. if (cur != path) {
  1469. out = path;
  1470. while (cur[0] != '\0')
  1471. (out++)[0] = (cur++)[0];
  1472. out[0] = 0;
  1473. }
  1474. }
  1475. return(0);
  1476. }
  1477. static int is_hex(char c) {
  1478. if (((c >= '0') && (c <= '9')) ||
  1479. ((c >= 'a') && (c <= 'f')) ||
  1480. ((c >= 'A') && (c <= 'F')))
  1481. return(1);
  1482. return(0);
  1483. }
  1484. /**
  1485. * xmlURIUnescapeString:
  1486. * @str: the string to unescape
  1487. * @len: the length in bytes to unescape (or <= 0 to indicate full string)
  1488. * @target: optional destination buffer
  1489. *
  1490. * Unescaping routine, but does not check that the string is an URI. The
  1491. * output is a direct unsigned char translation of %XX values (no encoding)
  1492. * Note that the length of the result can only be smaller or same size as
  1493. * the input string.
  1494. *
  1495. * Returns a copy of the string, but unescaped, will return NULL only in case
  1496. * of error
  1497. */
  1498. char *
  1499. xmlURIUnescapeString(const char *str, int len, char *target) {
  1500. char *ret, *out;
  1501. const char *in;
  1502. if (str == NULL)
  1503. return(NULL);
  1504. if (len <= 0) len = strlen(str);
  1505. if (len < 0) return(NULL);
  1506. if (target == NULL) {
  1507. ret = (char *) xmlMallocAtomic(len + 1);
  1508. if (ret == NULL) {
  1509. xmlURIErrMemory("unescaping URI value\n");
  1510. return(NULL);
  1511. }
  1512. } else
  1513. ret = target;
  1514. in = str;
  1515. out = ret;
  1516. while(len > 0) {
  1517. if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
  1518. int c = 0;
  1519. in++;
  1520. if ((*in >= '0') && (*in <= '9'))
  1521. c = (*in - '0');
  1522. else if ((*in >= 'a') && (*in <= 'f'))
  1523. c = (*in - 'a') + 10;
  1524. else if ((*in >= 'A') && (*in <= 'F'))
  1525. c = (*in - 'A') + 10;
  1526. in++;
  1527. if ((*in >= '0') && (*in <= '9'))
  1528. c = c * 16 + (*in - '0');
  1529. else if ((*in >= 'a') && (*in <= 'f'))
  1530. c = c * 16 + (*in - 'a') + 10;
  1531. else if ((*in >= 'A') && (*in <= 'F'))
  1532. c = c * 16 + (*in - 'A') + 10;
  1533. in++;
  1534. len -= 3;
  1535. /* Explicit sign change */
  1536. *out++ = (char) c;
  1537. } else {
  1538. *out++ = *in++;
  1539. len--;
  1540. }
  1541. }
  1542. *out = 0;
  1543. return(ret);
  1544. }
  1545. /**
  1546. * xmlURIEscapeStr:
  1547. * @str: string to escape
  1548. * @list: exception list string of chars not to escape
  1549. *
  1550. * This routine escapes a string to hex, ignoring reserved characters
  1551. * (a-z, A-Z, 0-9, "@-_.!~*'()") and the characters in the exception list.
  1552. *
  1553. * Returns a new escaped string or NULL in case of error.
  1554. */
  1555. xmlChar *
  1556. xmlURIEscapeStr(const xmlChar *str, const xmlChar *list) {
  1557. xmlChar *ret, ch;
  1558. xmlChar *temp;
  1559. const xmlChar *in;
  1560. int len, out;
  1561. if (str == NULL)
  1562. return(NULL);
  1563. if (str[0] == 0)
  1564. return(xmlStrdup(str));
  1565. len = xmlStrlen(str);
  1566. if (!(len > 0)) return(NULL);
  1567. len += 20;
  1568. ret = (xmlChar *) xmlMallocAtomic(len);
  1569. if (ret == NULL) {
  1570. xmlURIErrMemory("escaping URI value\n");
  1571. return(NULL);
  1572. }
  1573. in = (const xmlChar *) str;
  1574. out = 0;
  1575. while(*in != 0) {
  1576. if (len - out <= 3) {
  1577. temp = xmlSaveUriRealloc(ret, &len);
  1578. if (temp == NULL) {
  1579. xmlURIErrMemory("escaping URI value\n");
  1580. xmlFree(ret);
  1581. return(NULL);
  1582. }
  1583. ret = temp;
  1584. }
  1585. ch = *in;
  1586. if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!xmlStrchr(list, ch))) {
  1587. unsigned char val;
  1588. ret[out++] = '%';
  1589. val = ch >> 4;
  1590. if (val <= 9)
  1591. ret[out++] = '0' + val;
  1592. else
  1593. ret[out++] = 'A' + val - 0xA;
  1594. val = ch & 0xF;
  1595. if (val <= 9)
  1596. ret[out++] = '0' + val;
  1597. else
  1598. ret[out++] = 'A' + val - 0xA;
  1599. in++;
  1600. } else {
  1601. ret[out++] = *in++;
  1602. }
  1603. }
  1604. ret[out] = 0;
  1605. return(ret);
  1606. }
  1607. /**
  1608. * xmlURIEscape:
  1609. * @str: the string of the URI to escape
  1610. *
  1611. * Escaping routine, does not do validity checks !
  1612. * It will try to escape the chars needing this, but this is heuristic
  1613. * based it's impossible to be sure.
  1614. *
  1615. * Returns an copy of the string, but escaped
  1616. *
  1617. * 25 May 2001
  1618. * Uses xmlParseURI and xmlURIEscapeStr to try to escape correctly
  1619. * according to RFC2396.
  1620. * - Carl Douglas
  1621. */
  1622. xmlChar *
  1623. xmlURIEscape(const xmlChar * str)
  1624. {
  1625. xmlChar *ret, *segment = NULL;
  1626. xmlURIPtr uri;
  1627. int ret2;
  1628. if (str == NULL)
  1629. return (NULL);
  1630. uri = xmlCreateURI();
  1631. if (uri != NULL) {
  1632. /*
  1633. * Allow escaping errors in the unescaped form
  1634. */
  1635. uri->cleanup = 1;
  1636. ret2 = xmlParseURIReference(uri, (const char *)str);
  1637. if (ret2) {
  1638. xmlFreeURI(uri);
  1639. return (NULL);
  1640. }
  1641. }
  1642. if (!uri)
  1643. return NULL;
  1644. ret = NULL;
  1645. #define NULLCHK(p) if(!p) { \
  1646. xmlURIErrMemory("escaping URI value\n"); \
  1647. xmlFreeURI(uri); \
  1648. xmlFree(ret); \
  1649. return NULL; } \
  1650. if (uri->scheme) {
  1651. segment = xmlURIEscapeStr(BAD_CAST uri->scheme, BAD_CAST "+-.");
  1652. NULLCHK(segment)
  1653. ret = xmlStrcat(ret, segment);
  1654. ret = xmlStrcat(ret, BAD_CAST ":");
  1655. xmlFree(segment);
  1656. }
  1657. if (uri->authority) {
  1658. segment =
  1659. xmlURIEscapeStr(BAD_CAST uri->authority, BAD_CAST "/?;:@");
  1660. NULLCHK(segment)
  1661. ret = xmlStrcat(ret, BAD_CAST "//");
  1662. ret = xmlStrcat(ret, segment);
  1663. xmlFree(segment);
  1664. }
  1665. if (uri->user) {
  1666. segment = xmlURIEscapeStr(BAD_CAST uri->user, BAD_CAST ";:&=+$,");
  1667. NULLCHK(segment)
  1668. ret = xmlStrcat(ret,BAD_CAST "//");
  1669. ret = xmlStrcat(ret, segment);
  1670. ret = xmlStrcat(ret, BAD_CAST "@");
  1671. xmlFree(segment);
  1672. }
  1673. if (uri->server) {
  1674. segment = xmlURIEscapeStr(BAD_CAST uri->server, BAD_CAST "/?;:@");
  1675. NULLCHK(segment)
  1676. if (uri->user == NULL)
  1677. ret = xmlStrcat(ret, BAD_CAST "//");
  1678. ret = xmlStrcat(ret, segment);
  1679. xmlFree(segment);
  1680. }
  1681. if (uri->port > 0) {
  1682. xmlChar port[11];
  1683. snprintf((char *) port, 11, "%d", uri->port);
  1684. ret = xmlStrcat(ret, BAD_CAST ":");
  1685. ret = xmlStrcat(ret, port);
  1686. }
  1687. if (uri->path) {
  1688. segment =
  1689. xmlURIEscapeStr(BAD_CAST uri->path, BAD_CAST ":@&=+$,/?;");
  1690. NULLCHK(segment)
  1691. ret = xmlStrcat(ret, segment);
  1692. xmlFree(segment);
  1693. }
  1694. if (uri->query_raw) {
  1695. ret = xmlStrcat(ret, BAD_CAST "?");
  1696. ret = xmlStrcat(ret, BAD_CAST uri->query_raw);
  1697. }
  1698. else if (uri->query) {
  1699. segment =
  1700. xmlURIEscapeStr(BAD_CAST uri->query, BAD_CAST ";/?:@&=+,$");
  1701. NULLCHK(segment)
  1702. ret = xmlStrcat(ret, BAD_CAST "?");
  1703. ret = xmlStrcat(ret, segment);
  1704. xmlFree(segment);
  1705. }
  1706. if (uri->opaque) {
  1707. segment = xmlURIEscapeStr(BAD_CAST uri->opaque, BAD_CAST "");
  1708. NULLCHK(segment)
  1709. ret = xmlStrcat(ret, segment);
  1710. xmlFree(segment);
  1711. }
  1712. if (uri->fragment) {
  1713. segment = xmlURIEscapeStr(BAD_CAST uri->fragment, BAD_CAST "#");
  1714. NULLCHK(segment)
  1715. ret = xmlStrcat(ret, BAD_CAST "#");
  1716. ret = xmlStrcat(ret, segment);
  1717. xmlFree(segment);
  1718. }
  1719. xmlFreeURI(uri);
  1720. #undef NULLCHK
  1721. return (ret);
  1722. }
  1723. /************************************************************************
  1724. * *
  1725. * Public functions *
  1726. * *
  1727. ************************************************************************/
  1728. /**
  1729. * xmlBuildURI:
  1730. * @URI: the URI instance found in the document
  1731. * @base: the base value
  1732. *
  1733. * Computes he final URI of the reference done by checking that
  1734. * the given URI is valid, and building the final URI using the
  1735. * base URI. This is processed according to section 5.2 of the
  1736. * RFC 2396
  1737. *
  1738. * 5.2. Resolving Relative References to Absolute Form
  1739. *
  1740. * Returns a new URI string (to be freed by the caller) or NULL in case
  1741. * of error.
  1742. */
  1743. xmlChar *
  1744. xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
  1745. xmlChar *val = NULL;
  1746. int ret, len, indx, cur, out;
  1747. xmlURIPtr ref = NULL;
  1748. xmlURIPtr bas = NULL;
  1749. xmlURIPtr res = NULL;
  1750. /*
  1751. * 1) The URI reference is parsed into the potential four components and
  1752. * fragment identifier, as described in Section 4.3.
  1753. *
  1754. * NOTE that a completely empty URI is treated by modern browsers
  1755. * as a reference to "." rather than as a synonym for the current
  1756. * URI. Should we do that here?
  1757. */
  1758. if (URI == NULL)
  1759. ret = -1;
  1760. else {
  1761. if (*URI) {
  1762. ref = xmlCreateURI();
  1763. if (ref == NULL)
  1764. goto done;
  1765. ret = xmlParseURIReference(ref, (const char *) URI);
  1766. }
  1767. else
  1768. ret = 0;
  1769. }
  1770. if (ret != 0)
  1771. goto done;
  1772. if ((ref != NULL) && (ref->scheme != NULL)) {
  1773. /*
  1774. * The URI is absolute don't modify.
  1775. */
  1776. val = xmlStrdup(URI);
  1777. goto done;
  1778. }
  1779. if (base == NULL)
  1780. ret = -1;
  1781. else {
  1782. bas = xmlCreateURI();
  1783. if (bas == NULL)
  1784. goto done;
  1785. ret = xmlParseURIReference(bas, (const char *) base);
  1786. }
  1787. if (ret != 0) {
  1788. if (ref)
  1789. val = xmlSaveUri(ref);
  1790. goto done;
  1791. }
  1792. if (ref == NULL) {
  1793. /*
  1794. * the base fragment must be ignored
  1795. */
  1796. if (bas->fragment != NULL) {
  1797. xmlFree(bas->fragment);
  1798. bas->fragment = NULL;
  1799. }
  1800. val = xmlSaveUri(bas);
  1801. goto done;
  1802. }
  1803. /*
  1804. * 2) If the path component is empty and the scheme, authority, and
  1805. * query components are undefined, then it is a reference to the
  1806. * current document and we are done. Otherwise, the reference URI's
  1807. * query and fragment components are defined as found (or not found)
  1808. * within the URI reference and not inherited from the base URI.
  1809. *
  1810. * NOTE that in modern browsers, the parsing differs from the above
  1811. * in the following aspect: the query component is allowed to be
  1812. * defined while still treating this as a reference to the current
  1813. * document.
  1814. */
  1815. res = xmlCreateURI();
  1816. if (res == NULL)
  1817. goto done;
  1818. if ((ref->scheme == NULL) && (ref->path == NULL) &&
  1819. ((ref->authority == NULL) && (ref->server == NULL) &&
  1820. (ref->port == PORT_EMPTY))) {
  1821. if (bas->scheme != NULL)
  1822. res->scheme = xmlMemStrdup(bas->scheme);
  1823. if (bas->authority != NULL)
  1824. res->authority = xmlMemStrdup(bas->authority);
  1825. else {
  1826. if (bas->server != NULL)
  1827. res->server = xmlMemStrdup(bas->server);
  1828. if (bas->user != NULL)
  1829. res->user = xmlMemStrdup(bas->user);
  1830. res->port = bas->port;
  1831. }
  1832. if (bas->path != NULL)
  1833. res->path = xmlMemStrdup(bas->path);
  1834. if (ref->query_raw != NULL)
  1835. res->query_raw = xmlMemStrdup (ref->query_raw);
  1836. else if (ref->query != NULL)
  1837. res->query = xmlMemStrdup(ref->query);
  1838. else if (bas->query_raw != NULL)
  1839. res->query_raw = xmlMemStrdup(bas->query_raw);
  1840. else if (bas->query != NULL)
  1841. res->query = xmlMemStrdup(bas->query);
  1842. if (ref->fragment != NULL)
  1843. res->fragment = xmlMemStrdup(ref->fragment);
  1844. goto step_7;
  1845. }
  1846. /*
  1847. * 3) If the scheme component is defined, indicating that the reference
  1848. * starts with a scheme name, then the reference is interpreted as an
  1849. * absolute URI and we are done. Otherwise, the reference URI's
  1850. * scheme is inherited from the base URI's scheme component.
  1851. */
  1852. if (ref->scheme != NULL) {
  1853. val = xmlSaveUri(ref);
  1854. goto done;
  1855. }
  1856. if (bas->scheme != NULL)
  1857. res->scheme = xmlMemStrdup(bas->scheme);
  1858. if (ref->query_raw != NULL)
  1859. res->query_raw = xmlMemStrdup(ref->query_raw);
  1860. else if (ref->query != NULL)
  1861. res->query = xmlMemStrdup(ref->query);
  1862. if (ref->fragment != NULL)
  1863. res->fragment = xmlMemStrdup(ref->fragment);
  1864. /*
  1865. * 4) If the authority component is defined, then the reference is a
  1866. * network-path and we skip to step 7. Otherwise, the reference
  1867. * URI's authority is inherited from the base URI's authority
  1868. * component, which will also be undefined if the URI scheme does not
  1869. * use an authority component.
  1870. */
  1871. if ((ref->authority != NULL) || (ref->server != NULL) ||
  1872. (ref->port != PORT_EMPTY)) {
  1873. if (ref->authority != NULL)
  1874. res->authority = xmlMemStrdup(ref->authority);
  1875. else {
  1876. if (ref->server != NULL)
  1877. res->server = xmlMemStrdup(ref->server);
  1878. if (ref->user != NULL)
  1879. res->user = xmlMemStrdup(ref->user);
  1880. res->port = ref->port;
  1881. }
  1882. if (ref->path != NULL)
  1883. res->path = xmlMemStrdup(ref->path);
  1884. goto step_7;
  1885. }
  1886. if (bas->authority != NULL)
  1887. res->authority = xmlMemStrdup(bas->authority);
  1888. else if ((bas->server != NULL) || (bas->port != PORT_EMPTY)) {
  1889. if (bas->server != NULL)
  1890. res->server = xmlMemStrdup(bas->server);
  1891. if (bas->user != NULL)
  1892. res->user = xmlMemStrdup(bas->user);
  1893. res->port = bas->port;
  1894. }
  1895. /*
  1896. * 5) If the path component begins with a slash character ("/"), then
  1897. * the reference is an absolute-path and we skip to step 7.
  1898. */
  1899. if ((ref->path != NULL) && (ref->path[0] == '/')) {
  1900. res->path = xmlMemStrdup(ref->path);
  1901. goto step_7;
  1902. }
  1903. /*
  1904. * 6) If this step is reached, then we are resolving a relative-path
  1905. * reference. The relative path needs to be merged with the base
  1906. * URI's path. Although there are many ways to do this, we will
  1907. * describe a simple method using a separate string buffer.
  1908. *
  1909. * Allocate a buffer large enough for the result string.
  1910. */
  1911. len = 2; /* extra / and 0 */
  1912. if (ref->path != NULL)
  1913. len += strlen(ref->path);
  1914. if (bas->path != NULL)
  1915. len += strlen(bas->path);
  1916. res->path = (char *) xmlMallocAtomic(len);
  1917. if (res->path == NULL) {
  1918. xmlURIErrMemory("resolving URI against base\n");
  1919. goto done;
  1920. }
  1921. res->path[0] = 0;
  1922. /*
  1923. * a) All but the last segment of the base URI's path component is
  1924. * copied to the buffer. In other words, any characters after the
  1925. * last (right-most) slash character, if any, are excluded.
  1926. */
  1927. cur = 0;
  1928. out = 0;
  1929. if (bas->path != NULL) {
  1930. while (bas->path[cur] != 0) {
  1931. while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
  1932. cur++;
  1933. if (bas->path[cur] == 0)
  1934. break;
  1935. cur++;
  1936. while (out < cur) {
  1937. res->path[out] = bas->path[out];
  1938. out++;
  1939. }
  1940. }
  1941. }
  1942. res->path[out] = 0;
  1943. /*
  1944. * b) The reference's path component is appended to the buffer
  1945. * string.
  1946. */
  1947. if (ref->path != NULL && ref->path[0] != 0) {
  1948. indx = 0;
  1949. /*
  1950. * Ensure the path includes a '/'
  1951. */
  1952. if ((out == 0) && ((bas->server != NULL) || bas->port != PORT_EMPTY))
  1953. res->path[out++] = '/';
  1954. while (ref->path[indx] != 0) {
  1955. res->path[out++] = ref->path[indx++];
  1956. }
  1957. }
  1958. res->path[out] = 0;
  1959. /*
  1960. * Steps c) to h) are really path normalization steps
  1961. */
  1962. xmlNormalizeURIPath(res->path);
  1963. step_7:
  1964. /*
  1965. * 7) The resulting URI components, including any inherited from the
  1966. * base URI, are recombined to give the absolute form of the URI
  1967. * reference.
  1968. */
  1969. val = xmlSaveUri(res);
  1970. done:
  1971. if (ref != NULL)
  1972. xmlFreeURI(ref);
  1973. if (bas != NULL)
  1974. xmlFreeURI(bas);
  1975. if (res != NULL)
  1976. xmlFreeURI(res);
  1977. return(val);
  1978. }
  1979. /**
  1980. * xmlBuildRelativeURI:
  1981. * @URI: the URI reference under consideration
  1982. * @base: the base value
  1983. *
  1984. * Expresses the URI of the reference in terms relative to the
  1985. * base. Some examples of this operation include:
  1986. * base = "http://site1.com/docs/book1.html"
  1987. * URI input URI returned
  1988. * docs/pic1.gif pic1.gif
  1989. * docs/img/pic1.gif img/pic1.gif
  1990. * img/pic1.gif ../img/pic1.gif
  1991. * http://site1.com/docs/pic1.gif pic1.gif
  1992. * http://site2.com/docs/pic1.gif http://site2.com/docs/pic1.gif
  1993. *
  1994. * base = "docs/book1.html"
  1995. * URI input URI returned
  1996. * docs/pic1.gif pic1.gif
  1997. * docs/img/pic1.gif img/pic1.gif
  1998. * img/pic1.gif ../img/pic1.gif
  1999. * http://site1.com/docs/pic1.gif http://site1.com/docs/pic1.gif
  2000. *
  2001. *
  2002. * Note: if the URI reference is really weird or complicated, it may be
  2003. * worthwhile to first convert it into a "nice" one by calling
  2004. * xmlBuildURI (using 'base') before calling this routine,
  2005. * since this routine (for reasonable efficiency) assumes URI has
  2006. * already been through some validation.
  2007. *
  2008. * Returns a new URI string (to be freed by the caller) or NULL in case
  2009. * error.
  2010. */
  2011. xmlChar *
  2012. xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base)
  2013. {
  2014. xmlChar *val = NULL;
  2015. int ret;
  2016. int ix;
  2017. int nbslash = 0;
  2018. int len;
  2019. xmlURIPtr ref = NULL;
  2020. xmlURIPtr bas = NULL;
  2021. xmlChar *bptr, *uptr, *vptr;
  2022. int remove_path = 0;
  2023. if ((URI == NULL) || (*URI == 0))
  2024. return NULL;
  2025. /*
  2026. * First parse URI into a standard form
  2027. */
  2028. ref = xmlCreateURI ();
  2029. if (ref == NULL)
  2030. return NULL;
  2031. /* If URI not already in "relative" form */
  2032. if (URI[0] != '.') {
  2033. ret = xmlParseURIReference (ref, (const char *) URI);
  2034. if (ret != 0)
  2035. goto done; /* Error in URI, return NULL */
  2036. } else
  2037. ref->path = (char *)xmlStrdup(URI);
  2038. /*
  2039. * Next parse base into the same standard form
  2040. */
  2041. if ((base == NULL) || (*base == 0)) {
  2042. val = xmlStrdup (URI);
  2043. goto done;
  2044. }
  2045. bas = xmlCreateURI ();
  2046. if (bas == NULL)
  2047. goto done;
  2048. if (base[0] != '.') {
  2049. ret = xmlParseURIReference (bas, (const char *) base);
  2050. if (ret != 0)
  2051. goto done; /* Error in base, return NULL */
  2052. } else
  2053. bas->path = (char *)xmlStrdup(base);
  2054. /*
  2055. * If the scheme / server on the URI differs from the base,
  2056. * just return the URI
  2057. */
  2058. if ((ref->scheme != NULL) &&
  2059. ((bas->scheme == NULL) ||
  2060. (xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) ||
  2061. (xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)) ||
  2062. (bas->port != ref->port))) {
  2063. val = xmlStrdup (URI);
  2064. goto done;
  2065. }
  2066. if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) {
  2067. val = xmlStrdup(BAD_CAST "");
  2068. goto done;
  2069. }
  2070. if (bas->path == NULL) {
  2071. val = xmlStrdup((xmlChar *)ref->path);
  2072. goto done;
  2073. }
  2074. if (ref->path == NULL) {
  2075. ref->path = (char *) "/";
  2076. remove_path = 1;
  2077. }
  2078. /*
  2079. * At this point (at last!) we can compare the two paths
  2080. *
  2081. * First we take care of the special case where either of the
  2082. * two path components may be missing (bug 316224)
  2083. */
  2084. bptr = (xmlChar *)bas->path;
  2085. {
  2086. xmlChar *rptr = (xmlChar *) ref->path;
  2087. int pos = 0;
  2088. /*
  2089. * Next we compare the two strings and find where they first differ
  2090. */
  2091. if ((*rptr == '.') && (rptr[1] == '/'))
  2092. rptr += 2;
  2093. if ((*bptr == '.') && (bptr[1] == '/'))
  2094. bptr += 2;
  2095. else if ((*bptr == '/') && (*rptr != '/'))
  2096. bptr++;
  2097. while ((bptr[pos] == rptr[pos]) && (bptr[pos] != 0))
  2098. pos++;
  2099. if (bptr[pos] == rptr[pos]) {
  2100. val = xmlStrdup(BAD_CAST "");
  2101. goto done; /* (I can't imagine why anyone would do this) */
  2102. }
  2103. /*
  2104. * In URI, "back up" to the last '/' encountered. This will be the
  2105. * beginning of the "unique" suffix of URI
  2106. */
  2107. ix = pos;
  2108. for (; ix > 0; ix--) {
  2109. if (rptr[ix - 1] == '/')
  2110. break;
  2111. }
  2112. uptr = (xmlChar *)&rptr[ix];
  2113. /*
  2114. * In base, count the number of '/' from the differing point
  2115. */
  2116. for (; bptr[ix] != 0; ix++) {
  2117. if (bptr[ix] == '/')
  2118. nbslash++;
  2119. }
  2120. /*
  2121. * e.g: URI="foo/" base="foo/bar" -> "./"
  2122. */
  2123. if (nbslash == 0 && !uptr[0]) {
  2124. val = xmlStrdup(BAD_CAST "./");
  2125. goto done;
  2126. }
  2127. len = xmlStrlen (uptr) + 1;
  2128. }
  2129. if (nbslash == 0) {
  2130. if (uptr != NULL)
  2131. /* exception characters from xmlSaveUri */
  2132. val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
  2133. goto done;
  2134. }
  2135. /*
  2136. * Allocate just enough space for the returned string -
  2137. * length of the remainder of the URI, plus enough space
  2138. * for the "../" groups, plus one for the terminator
  2139. */
  2140. val = (xmlChar *) xmlMalloc (len + 3 * nbslash);
  2141. if (val == NULL) {
  2142. xmlURIErrMemory("building relative URI\n");
  2143. goto done;
  2144. }
  2145. vptr = val;
  2146. /*
  2147. * Put in as many "../" as needed
  2148. */
  2149. for (; nbslash>0; nbslash--) {
  2150. *vptr++ = '.';
  2151. *vptr++ = '.';
  2152. *vptr++ = '/';
  2153. }
  2154. /*
  2155. * Finish up with the end of the URI
  2156. */
  2157. if (uptr != NULL) {
  2158. if ((vptr > val) && (len > 0) &&
  2159. (uptr[0] == '/') && (vptr[-1] == '/')) {
  2160. memcpy (vptr, uptr + 1, len - 1);
  2161. vptr[len - 2] = 0;
  2162. } else {
  2163. memcpy (vptr, uptr, len);
  2164. vptr[len - 1] = 0;
  2165. }
  2166. } else {
  2167. vptr[len - 1] = 0;
  2168. }
  2169. /* escape the freshly-built path */
  2170. vptr = val;
  2171. /* exception characters from xmlSaveUri */
  2172. val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,");
  2173. xmlFree(vptr);
  2174. done:
  2175. /*
  2176. * Free the working variables
  2177. */
  2178. if (remove_path != 0)
  2179. ref->path = NULL;
  2180. if (ref != NULL)
  2181. xmlFreeURI (ref);
  2182. if (bas != NULL)
  2183. xmlFreeURI (bas);
  2184. return val;
  2185. }
  2186. /**
  2187. * xmlCanonicPath:
  2188. * @path: the resource locator in a filesystem notation
  2189. *
  2190. * Constructs a canonic path from the specified path.
  2191. *
  2192. * Returns a new canonic path, or a duplicate of the path parameter if the
  2193. * construction fails. The caller is responsible for freeing the memory occupied
  2194. * by the returned string. If there is insufficient memory available, or the
  2195. * argument is NULL, the function returns NULL.
  2196. */
  2197. #define IS_WINDOWS_PATH(p) \
  2198. ((p != NULL) && \
  2199. (((p[0] >= 'a') && (p[0] <= 'z')) || \
  2200. ((p[0] >= 'A') && (p[0] <= 'Z'))) && \
  2201. (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))
  2202. xmlChar *
  2203. xmlCanonicPath(const xmlChar *path)
  2204. {
  2205. /*
  2206. * For Windows implementations, additional work needs to be done to
  2207. * replace backslashes in pathnames with "forward slashes"
  2208. */
  2209. #if defined(_WIN32)
  2210. int len = 0;
  2211. char *p = NULL;
  2212. #endif
  2213. xmlURIPtr uri;
  2214. xmlChar *ret;
  2215. const xmlChar *absuri;
  2216. if (path == NULL)
  2217. return(NULL);
  2218. #if defined(_WIN32)
  2219. /*
  2220. * We must not change the backslashes to slashes if the the path
  2221. * starts with \\?\
  2222. * Those paths can be up to 32k characters long.
  2223. * Was added specifically for OpenOffice, those paths can't be converted
  2224. * to URIs anyway.
  2225. */
  2226. if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
  2227. (path[3] == '\\') )
  2228. return xmlStrdup((const xmlChar *) path);
  2229. #endif
  2230. /* sanitize filename starting with // so it can be used as URI */
  2231. if ((path[0] == '/') && (path[1] == '/') && (path[2] != '/'))
  2232. path++;
  2233. if ((uri = xmlParseURI((const char *) path)) != NULL) {
  2234. xmlFreeURI(uri);
  2235. return xmlStrdup(path);
  2236. }
  2237. /* Check if this is an "absolute uri" */
  2238. absuri = xmlStrstr(path, BAD_CAST "://");
  2239. if (absuri != NULL) {
  2240. int l, j;
  2241. unsigned char c;
  2242. xmlChar *escURI;
  2243. /*
  2244. * this looks like an URI where some parts have not been
  2245. * escaped leading to a parsing problem. Check that the first
  2246. * part matches a protocol.
  2247. */
  2248. l = absuri - path;
  2249. /* Bypass if first part (part before the '://') is > 20 chars */
  2250. if ((l <= 0) || (l > 20))
  2251. goto path_processing;
  2252. /* Bypass if any non-alpha characters are present in first part */
  2253. for (j = 0;j < l;j++) {
  2254. c = path[j];
  2255. if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))))
  2256. goto path_processing;
  2257. }
  2258. /* Escape all except the characters specified in the supplied path */
  2259. escURI = xmlURIEscapeStr(path, BAD_CAST ":/?_.#&;=");
  2260. if (escURI != NULL) {
  2261. /* Try parsing the escaped path */
  2262. uri = xmlParseURI((const char *) escURI);
  2263. /* If successful, return the escaped string */
  2264. if (uri != NULL) {
  2265. xmlFreeURI(uri);
  2266. return escURI;
  2267. }
  2268. xmlFree(escURI);
  2269. }
  2270. }
  2271. path_processing:
  2272. /* For Windows implementations, replace backslashes with 'forward slashes' */
  2273. #if defined(_WIN32)
  2274. /*
  2275. * Create a URI structure
  2276. */
  2277. uri = xmlCreateURI();
  2278. if (uri == NULL) { /* Guard against 'out of memory' */
  2279. return(NULL);
  2280. }
  2281. len = xmlStrlen(path);
  2282. if ((len > 2) && IS_WINDOWS_PATH(path)) {
  2283. /* make the scheme 'file' */
  2284. uri->scheme = (char *) xmlStrdup(BAD_CAST "file");
  2285. /* allocate space for leading '/' + path + string terminator */
  2286. uri->path = xmlMallocAtomic(len + 2);
  2287. if (uri->path == NULL) {
  2288. xmlFreeURI(uri); /* Guard against 'out of memory' */
  2289. return(NULL);
  2290. }
  2291. /* Put in leading '/' plus path */
  2292. uri->path[0] = '/';
  2293. p = uri->path + 1;
  2294. strncpy(p, (char *) path, len + 1);
  2295. } else {
  2296. uri->path = (char *) xmlStrdup(path);
  2297. if (uri->path == NULL) {
  2298. xmlFreeURI(uri);
  2299. return(NULL);
  2300. }
  2301. p = uri->path;
  2302. }
  2303. /* Now change all occurrences of '\' to '/' */
  2304. while (*p != '\0') {
  2305. if (*p == '\\')
  2306. *p = '/';
  2307. p++;
  2308. }
  2309. if (uri->scheme == NULL) {
  2310. ret = xmlStrdup((const xmlChar *) uri->path);
  2311. } else {
  2312. ret = xmlSaveUri(uri);
  2313. }
  2314. xmlFreeURI(uri);
  2315. #else
  2316. ret = xmlStrdup((const xmlChar *) path);
  2317. #endif
  2318. return(ret);
  2319. }
  2320. /**
  2321. * xmlPathToURI:
  2322. * @path: the resource locator in a filesystem notation
  2323. *
  2324. * Constructs an URI expressing the existing path
  2325. *
  2326. * Returns a new URI, or a duplicate of the path parameter if the
  2327. * construction fails. The caller is responsible for freeing the memory
  2328. * occupied by the returned string. If there is insufficient memory available,
  2329. * or the argument is NULL, the function returns NULL.
  2330. */
  2331. xmlChar *
  2332. xmlPathToURI(const xmlChar *path)
  2333. {
  2334. xmlURIPtr uri;
  2335. xmlURI temp;
  2336. xmlChar *ret, *cal;
  2337. if (path == NULL)
  2338. return(NULL);
  2339. if ((uri = xmlParseURI((const char *) path)) != NULL) {
  2340. xmlFreeURI(uri);
  2341. return xmlStrdup(path);
  2342. }
  2343. cal = xmlCanonicPath(path);
  2344. if (cal == NULL)
  2345. return(NULL);
  2346. #if defined(_WIN32)
  2347. /* xmlCanonicPath can return an URI on Windows (is that the intended behaviour?)
  2348. If 'cal' is a valid URI already then we are done here, as continuing would make
  2349. it invalid. */
  2350. if ((uri = xmlParseURI((const char *) cal)) != NULL) {
  2351. xmlFreeURI(uri);
  2352. return cal;
  2353. }
  2354. /* 'cal' can contain a relative path with backslashes. If that is processed
  2355. by xmlSaveURI, they will be escaped and the external entity loader machinery
  2356. will fail. So convert them to slashes. Misuse 'ret' for walking. */
  2357. ret = cal;
  2358. while (*ret != '\0') {
  2359. if (*ret == '\\')
  2360. *ret = '/';
  2361. ret++;
  2362. }
  2363. #endif
  2364. memset(&temp, 0, sizeof(temp));
  2365. temp.path = (char *) cal;
  2366. ret = xmlSaveUri(&temp);
  2367. xmlFree(cal);
  2368. return(ret);
  2369. }