uri.c 65 KB

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