xpointer.c 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920
  1. /*
  2. * xpointer.c : Code to handle XML Pointer
  3. *
  4. * Base implementation was made accordingly to
  5. * W3C Candidate Recommendation 7 June 2000
  6. * http://www.w3.org/TR/2000/CR-xptr-20000607
  7. *
  8. * Added support for the element() scheme described in:
  9. * W3C Proposed Recommendation 13 November 2002
  10. * http://www.w3.org/TR/2002/PR-xptr-element-20021113/
  11. *
  12. * See Copyright for the status of this software.
  13. *
  14. * daniel@veillard.com
  15. */
  16. /* To avoid EBCDIC trouble when parsing on zOS */
  17. #if defined(__MVS__)
  18. #pragma convert("ISO8859-1")
  19. #endif
  20. #define IN_LIBXML
  21. #include "libxml.h"
  22. /*
  23. * TODO: better handling of error cases, the full expression should
  24. * be parsed beforehand instead of a progressive evaluation
  25. * TODO: Access into entities references are not supported now ...
  26. * need a start to be able to pop out of entities refs since
  27. * parent is the entity declaration, not the ref.
  28. */
  29. #include <string.h>
  30. #include <libxml/xpointer.h>
  31. #include <libxml/xmlmemory.h>
  32. #include <libxml/parserInternals.h>
  33. #include <libxml/uri.h>
  34. #include <libxml/xpath.h>
  35. #include <libxml/xpathInternals.h>
  36. #include <libxml/xmlerror.h>
  37. #ifdef LIBXML_XPTR_ENABLED
  38. /* Add support of the xmlns() xpointer scheme to initialize the namespaces */
  39. #define XPTR_XMLNS_SCHEME
  40. #include "private/error.h"
  41. #define TODO \
  42. xmlGenericError(xmlGenericErrorContext, \
  43. "Unimplemented block at %s:%d\n", \
  44. __FILE__, __LINE__);
  45. #define STRANGE \
  46. xmlGenericError(xmlGenericErrorContext, \
  47. "Internal error at %s:%d\n", \
  48. __FILE__, __LINE__);
  49. /************************************************************************
  50. * *
  51. * Some factorized error routines *
  52. * *
  53. ************************************************************************/
  54. /**
  55. * xmlXPtrErrMemory:
  56. * @extra: extra information
  57. *
  58. * Handle a redefinition of attribute error
  59. */
  60. static void
  61. xmlXPtrErrMemory(const char *extra)
  62. {
  63. __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPOINTER,
  64. XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra,
  65. NULL, NULL, 0, 0,
  66. "Memory allocation failed : %s\n", extra);
  67. }
  68. /**
  69. * xmlXPtrErr:
  70. * @ctxt: an XPTR evaluation context
  71. * @extra: extra information
  72. *
  73. * Handle a redefinition of attribute error
  74. */
  75. static void LIBXML_ATTR_FORMAT(3,0)
  76. xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error,
  77. const char * msg, const xmlChar *extra)
  78. {
  79. if (ctxt != NULL)
  80. ctxt->error = error;
  81. if ((ctxt == NULL) || (ctxt->context == NULL)) {
  82. __xmlRaiseError(NULL, NULL, NULL,
  83. NULL, NULL, XML_FROM_XPOINTER, error,
  84. XML_ERR_ERROR, NULL, 0,
  85. (const char *) extra, NULL, NULL, 0, 0,
  86. msg, extra);
  87. return;
  88. }
  89. /* cleanup current last error */
  90. xmlResetError(&ctxt->context->lastError);
  91. ctxt->context->lastError.domain = XML_FROM_XPOINTER;
  92. ctxt->context->lastError.code = error;
  93. ctxt->context->lastError.level = XML_ERR_ERROR;
  94. ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
  95. ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
  96. ctxt->context->lastError.node = ctxt->context->debugNode;
  97. if (ctxt->context->error != NULL) {
  98. ctxt->context->error(ctxt->context->userData,
  99. &ctxt->context->lastError);
  100. } else {
  101. __xmlRaiseError(NULL, NULL, NULL,
  102. NULL, ctxt->context->debugNode, XML_FROM_XPOINTER,
  103. error, XML_ERR_ERROR, NULL, 0,
  104. (const char *) extra, (const char *) ctxt->base, NULL,
  105. ctxt->cur - ctxt->base, 0,
  106. msg, extra);
  107. }
  108. }
  109. /************************************************************************
  110. * *
  111. * A few helper functions for child sequences *
  112. * *
  113. ************************************************************************/
  114. #ifdef LIBXML_XPTR_LOCS_ENABLED
  115. /* xmlXPtrAdvanceNode is a private function, but used by xinclude.c */
  116. xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level);
  117. /**
  118. * xmlXPtrGetArity:
  119. * @cur: the node
  120. *
  121. * Returns the number of child for an element, -1 in case of error
  122. */
  123. static int
  124. xmlXPtrGetArity(xmlNodePtr cur) {
  125. int i;
  126. if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
  127. return(-1);
  128. cur = cur->children;
  129. for (i = 0;cur != NULL;cur = cur->next) {
  130. if ((cur->type == XML_ELEMENT_NODE) ||
  131. (cur->type == XML_DOCUMENT_NODE) ||
  132. (cur->type == XML_HTML_DOCUMENT_NODE)) {
  133. i++;
  134. }
  135. }
  136. return(i);
  137. }
  138. /**
  139. * xmlXPtrGetIndex:
  140. * @cur: the node
  141. *
  142. * Returns the index of the node in its parent children list, -1
  143. * in case of error
  144. */
  145. static int
  146. xmlXPtrGetIndex(xmlNodePtr cur) {
  147. int i;
  148. if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
  149. return(-1);
  150. for (i = 1;cur != NULL;cur = cur->prev) {
  151. if ((cur->type == XML_ELEMENT_NODE) ||
  152. (cur->type == XML_DOCUMENT_NODE) ||
  153. (cur->type == XML_HTML_DOCUMENT_NODE)) {
  154. i++;
  155. }
  156. }
  157. return(i);
  158. }
  159. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  160. /**
  161. * xmlXPtrGetNthChild:
  162. * @cur: the node
  163. * @no: the child number
  164. *
  165. * Returns the @no'th element child of @cur or NULL
  166. */
  167. static xmlNodePtr
  168. xmlXPtrGetNthChild(xmlNodePtr cur, int no) {
  169. int i;
  170. if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
  171. return(cur);
  172. cur = cur->children;
  173. for (i = 0;i <= no;cur = cur->next) {
  174. if (cur == NULL)
  175. return(cur);
  176. if ((cur->type == XML_ELEMENT_NODE) ||
  177. (cur->type == XML_DOCUMENT_NODE) ||
  178. (cur->type == XML_HTML_DOCUMENT_NODE)) {
  179. i++;
  180. if (i == no)
  181. break;
  182. }
  183. }
  184. return(cur);
  185. }
  186. #ifdef LIBXML_XPTR_LOCS_ENABLED
  187. /************************************************************************
  188. * *
  189. * Handling of XPointer specific types *
  190. * *
  191. ************************************************************************/
  192. /**
  193. * xmlXPtrCmpPoints:
  194. * @node1: the first node
  195. * @index1: the first index
  196. * @node2: the second node
  197. * @index2: the second index
  198. *
  199. * Compare two points w.r.t document order
  200. *
  201. * Returns -2 in case of error 1 if first point < second point, 0 if
  202. * that's the same point, -1 otherwise
  203. */
  204. static int
  205. xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) {
  206. if ((node1 == NULL) || (node2 == NULL))
  207. return(-2);
  208. /*
  209. * a couple of optimizations which will avoid computations in most cases
  210. */
  211. if (node1 == node2) {
  212. if (index1 < index2)
  213. return(1);
  214. if (index1 > index2)
  215. return(-1);
  216. return(0);
  217. }
  218. return(xmlXPathCmpNodes(node1, node2));
  219. }
  220. /**
  221. * xmlXPtrNewPoint:
  222. * @node: the xmlNodePtr
  223. * @indx: the indx within the node
  224. *
  225. * Create a new xmlXPathObjectPtr of type point
  226. *
  227. * Returns the newly created object.
  228. */
  229. static xmlXPathObjectPtr
  230. xmlXPtrNewPoint(xmlNodePtr node, int indx) {
  231. xmlXPathObjectPtr ret;
  232. if (node == NULL)
  233. return(NULL);
  234. if (indx < 0)
  235. return(NULL);
  236. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  237. if (ret == NULL) {
  238. xmlXPtrErrMemory("allocating point");
  239. return(NULL);
  240. }
  241. memset(ret, 0 , sizeof(xmlXPathObject));
  242. ret->type = XPATH_POINT;
  243. ret->user = (void *) node;
  244. ret->index = indx;
  245. return(ret);
  246. }
  247. /**
  248. * xmlXPtrRangeCheckOrder:
  249. * @range: an object range
  250. *
  251. * Make sure the points in the range are in the right order
  252. */
  253. static void
  254. xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) {
  255. int tmp;
  256. xmlNodePtr tmp2;
  257. if (range == NULL)
  258. return;
  259. if (range->type != XPATH_RANGE)
  260. return;
  261. if (range->user2 == NULL)
  262. return;
  263. tmp = xmlXPtrCmpPoints(range->user, range->index,
  264. range->user2, range->index2);
  265. if (tmp == -1) {
  266. tmp2 = range->user;
  267. range->user = range->user2;
  268. range->user2 = tmp2;
  269. tmp = range->index;
  270. range->index = range->index2;
  271. range->index2 = tmp;
  272. }
  273. }
  274. /**
  275. * xmlXPtrRangesEqual:
  276. * @range1: the first range
  277. * @range2: the second range
  278. *
  279. * Compare two ranges
  280. *
  281. * Returns 1 if equal, 0 otherwise
  282. */
  283. static int
  284. xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) {
  285. if (range1 == range2)
  286. return(1);
  287. if ((range1 == NULL) || (range2 == NULL))
  288. return(0);
  289. if (range1->type != range2->type)
  290. return(0);
  291. if (range1->type != XPATH_RANGE)
  292. return(0);
  293. if (range1->user != range2->user)
  294. return(0);
  295. if (range1->index != range2->index)
  296. return(0);
  297. if (range1->user2 != range2->user2)
  298. return(0);
  299. if (range1->index2 != range2->index2)
  300. return(0);
  301. return(1);
  302. }
  303. /**
  304. * xmlXPtrNewRangeInternal:
  305. * @start: the starting node
  306. * @startindex: the start index
  307. * @end: the ending point
  308. * @endindex: the ending index
  309. *
  310. * Internal function to create a new xmlXPathObjectPtr of type range
  311. *
  312. * Returns the newly created object.
  313. */
  314. static xmlXPathObjectPtr
  315. xmlXPtrNewRangeInternal(xmlNodePtr start, int startindex,
  316. xmlNodePtr end, int endindex) {
  317. xmlXPathObjectPtr ret;
  318. /*
  319. * Namespace nodes must be copied (see xmlXPathNodeSetDupNs).
  320. * Disallow them for now.
  321. */
  322. if ((start != NULL) && (start->type == XML_NAMESPACE_DECL))
  323. return(NULL);
  324. if ((end != NULL) && (end->type == XML_NAMESPACE_DECL))
  325. return(NULL);
  326. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  327. if (ret == NULL) {
  328. xmlXPtrErrMemory("allocating range");
  329. return(NULL);
  330. }
  331. memset(ret, 0, sizeof(xmlXPathObject));
  332. ret->type = XPATH_RANGE;
  333. ret->user = start;
  334. ret->index = startindex;
  335. ret->user2 = end;
  336. ret->index2 = endindex;
  337. return(ret);
  338. }
  339. /**
  340. * xmlXPtrNewRange:
  341. * @start: the starting node
  342. * @startindex: the start index
  343. * @end: the ending point
  344. * @endindex: the ending index
  345. *
  346. * Create a new xmlXPathObjectPtr of type range
  347. *
  348. * Returns the newly created object.
  349. */
  350. xmlXPathObjectPtr
  351. xmlXPtrNewRange(xmlNodePtr start, int startindex,
  352. xmlNodePtr end, int endindex) {
  353. xmlXPathObjectPtr ret;
  354. if (start == NULL)
  355. return(NULL);
  356. if (end == NULL)
  357. return(NULL);
  358. if (startindex < 0)
  359. return(NULL);
  360. if (endindex < 0)
  361. return(NULL);
  362. ret = xmlXPtrNewRangeInternal(start, startindex, end, endindex);
  363. xmlXPtrRangeCheckOrder(ret);
  364. return(ret);
  365. }
  366. /**
  367. * xmlXPtrNewRangePoints:
  368. * @start: the starting point
  369. * @end: the ending point
  370. *
  371. * Create a new xmlXPathObjectPtr of type range using 2 Points
  372. *
  373. * Returns the newly created object.
  374. */
  375. xmlXPathObjectPtr
  376. xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) {
  377. xmlXPathObjectPtr ret;
  378. if (start == NULL)
  379. return(NULL);
  380. if (end == NULL)
  381. return(NULL);
  382. if (start->type != XPATH_POINT)
  383. return(NULL);
  384. if (end->type != XPATH_POINT)
  385. return(NULL);
  386. ret = xmlXPtrNewRangeInternal(start->user, start->index, end->user,
  387. end->index);
  388. xmlXPtrRangeCheckOrder(ret);
  389. return(ret);
  390. }
  391. /**
  392. * xmlXPtrNewRangePointNode:
  393. * @start: the starting point
  394. * @end: the ending node
  395. *
  396. * Create a new xmlXPathObjectPtr of type range from a point to a node
  397. *
  398. * Returns the newly created object.
  399. */
  400. xmlXPathObjectPtr
  401. xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) {
  402. xmlXPathObjectPtr ret;
  403. if (start == NULL)
  404. return(NULL);
  405. if (end == NULL)
  406. return(NULL);
  407. if (start->type != XPATH_POINT)
  408. return(NULL);
  409. ret = xmlXPtrNewRangeInternal(start->user, start->index, end, -1);
  410. xmlXPtrRangeCheckOrder(ret);
  411. return(ret);
  412. }
  413. /**
  414. * xmlXPtrNewRangeNodePoint:
  415. * @start: the starting node
  416. * @end: the ending point
  417. *
  418. * Create a new xmlXPathObjectPtr of type range from a node to a point
  419. *
  420. * Returns the newly created object.
  421. */
  422. xmlXPathObjectPtr
  423. xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) {
  424. xmlXPathObjectPtr ret;
  425. if (start == NULL)
  426. return(NULL);
  427. if (end == NULL)
  428. return(NULL);
  429. if (end->type != XPATH_POINT)
  430. return(NULL);
  431. ret = xmlXPtrNewRangeInternal(start, -1, end->user, end->index);
  432. xmlXPtrRangeCheckOrder(ret);
  433. return(ret);
  434. }
  435. /**
  436. * xmlXPtrNewRangeNodes:
  437. * @start: the starting node
  438. * @end: the ending node
  439. *
  440. * Create a new xmlXPathObjectPtr of type range using 2 nodes
  441. *
  442. * Returns the newly created object.
  443. */
  444. xmlXPathObjectPtr
  445. xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) {
  446. xmlXPathObjectPtr ret;
  447. if (start == NULL)
  448. return(NULL);
  449. if (end == NULL)
  450. return(NULL);
  451. ret = xmlXPtrNewRangeInternal(start, -1, end, -1);
  452. xmlXPtrRangeCheckOrder(ret);
  453. return(ret);
  454. }
  455. /**
  456. * xmlXPtrNewCollapsedRange:
  457. * @start: the starting and ending node
  458. *
  459. * Create a new xmlXPathObjectPtr of type range using a single nodes
  460. *
  461. * Returns the newly created object.
  462. */
  463. xmlXPathObjectPtr
  464. xmlXPtrNewCollapsedRange(xmlNodePtr start) {
  465. xmlXPathObjectPtr ret;
  466. if (start == NULL)
  467. return(NULL);
  468. ret = xmlXPtrNewRangeInternal(start, -1, NULL, -1);
  469. return(ret);
  470. }
  471. /**
  472. * xmlXPtrNewRangeNodeObject:
  473. * @start: the starting node
  474. * @end: the ending object
  475. *
  476. * Create a new xmlXPathObjectPtr of type range from a not to an object
  477. *
  478. * Returns the newly created object.
  479. */
  480. xmlXPathObjectPtr
  481. xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) {
  482. xmlNodePtr endNode;
  483. int endIndex;
  484. xmlXPathObjectPtr ret;
  485. if (start == NULL)
  486. return(NULL);
  487. if (end == NULL)
  488. return(NULL);
  489. switch (end->type) {
  490. case XPATH_POINT:
  491. endNode = end->user;
  492. endIndex = end->index;
  493. break;
  494. case XPATH_RANGE:
  495. endNode = end->user2;
  496. endIndex = end->index2;
  497. break;
  498. case XPATH_NODESET:
  499. /*
  500. * Empty set ...
  501. */
  502. if ((end->nodesetval == NULL) || (end->nodesetval->nodeNr <= 0))
  503. return(NULL);
  504. endNode = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1];
  505. endIndex = -1;
  506. break;
  507. default:
  508. /* TODO */
  509. return(NULL);
  510. }
  511. ret = xmlXPtrNewRangeInternal(start, -1, endNode, endIndex);
  512. xmlXPtrRangeCheckOrder(ret);
  513. return(ret);
  514. }
  515. #define XML_RANGESET_DEFAULT 10
  516. /**
  517. * xmlXPtrLocationSetCreate:
  518. * @val: an initial xmlXPathObjectPtr, or NULL
  519. *
  520. * Create a new xmlLocationSetPtr of type double and of value @val
  521. *
  522. * Returns the newly created object.
  523. */
  524. xmlLocationSetPtr
  525. xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) {
  526. xmlLocationSetPtr ret;
  527. ret = (xmlLocationSetPtr) xmlMalloc(sizeof(xmlLocationSet));
  528. if (ret == NULL) {
  529. xmlXPtrErrMemory("allocating locationset");
  530. return(NULL);
  531. }
  532. memset(ret, 0 , sizeof(xmlLocationSet));
  533. if (val != NULL) {
  534. ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
  535. sizeof(xmlXPathObjectPtr));
  536. if (ret->locTab == NULL) {
  537. xmlXPtrErrMemory("allocating locationset");
  538. xmlFree(ret);
  539. return(NULL);
  540. }
  541. memset(ret->locTab, 0 ,
  542. XML_RANGESET_DEFAULT * sizeof(xmlXPathObjectPtr));
  543. ret->locMax = XML_RANGESET_DEFAULT;
  544. ret->locTab[ret->locNr++] = val;
  545. }
  546. return(ret);
  547. }
  548. /**
  549. * xmlXPtrLocationSetAdd:
  550. * @cur: the initial range set
  551. * @val: a new xmlXPathObjectPtr
  552. *
  553. * add a new xmlXPathObjectPtr to an existing LocationSet
  554. * If the location already exist in the set @val is freed.
  555. */
  556. void
  557. xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
  558. int i;
  559. if ((cur == NULL) || (val == NULL)) return;
  560. /*
  561. * check against doublons
  562. */
  563. for (i = 0;i < cur->locNr;i++) {
  564. if (xmlXPtrRangesEqual(cur->locTab[i], val)) {
  565. xmlXPathFreeObject(val);
  566. return;
  567. }
  568. }
  569. /*
  570. * grow the locTab if needed
  571. */
  572. if (cur->locMax == 0) {
  573. cur->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
  574. sizeof(xmlXPathObjectPtr));
  575. if (cur->locTab == NULL) {
  576. xmlXPtrErrMemory("adding location to set");
  577. return;
  578. }
  579. memset(cur->locTab, 0 ,
  580. XML_RANGESET_DEFAULT * sizeof(xmlXPathObjectPtr));
  581. cur->locMax = XML_RANGESET_DEFAULT;
  582. } else if (cur->locNr == cur->locMax) {
  583. xmlXPathObjectPtr *temp;
  584. cur->locMax *= 2;
  585. temp = (xmlXPathObjectPtr *) xmlRealloc(cur->locTab, cur->locMax *
  586. sizeof(xmlXPathObjectPtr));
  587. if (temp == NULL) {
  588. xmlXPtrErrMemory("adding location to set");
  589. return;
  590. }
  591. cur->locTab = temp;
  592. }
  593. cur->locTab[cur->locNr++] = val;
  594. }
  595. /**
  596. * xmlXPtrLocationSetMerge:
  597. * @val1: the first LocationSet
  598. * @val2: the second LocationSet
  599. *
  600. * Merges two rangesets, all ranges from @val2 are added to @val1
  601. *
  602. * Returns val1 once extended or NULL in case of error.
  603. */
  604. xmlLocationSetPtr
  605. xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) {
  606. int i;
  607. if (val1 == NULL) return(NULL);
  608. if (val2 == NULL) return(val1);
  609. /*
  610. * !!!!! this can be optimized a lot, knowing that both
  611. * val1 and val2 already have unicity of their values.
  612. */
  613. for (i = 0;i < val2->locNr;i++)
  614. xmlXPtrLocationSetAdd(val1, val2->locTab[i]);
  615. return(val1);
  616. }
  617. /**
  618. * xmlXPtrLocationSetDel:
  619. * @cur: the initial range set
  620. * @val: an xmlXPathObjectPtr
  621. *
  622. * Removes an xmlXPathObjectPtr from an existing LocationSet
  623. */
  624. void
  625. xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
  626. int i;
  627. if (cur == NULL) return;
  628. if (val == NULL) return;
  629. /*
  630. * check against doublons
  631. */
  632. for (i = 0;i < cur->locNr;i++)
  633. if (cur->locTab[i] == val) break;
  634. if (i >= cur->locNr) {
  635. return;
  636. }
  637. cur->locNr--;
  638. for (;i < cur->locNr;i++)
  639. cur->locTab[i] = cur->locTab[i + 1];
  640. cur->locTab[cur->locNr] = NULL;
  641. }
  642. /**
  643. * xmlXPtrLocationSetRemove:
  644. * @cur: the initial range set
  645. * @val: the index to remove
  646. *
  647. * Removes an entry from an existing LocationSet list.
  648. */
  649. void
  650. xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val) {
  651. if (cur == NULL) return;
  652. if (val >= cur->locNr) return;
  653. cur->locNr--;
  654. for (;val < cur->locNr;val++)
  655. cur->locTab[val] = cur->locTab[val + 1];
  656. cur->locTab[cur->locNr] = NULL;
  657. }
  658. /**
  659. * xmlXPtrFreeLocationSet:
  660. * @obj: the xmlLocationSetPtr to free
  661. *
  662. * Free the LocationSet compound (not the actual ranges !).
  663. */
  664. void
  665. xmlXPtrFreeLocationSet(xmlLocationSetPtr obj) {
  666. int i;
  667. if (obj == NULL) return;
  668. if (obj->locTab != NULL) {
  669. for (i = 0;i < obj->locNr; i++) {
  670. xmlXPathFreeObject(obj->locTab[i]);
  671. }
  672. xmlFree(obj->locTab);
  673. }
  674. xmlFree(obj);
  675. }
  676. /**
  677. * xmlXPtrNewLocationSetNodes:
  678. * @start: the start NodePtr value
  679. * @end: the end NodePtr value or NULL
  680. *
  681. * Create a new xmlXPathObjectPtr of type LocationSet and initialize
  682. * it with the single range made of the two nodes @start and @end
  683. *
  684. * Returns the newly created object.
  685. */
  686. xmlXPathObjectPtr
  687. xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) {
  688. xmlXPathObjectPtr ret;
  689. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  690. if (ret == NULL) {
  691. xmlXPtrErrMemory("allocating locationset");
  692. return(NULL);
  693. }
  694. memset(ret, 0 , sizeof(xmlXPathObject));
  695. ret->type = XPATH_LOCATIONSET;
  696. if (end == NULL)
  697. ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start));
  698. else
  699. ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewRangeNodes(start,end));
  700. return(ret);
  701. }
  702. /**
  703. * xmlXPtrNewLocationSetNodeSet:
  704. * @set: a node set
  705. *
  706. * Create a new xmlXPathObjectPtr of type LocationSet and initialize
  707. * it with all the nodes from @set
  708. *
  709. * Returns the newly created object.
  710. */
  711. xmlXPathObjectPtr
  712. xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) {
  713. xmlXPathObjectPtr ret;
  714. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  715. if (ret == NULL) {
  716. xmlXPtrErrMemory("allocating locationset");
  717. return(NULL);
  718. }
  719. memset(ret, 0, sizeof(xmlXPathObject));
  720. ret->type = XPATH_LOCATIONSET;
  721. if (set != NULL) {
  722. int i;
  723. xmlLocationSetPtr newset;
  724. newset = xmlXPtrLocationSetCreate(NULL);
  725. if (newset == NULL)
  726. return(ret);
  727. for (i = 0;i < set->nodeNr;i++)
  728. xmlXPtrLocationSetAdd(newset,
  729. xmlXPtrNewCollapsedRange(set->nodeTab[i]));
  730. ret->user = (void *) newset;
  731. }
  732. return(ret);
  733. }
  734. /**
  735. * xmlXPtrWrapLocationSet:
  736. * @val: the LocationSet value
  737. *
  738. * Wrap the LocationSet @val in a new xmlXPathObjectPtr
  739. *
  740. * Returns the newly created object.
  741. */
  742. xmlXPathObjectPtr
  743. xmlXPtrWrapLocationSet(xmlLocationSetPtr val) {
  744. xmlXPathObjectPtr ret;
  745. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  746. if (ret == NULL) {
  747. xmlXPtrErrMemory("allocating locationset");
  748. return(NULL);
  749. }
  750. memset(ret, 0, sizeof(xmlXPathObject));
  751. ret->type = XPATH_LOCATIONSET;
  752. ret->user = (void *) val;
  753. return(ret);
  754. }
  755. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  756. /************************************************************************
  757. * *
  758. * The parser *
  759. * *
  760. ************************************************************************/
  761. static void xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name);
  762. /*
  763. * Macros for accessing the content. Those should be used only by the parser,
  764. * and not exported.
  765. *
  766. * Dirty macros, i.e. one need to make assumption on the context to use them
  767. *
  768. * CUR returns the current xmlChar value, i.e. a 8 bit value
  769. * in ISO-Latin or UTF-8.
  770. * This should be used internally by the parser
  771. * only to compare to ASCII values otherwise it would break when
  772. * running with UTF-8 encoding.
  773. * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
  774. * to compare on ASCII based substring.
  775. * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
  776. * strings within the parser.
  777. * CURRENT Returns the current char value, with the full decoding of
  778. * UTF-8 if we are using this mode. It returns an int.
  779. * NEXT Skip to the next character, this does the proper decoding
  780. * in UTF-8 mode. It also pop-up unfinished entities on the fly.
  781. * It returns the pointer to the current xmlChar.
  782. */
  783. #define CUR (*ctxt->cur)
  784. #define SKIP(val) ctxt->cur += (val)
  785. #define NXT(val) ctxt->cur[(val)]
  786. #define SKIP_BLANKS \
  787. while (IS_BLANK_CH(*(ctxt->cur))) NEXT
  788. #define CURRENT (*ctxt->cur)
  789. #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
  790. /*
  791. * xmlXPtrGetChildNo:
  792. * @ctxt: the XPointer Parser context
  793. * @index: the child number
  794. *
  795. * Move the current node of the nodeset on the stack to the
  796. * given child if found
  797. */
  798. static void
  799. xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int indx) {
  800. xmlNodePtr cur = NULL;
  801. xmlXPathObjectPtr obj;
  802. xmlNodeSetPtr oldset;
  803. CHECK_TYPE(XPATH_NODESET);
  804. obj = valuePop(ctxt);
  805. oldset = obj->nodesetval;
  806. if ((indx <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) {
  807. xmlXPathFreeObject(obj);
  808. valuePush(ctxt, xmlXPathNewNodeSet(NULL));
  809. return;
  810. }
  811. cur = xmlXPtrGetNthChild(oldset->nodeTab[0], indx);
  812. if (cur == NULL) {
  813. xmlXPathFreeObject(obj);
  814. valuePush(ctxt, xmlXPathNewNodeSet(NULL));
  815. return;
  816. }
  817. oldset->nodeTab[0] = cur;
  818. valuePush(ctxt, obj);
  819. }
  820. /**
  821. * xmlXPtrEvalXPtrPart:
  822. * @ctxt: the XPointer Parser context
  823. * @name: the preparsed Scheme for the XPtrPart
  824. *
  825. * XPtrPart ::= 'xpointer' '(' XPtrExpr ')'
  826. * | Scheme '(' SchemeSpecificExpr ')'
  827. *
  828. * Scheme ::= NCName - 'xpointer' [VC: Non-XPointer schemes]
  829. *
  830. * SchemeSpecificExpr ::= StringWithBalancedParens
  831. *
  832. * StringWithBalancedParens ::=
  833. * [^()]* ('(' StringWithBalancedParens ')' [^()]*)*
  834. * [VC: Parenthesis escaping]
  835. *
  836. * XPtrExpr ::= Expr [VC: Parenthesis escaping]
  837. *
  838. * VC: Parenthesis escaping:
  839. * The end of an XPointer part is signaled by the right parenthesis ")"
  840. * character that is balanced with the left parenthesis "(" character
  841. * that began the part. Any unbalanced parenthesis character inside the
  842. * expression, even within literals, must be escaped with a circumflex (^)
  843. * character preceding it. If the expression contains any literal
  844. * occurrences of the circumflex, each must be escaped with an additional
  845. * circumflex (that is, ^^). If the unescaped parentheses in the expression
  846. * are not balanced, a syntax error results.
  847. *
  848. * Parse and evaluate an XPtrPart. Basically it generates the unescaped
  849. * string and if the scheme is 'xpointer' it will call the XPath interpreter.
  850. *
  851. * TODO: there is no new scheme registration mechanism
  852. */
  853. static void
  854. xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) {
  855. xmlChar *buffer, *cur;
  856. int len;
  857. int level;
  858. if (name == NULL)
  859. name = xmlXPathParseName(ctxt);
  860. if (name == NULL)
  861. XP_ERROR(XPATH_EXPR_ERROR);
  862. if (CUR != '(') {
  863. xmlFree(name);
  864. XP_ERROR(XPATH_EXPR_ERROR);
  865. }
  866. NEXT;
  867. level = 1;
  868. len = xmlStrlen(ctxt->cur);
  869. len++;
  870. buffer = (xmlChar *) xmlMallocAtomic(len);
  871. if (buffer == NULL) {
  872. xmlXPtrErrMemory("allocating buffer");
  873. xmlFree(name);
  874. return;
  875. }
  876. cur = buffer;
  877. while (CUR != 0) {
  878. if (CUR == ')') {
  879. level--;
  880. if (level == 0) {
  881. NEXT;
  882. break;
  883. }
  884. } else if (CUR == '(') {
  885. level++;
  886. } else if (CUR == '^') {
  887. if ((NXT(1) == ')') || (NXT(1) == '(') || (NXT(1) == '^')) {
  888. NEXT;
  889. }
  890. }
  891. *cur++ = CUR;
  892. NEXT;
  893. }
  894. *cur = 0;
  895. if ((level != 0) && (CUR == 0)) {
  896. xmlFree(name);
  897. xmlFree(buffer);
  898. XP_ERROR(XPTR_SYNTAX_ERROR);
  899. }
  900. if (xmlStrEqual(name, (xmlChar *) "xpointer") ||
  901. xmlStrEqual(name, (xmlChar *) "xpath1")) {
  902. const xmlChar *oldBase = ctxt->base;
  903. const xmlChar *oldCur = ctxt->cur;
  904. ctxt->cur = ctxt->base = buffer;
  905. /*
  906. * To evaluate an xpointer scheme element (4.3) we need:
  907. * context initialized to the root
  908. * context position initialized to 1
  909. * context size initialized to 1
  910. */
  911. ctxt->context->node = (xmlNodePtr)ctxt->context->doc;
  912. ctxt->context->proximityPosition = 1;
  913. ctxt->context->contextSize = 1;
  914. #ifdef LIBXML_XPTR_LOCS_ENABLED
  915. ctxt->xptr = xmlStrEqual(name, (xmlChar *) "xpointer");
  916. #endif
  917. xmlXPathEvalExpr(ctxt);
  918. ctxt->base = oldBase;
  919. ctxt->cur = oldCur;
  920. } else if (xmlStrEqual(name, (xmlChar *) "element")) {
  921. const xmlChar *oldBase = ctxt->base;
  922. const xmlChar *oldCur = ctxt->cur;
  923. xmlChar *name2;
  924. ctxt->cur = ctxt->base = buffer;
  925. if (buffer[0] == '/') {
  926. xmlXPathRoot(ctxt);
  927. xmlXPtrEvalChildSeq(ctxt, NULL);
  928. } else {
  929. name2 = xmlXPathParseName(ctxt);
  930. if (name2 == NULL) {
  931. ctxt->base = oldBase;
  932. ctxt->cur = oldCur;
  933. xmlFree(buffer);
  934. xmlFree(name);
  935. XP_ERROR(XPATH_EXPR_ERROR);
  936. }
  937. xmlXPtrEvalChildSeq(ctxt, name2);
  938. }
  939. ctxt->base = oldBase;
  940. ctxt->cur = oldCur;
  941. #ifdef XPTR_XMLNS_SCHEME
  942. } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) {
  943. const xmlChar *oldBase = ctxt->base;
  944. const xmlChar *oldCur = ctxt->cur;
  945. xmlChar *prefix;
  946. ctxt->cur = ctxt->base = buffer;
  947. prefix = xmlXPathParseNCName(ctxt);
  948. if (prefix == NULL) {
  949. ctxt->base = oldBase;
  950. ctxt->cur = oldCur;
  951. xmlFree(buffer);
  952. xmlFree(name);
  953. XP_ERROR(XPTR_SYNTAX_ERROR);
  954. }
  955. SKIP_BLANKS;
  956. if (CUR != '=') {
  957. ctxt->base = oldBase;
  958. ctxt->cur = oldCur;
  959. xmlFree(prefix);
  960. xmlFree(buffer);
  961. xmlFree(name);
  962. XP_ERROR(XPTR_SYNTAX_ERROR);
  963. }
  964. NEXT;
  965. SKIP_BLANKS;
  966. xmlXPathRegisterNs(ctxt->context, prefix, ctxt->cur);
  967. ctxt->base = oldBase;
  968. ctxt->cur = oldCur;
  969. xmlFree(prefix);
  970. #endif /* XPTR_XMLNS_SCHEME */
  971. } else {
  972. xmlXPtrErr(ctxt, XML_XPTR_UNKNOWN_SCHEME,
  973. "unsupported scheme '%s'\n", name);
  974. }
  975. xmlFree(buffer);
  976. xmlFree(name);
  977. }
  978. /**
  979. * xmlXPtrEvalFullXPtr:
  980. * @ctxt: the XPointer Parser context
  981. * @name: the preparsed Scheme for the first XPtrPart
  982. *
  983. * FullXPtr ::= XPtrPart (S? XPtrPart)*
  984. *
  985. * As the specs says:
  986. * -----------
  987. * When multiple XPtrParts are provided, they must be evaluated in
  988. * left-to-right order. If evaluation of one part fails, the nexti
  989. * is evaluated. The following conditions cause XPointer part failure:
  990. *
  991. * - An unknown scheme
  992. * - A scheme that does not locate any sub-resource present in the resource
  993. * - A scheme that is not applicable to the media type of the resource
  994. *
  995. * The XPointer application must consume a failed XPointer part and
  996. * attempt to evaluate the next one, if any. The result of the first
  997. * XPointer part whose evaluation succeeds is taken to be the fragment
  998. * located by the XPointer as a whole. If all the parts fail, the result
  999. * for the XPointer as a whole is a sub-resource error.
  1000. * -----------
  1001. *
  1002. * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based
  1003. * expressions or other schemes.
  1004. */
  1005. static void
  1006. xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) {
  1007. if (name == NULL)
  1008. name = xmlXPathParseName(ctxt);
  1009. if (name == NULL)
  1010. XP_ERROR(XPATH_EXPR_ERROR);
  1011. while (name != NULL) {
  1012. ctxt->error = XPATH_EXPRESSION_OK;
  1013. xmlXPtrEvalXPtrPart(ctxt, name);
  1014. /* in case of syntax error, break here */
  1015. if ((ctxt->error != XPATH_EXPRESSION_OK) &&
  1016. (ctxt->error != XML_XPTR_UNKNOWN_SCHEME))
  1017. return;
  1018. /*
  1019. * If the returned value is a non-empty nodeset
  1020. * or location set, return here.
  1021. */
  1022. if (ctxt->value != NULL) {
  1023. xmlXPathObjectPtr obj = ctxt->value;
  1024. switch (obj->type) {
  1025. #ifdef LIBXML_XPTR_LOCS_ENABLED
  1026. case XPATH_LOCATIONSET: {
  1027. xmlLocationSetPtr loc = ctxt->value->user;
  1028. if ((loc != NULL) && (loc->locNr > 0))
  1029. return;
  1030. break;
  1031. }
  1032. #endif
  1033. case XPATH_NODESET: {
  1034. xmlNodeSetPtr loc = ctxt->value->nodesetval;
  1035. if ((loc != NULL) && (loc->nodeNr > 0))
  1036. return;
  1037. break;
  1038. }
  1039. default:
  1040. break;
  1041. }
  1042. /*
  1043. * Evaluating to improper values is equivalent to
  1044. * a sub-resource error, clean-up the stack
  1045. */
  1046. do {
  1047. obj = valuePop(ctxt);
  1048. if (obj != NULL) {
  1049. xmlXPathFreeObject(obj);
  1050. }
  1051. } while (obj != NULL);
  1052. }
  1053. /*
  1054. * Is there another XPointer part.
  1055. */
  1056. SKIP_BLANKS;
  1057. name = xmlXPathParseName(ctxt);
  1058. }
  1059. }
  1060. /**
  1061. * xmlXPtrEvalChildSeq:
  1062. * @ctxt: the XPointer Parser context
  1063. * @name: a possible ID name of the child sequence
  1064. *
  1065. * ChildSeq ::= '/1' ('/' [0-9]*)*
  1066. * | Name ('/' [0-9]*)+
  1067. *
  1068. * Parse and evaluate a Child Sequence. This routine also handle the
  1069. * case of a Bare Name used to get a document ID.
  1070. */
  1071. static void
  1072. xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) {
  1073. /*
  1074. * XPointer don't allow by syntax to address in multirooted trees
  1075. * this might prove useful in some cases, warn about it.
  1076. */
  1077. if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) {
  1078. xmlXPtrErr(ctxt, XML_XPTR_CHILDSEQ_START,
  1079. "warning: ChildSeq not starting by /1\n", NULL);
  1080. }
  1081. if (name != NULL) {
  1082. valuePush(ctxt, xmlXPathNewString(name));
  1083. xmlFree(name);
  1084. xmlXPathIdFunction(ctxt, 1);
  1085. CHECK_ERROR;
  1086. }
  1087. while (CUR == '/') {
  1088. int child = 0, overflow = 0;
  1089. NEXT;
  1090. while ((CUR >= '0') && (CUR <= '9')) {
  1091. int d = CUR - '0';
  1092. if (child > INT_MAX / 10)
  1093. overflow = 1;
  1094. else
  1095. child *= 10;
  1096. if (child > INT_MAX - d)
  1097. overflow = 1;
  1098. else
  1099. child += d;
  1100. NEXT;
  1101. }
  1102. if (overflow)
  1103. child = 0;
  1104. xmlXPtrGetChildNo(ctxt, child);
  1105. }
  1106. }
  1107. /**
  1108. * xmlXPtrEvalXPointer:
  1109. * @ctxt: the XPointer Parser context
  1110. *
  1111. * XPointer ::= Name
  1112. * | ChildSeq
  1113. * | FullXPtr
  1114. *
  1115. * Parse and evaluate an XPointer
  1116. */
  1117. static void
  1118. xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) {
  1119. if (ctxt->valueTab == NULL) {
  1120. /* Allocate the value stack */
  1121. ctxt->valueTab = (xmlXPathObjectPtr *)
  1122. xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  1123. if (ctxt->valueTab == NULL) {
  1124. xmlXPtrErrMemory("allocating evaluation context");
  1125. return;
  1126. }
  1127. ctxt->valueNr = 0;
  1128. ctxt->valueMax = 10;
  1129. ctxt->value = NULL;
  1130. }
  1131. SKIP_BLANKS;
  1132. if (CUR == '/') {
  1133. xmlXPathRoot(ctxt);
  1134. xmlXPtrEvalChildSeq(ctxt, NULL);
  1135. } else {
  1136. xmlChar *name;
  1137. name = xmlXPathParseName(ctxt);
  1138. if (name == NULL)
  1139. XP_ERROR(XPATH_EXPR_ERROR);
  1140. if (CUR == '(') {
  1141. xmlXPtrEvalFullXPtr(ctxt, name);
  1142. /* Short evaluation */
  1143. return;
  1144. } else {
  1145. /* this handle both Bare Names and Child Sequences */
  1146. xmlXPtrEvalChildSeq(ctxt, name);
  1147. }
  1148. }
  1149. SKIP_BLANKS;
  1150. if (CUR != 0)
  1151. XP_ERROR(XPATH_EXPR_ERROR);
  1152. }
  1153. /************************************************************************
  1154. * *
  1155. * General routines *
  1156. * *
  1157. ************************************************************************/
  1158. #ifdef LIBXML_XPTR_LOCS_ENABLED
  1159. static
  1160. void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
  1161. static
  1162. void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
  1163. static
  1164. void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
  1165. static
  1166. void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs);
  1167. static
  1168. void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs);
  1169. static
  1170. void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs);
  1171. static
  1172. void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
  1173. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  1174. /**
  1175. * xmlXPtrNewContext:
  1176. * @doc: the XML document
  1177. * @here: the node that directly contains the XPointer being evaluated or NULL
  1178. * @origin: the element from which a user or program initiated traversal of
  1179. * the link, or NULL.
  1180. *
  1181. * Create a new XPointer context
  1182. *
  1183. * Returns the xmlXPathContext just allocated.
  1184. */
  1185. xmlXPathContextPtr
  1186. xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) {
  1187. xmlXPathContextPtr ret;
  1188. (void) here;
  1189. (void) origin;
  1190. ret = xmlXPathNewContext(doc);
  1191. if (ret == NULL)
  1192. return(ret);
  1193. #ifdef LIBXML_XPTR_LOCS_ENABLED
  1194. ret->xptr = 1;
  1195. ret->here = here;
  1196. ret->origin = origin;
  1197. xmlXPathRegisterFunc(ret, (xmlChar *)"range",
  1198. xmlXPtrRangeFunction);
  1199. xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside",
  1200. xmlXPtrRangeInsideFunction);
  1201. xmlXPathRegisterFunc(ret, (xmlChar *)"string-range",
  1202. xmlXPtrStringRangeFunction);
  1203. xmlXPathRegisterFunc(ret, (xmlChar *)"start-point",
  1204. xmlXPtrStartPointFunction);
  1205. xmlXPathRegisterFunc(ret, (xmlChar *)"end-point",
  1206. xmlXPtrEndPointFunction);
  1207. xmlXPathRegisterFunc(ret, (xmlChar *)"here",
  1208. xmlXPtrHereFunction);
  1209. xmlXPathRegisterFunc(ret, (xmlChar *)" origin",
  1210. xmlXPtrOriginFunction);
  1211. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  1212. return(ret);
  1213. }
  1214. /**
  1215. * xmlXPtrEval:
  1216. * @str: the XPointer expression
  1217. * @ctx: the XPointer context
  1218. *
  1219. * Evaluate the XPath Location Path in the given context.
  1220. *
  1221. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  1222. * the caller has to free the object.
  1223. */
  1224. xmlXPathObjectPtr
  1225. xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) {
  1226. xmlXPathParserContextPtr ctxt;
  1227. xmlXPathObjectPtr res = NULL, tmp;
  1228. xmlXPathObjectPtr init = NULL;
  1229. int stack = 0;
  1230. xmlInitParser();
  1231. if ((ctx == NULL) || (str == NULL))
  1232. return(NULL);
  1233. ctxt = xmlXPathNewParserContext(str, ctx);
  1234. if (ctxt == NULL)
  1235. return(NULL);
  1236. xmlXPtrEvalXPointer(ctxt);
  1237. if ((ctxt->value != NULL) &&
  1238. #ifdef LIBXML_XPTR_LOCS_ENABLED
  1239. (ctxt->value->type != XPATH_LOCATIONSET) &&
  1240. #endif
  1241. (ctxt->value->type != XPATH_NODESET)) {
  1242. xmlXPtrErr(ctxt, XML_XPTR_EVAL_FAILED,
  1243. "xmlXPtrEval: evaluation failed to return a node set\n",
  1244. NULL);
  1245. } else {
  1246. res = valuePop(ctxt);
  1247. }
  1248. do {
  1249. tmp = valuePop(ctxt);
  1250. if (tmp != NULL) {
  1251. if (tmp != init) {
  1252. if (tmp->type == XPATH_NODESET) {
  1253. /*
  1254. * Evaluation may push a root nodeset which is unused
  1255. */
  1256. xmlNodeSetPtr set;
  1257. set = tmp->nodesetval;
  1258. if ((set == NULL) || (set->nodeNr != 1) ||
  1259. (set->nodeTab[0] != (xmlNodePtr) ctx->doc))
  1260. stack++;
  1261. } else
  1262. stack++;
  1263. }
  1264. xmlXPathFreeObject(tmp);
  1265. }
  1266. } while (tmp != NULL);
  1267. if (stack != 0) {
  1268. xmlXPtrErr(ctxt, XML_XPTR_EXTRA_OBJECTS,
  1269. "xmlXPtrEval: object(s) left on the eval stack\n",
  1270. NULL);
  1271. }
  1272. if (ctxt->error != XPATH_EXPRESSION_OK) {
  1273. xmlXPathFreeObject(res);
  1274. res = NULL;
  1275. }
  1276. xmlXPathFreeParserContext(ctxt);
  1277. return(res);
  1278. }
  1279. #ifdef LIBXML_XPTR_LOCS_ENABLED
  1280. /**
  1281. * xmlXPtrBuildRangeNodeList:
  1282. * @range: a range object
  1283. *
  1284. * Build a node list tree copy of the range
  1285. *
  1286. * Returns an xmlNodePtr list or NULL.
  1287. * the caller has to free the node tree.
  1288. */
  1289. static xmlNodePtr
  1290. xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) {
  1291. /* pointers to generated nodes */
  1292. xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
  1293. /* pointers to traversal nodes */
  1294. xmlNodePtr start, cur, end;
  1295. int index1, index2;
  1296. if (range == NULL)
  1297. return(NULL);
  1298. if (range->type != XPATH_RANGE)
  1299. return(NULL);
  1300. start = (xmlNodePtr) range->user;
  1301. if ((start == NULL) || (start->type == XML_NAMESPACE_DECL))
  1302. return(NULL);
  1303. end = range->user2;
  1304. if (end == NULL)
  1305. return(xmlCopyNode(start, 1));
  1306. if (end->type == XML_NAMESPACE_DECL)
  1307. return(NULL);
  1308. cur = start;
  1309. index1 = range->index;
  1310. index2 = range->index2;
  1311. while (cur != NULL) {
  1312. if (cur == end) {
  1313. if (cur->type == XML_TEXT_NODE) {
  1314. const xmlChar *content = cur->content;
  1315. int len;
  1316. if (content == NULL) {
  1317. tmp = xmlNewTextLen(NULL, 0);
  1318. } else {
  1319. len = index2;
  1320. if ((cur == start) && (index1 > 1)) {
  1321. content += (index1 - 1);
  1322. len -= (index1 - 1);
  1323. index1 = 0;
  1324. } else {
  1325. len = index2;
  1326. }
  1327. tmp = xmlNewTextLen(content, len);
  1328. }
  1329. /* single sub text node selection */
  1330. if (list == NULL)
  1331. return(tmp);
  1332. /* prune and return full set */
  1333. if (last != NULL)
  1334. xmlAddNextSibling(last, tmp);
  1335. else
  1336. xmlAddChild(parent, tmp);
  1337. return(list);
  1338. } else {
  1339. tmp = xmlCopyNode(cur, 0);
  1340. if (list == NULL) {
  1341. list = tmp;
  1342. parent = tmp;
  1343. } else {
  1344. if (last != NULL)
  1345. parent = xmlAddNextSibling(last, tmp);
  1346. else
  1347. parent = xmlAddChild(parent, tmp);
  1348. }
  1349. last = NULL;
  1350. if (index2 > 1) {
  1351. end = xmlXPtrGetNthChild(cur, index2 - 1);
  1352. index2 = 0;
  1353. }
  1354. if ((cur == start) && (index1 > 1)) {
  1355. cur = xmlXPtrGetNthChild(cur, index1 - 1);
  1356. index1 = 0;
  1357. } else {
  1358. cur = cur->children;
  1359. }
  1360. /*
  1361. * Now gather the remaining nodes from cur to end
  1362. */
  1363. continue; /* while */
  1364. }
  1365. } else if ((cur == start) &&
  1366. (list == NULL) /* looks superfluous but ... */ ) {
  1367. if ((cur->type == XML_TEXT_NODE) ||
  1368. (cur->type == XML_CDATA_SECTION_NODE)) {
  1369. const xmlChar *content = cur->content;
  1370. if (content == NULL) {
  1371. tmp = xmlNewTextLen(NULL, 0);
  1372. } else {
  1373. if (index1 > 1) {
  1374. content += (index1 - 1);
  1375. }
  1376. tmp = xmlNewText(content);
  1377. }
  1378. last = list = tmp;
  1379. } else {
  1380. if ((cur == start) && (index1 > 1)) {
  1381. tmp = xmlCopyNode(cur, 0);
  1382. list = tmp;
  1383. parent = tmp;
  1384. last = NULL;
  1385. cur = xmlXPtrGetNthChild(cur, index1 - 1);
  1386. index1 = 0;
  1387. /*
  1388. * Now gather the remaining nodes from cur to end
  1389. */
  1390. continue; /* while */
  1391. }
  1392. tmp = xmlCopyNode(cur, 1);
  1393. list = tmp;
  1394. parent = NULL;
  1395. last = tmp;
  1396. }
  1397. } else {
  1398. tmp = NULL;
  1399. switch (cur->type) {
  1400. case XML_DTD_NODE:
  1401. case XML_ELEMENT_DECL:
  1402. case XML_ATTRIBUTE_DECL:
  1403. case XML_ENTITY_NODE:
  1404. /* Do not copy DTD information */
  1405. break;
  1406. case XML_ENTITY_DECL:
  1407. TODO /* handle crossing entities -> stack needed */
  1408. break;
  1409. case XML_XINCLUDE_START:
  1410. case XML_XINCLUDE_END:
  1411. /* don't consider it part of the tree content */
  1412. break;
  1413. case XML_ATTRIBUTE_NODE:
  1414. /* Humm, should not happen ! */
  1415. STRANGE
  1416. break;
  1417. default:
  1418. tmp = xmlCopyNode(cur, 1);
  1419. break;
  1420. }
  1421. if (tmp != NULL) {
  1422. if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
  1423. STRANGE
  1424. return(NULL);
  1425. }
  1426. if (last != NULL)
  1427. xmlAddNextSibling(last, tmp);
  1428. else {
  1429. last = xmlAddChild(parent, tmp);
  1430. }
  1431. }
  1432. }
  1433. /*
  1434. * Skip to next node in document order
  1435. */
  1436. if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
  1437. STRANGE
  1438. return(NULL);
  1439. }
  1440. cur = xmlXPtrAdvanceNode(cur, NULL);
  1441. }
  1442. return(list);
  1443. }
  1444. /**
  1445. * xmlXPtrBuildNodeList:
  1446. * @obj: the XPointer result from the evaluation.
  1447. *
  1448. * Build a node list tree copy of the XPointer result.
  1449. * This will drop Attributes and Namespace declarations.
  1450. *
  1451. * Returns an xmlNodePtr list or NULL.
  1452. * the caller has to free the node tree.
  1453. */
  1454. xmlNodePtr
  1455. xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) {
  1456. xmlNodePtr list = NULL, last = NULL;
  1457. int i;
  1458. if (obj == NULL)
  1459. return(NULL);
  1460. switch (obj->type) {
  1461. case XPATH_NODESET: {
  1462. xmlNodeSetPtr set = obj->nodesetval;
  1463. if (set == NULL)
  1464. return(NULL);
  1465. for (i = 0;i < set->nodeNr;i++) {
  1466. if (set->nodeTab[i] == NULL)
  1467. continue;
  1468. switch (set->nodeTab[i]->type) {
  1469. case XML_TEXT_NODE:
  1470. case XML_CDATA_SECTION_NODE:
  1471. case XML_ELEMENT_NODE:
  1472. case XML_ENTITY_REF_NODE:
  1473. case XML_ENTITY_NODE:
  1474. case XML_PI_NODE:
  1475. case XML_COMMENT_NODE:
  1476. case XML_DOCUMENT_NODE:
  1477. case XML_HTML_DOCUMENT_NODE:
  1478. case XML_XINCLUDE_START:
  1479. case XML_XINCLUDE_END:
  1480. break;
  1481. case XML_ATTRIBUTE_NODE:
  1482. case XML_NAMESPACE_DECL:
  1483. case XML_DOCUMENT_TYPE_NODE:
  1484. case XML_DOCUMENT_FRAG_NODE:
  1485. case XML_NOTATION_NODE:
  1486. case XML_DTD_NODE:
  1487. case XML_ELEMENT_DECL:
  1488. case XML_ATTRIBUTE_DECL:
  1489. case XML_ENTITY_DECL:
  1490. continue; /* for */
  1491. }
  1492. if (last == NULL)
  1493. list = last = xmlCopyNode(set->nodeTab[i], 1);
  1494. else {
  1495. xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1));
  1496. if (last->next != NULL)
  1497. last = last->next;
  1498. }
  1499. }
  1500. break;
  1501. }
  1502. case XPATH_LOCATIONSET: {
  1503. xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
  1504. if (set == NULL)
  1505. return(NULL);
  1506. for (i = 0;i < set->locNr;i++) {
  1507. if (last == NULL)
  1508. list = last = xmlXPtrBuildNodeList(set->locTab[i]);
  1509. else
  1510. xmlAddNextSibling(last,
  1511. xmlXPtrBuildNodeList(set->locTab[i]));
  1512. if (last != NULL) {
  1513. while (last->next != NULL)
  1514. last = last->next;
  1515. }
  1516. }
  1517. break;
  1518. }
  1519. case XPATH_RANGE:
  1520. return(xmlXPtrBuildRangeNodeList(obj));
  1521. case XPATH_POINT:
  1522. return(xmlCopyNode(obj->user, 0));
  1523. default:
  1524. break;
  1525. }
  1526. return(list);
  1527. }
  1528. /************************************************************************
  1529. * *
  1530. * XPointer functions *
  1531. * *
  1532. ************************************************************************/
  1533. /**
  1534. * xmlXPtrNbLocChildren:
  1535. * @node: an xmlNodePtr
  1536. *
  1537. * Count the number of location children of @node or the length of the
  1538. * string value in case of text/PI/Comments nodes
  1539. *
  1540. * Returns the number of location children
  1541. */
  1542. static int
  1543. xmlXPtrNbLocChildren(xmlNodePtr node) {
  1544. int ret = 0;
  1545. if (node == NULL)
  1546. return(-1);
  1547. switch (node->type) {
  1548. case XML_HTML_DOCUMENT_NODE:
  1549. case XML_DOCUMENT_NODE:
  1550. case XML_ELEMENT_NODE:
  1551. node = node->children;
  1552. while (node != NULL) {
  1553. if (node->type == XML_ELEMENT_NODE)
  1554. ret++;
  1555. node = node->next;
  1556. }
  1557. break;
  1558. case XML_ATTRIBUTE_NODE:
  1559. return(-1);
  1560. case XML_PI_NODE:
  1561. case XML_COMMENT_NODE:
  1562. case XML_TEXT_NODE:
  1563. case XML_CDATA_SECTION_NODE:
  1564. case XML_ENTITY_REF_NODE:
  1565. ret = xmlStrlen(node->content);
  1566. break;
  1567. default:
  1568. return(-1);
  1569. }
  1570. return(ret);
  1571. }
  1572. /**
  1573. * xmlXPtrHereFunction:
  1574. * @ctxt: the XPointer Parser context
  1575. * @nargs: the number of args
  1576. *
  1577. * Function implementing here() operation
  1578. * as described in 5.4.3
  1579. */
  1580. static void
  1581. xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  1582. CHECK_ARITY(0);
  1583. if (ctxt->context->here == NULL)
  1584. XP_ERROR(XPTR_SYNTAX_ERROR);
  1585. valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL));
  1586. }
  1587. /**
  1588. * xmlXPtrOriginFunction:
  1589. * @ctxt: the XPointer Parser context
  1590. * @nargs: the number of args
  1591. *
  1592. * Function implementing origin() operation
  1593. * as described in 5.4.3
  1594. */
  1595. static void
  1596. xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  1597. CHECK_ARITY(0);
  1598. if (ctxt->context->origin == NULL)
  1599. XP_ERROR(XPTR_SYNTAX_ERROR);
  1600. valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL));
  1601. }
  1602. /**
  1603. * xmlXPtrStartPointFunction:
  1604. * @ctxt: the XPointer Parser context
  1605. * @nargs: the number of args
  1606. *
  1607. * Function implementing start-point() operation
  1608. * as described in 5.4.3
  1609. * ----------------
  1610. * location-set start-point(location-set)
  1611. *
  1612. * For each location x in the argument location-set, start-point adds a
  1613. * location of type point to the result location-set. That point represents
  1614. * the start point of location x and is determined by the following rules:
  1615. *
  1616. * - If x is of type point, the start point is x.
  1617. * - If x is of type range, the start point is the start point of x.
  1618. * - If x is of type root, element, text, comment, or processing instruction,
  1619. * - the container node of the start point is x and the index is 0.
  1620. * - If x is of type attribute or namespace, the function must signal a
  1621. * syntax error.
  1622. * ----------------
  1623. *
  1624. */
  1625. static void
  1626. xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  1627. xmlXPathObjectPtr tmp, obj, point;
  1628. xmlLocationSetPtr newset = NULL;
  1629. xmlLocationSetPtr oldset = NULL;
  1630. CHECK_ARITY(1);
  1631. if ((ctxt->value == NULL) ||
  1632. ((ctxt->value->type != XPATH_LOCATIONSET) &&
  1633. (ctxt->value->type != XPATH_NODESET)))
  1634. XP_ERROR(XPATH_INVALID_TYPE)
  1635. obj = valuePop(ctxt);
  1636. if (obj->type == XPATH_NODESET) {
  1637. /*
  1638. * First convert to a location set
  1639. */
  1640. tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
  1641. xmlXPathFreeObject(obj);
  1642. if (tmp == NULL)
  1643. XP_ERROR(XPATH_MEMORY_ERROR)
  1644. obj = tmp;
  1645. }
  1646. newset = xmlXPtrLocationSetCreate(NULL);
  1647. if (newset == NULL) {
  1648. xmlXPathFreeObject(obj);
  1649. XP_ERROR(XPATH_MEMORY_ERROR);
  1650. }
  1651. oldset = (xmlLocationSetPtr) obj->user;
  1652. if (oldset != NULL) {
  1653. int i;
  1654. for (i = 0; i < oldset->locNr; i++) {
  1655. tmp = oldset->locTab[i];
  1656. if (tmp == NULL)
  1657. continue;
  1658. point = NULL;
  1659. switch (tmp->type) {
  1660. case XPATH_POINT:
  1661. point = xmlXPtrNewPoint(tmp->user, tmp->index);
  1662. break;
  1663. case XPATH_RANGE: {
  1664. xmlNodePtr node = tmp->user;
  1665. if (node != NULL) {
  1666. if ((node->type == XML_ATTRIBUTE_NODE) ||
  1667. (node->type == XML_NAMESPACE_DECL)) {
  1668. xmlXPathFreeObject(obj);
  1669. xmlXPtrFreeLocationSet(newset);
  1670. XP_ERROR(XPTR_SYNTAX_ERROR);
  1671. }
  1672. point = xmlXPtrNewPoint(node, tmp->index);
  1673. }
  1674. break;
  1675. }
  1676. default:
  1677. /*** Should we raise an error ?
  1678. xmlXPathFreeObject(obj);
  1679. xmlXPathFreeObject(newset);
  1680. XP_ERROR(XPATH_INVALID_TYPE)
  1681. ***/
  1682. break;
  1683. }
  1684. if (point != NULL)
  1685. xmlXPtrLocationSetAdd(newset, point);
  1686. }
  1687. }
  1688. xmlXPathFreeObject(obj);
  1689. valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
  1690. }
  1691. /**
  1692. * xmlXPtrEndPointFunction:
  1693. * @ctxt: the XPointer Parser context
  1694. * @nargs: the number of args
  1695. *
  1696. * Function implementing end-point() operation
  1697. * as described in 5.4.3
  1698. * ----------------------------
  1699. * location-set end-point(location-set)
  1700. *
  1701. * For each location x in the argument location-set, end-point adds a
  1702. * location of type point to the result location-set. That point represents
  1703. * the end point of location x and is determined by the following rules:
  1704. *
  1705. * - If x is of type point, the resulting point is x.
  1706. * - If x is of type range, the resulting point is the end point of x.
  1707. * - If x is of type root or element, the container node of the resulting
  1708. * point is x and the index is the number of location children of x.
  1709. * - If x is of type text, comment, or processing instruction, the container
  1710. * node of the resulting point is x and the index is the length of the
  1711. * string-value of x.
  1712. * - If x is of type attribute or namespace, the function must signal a
  1713. * syntax error.
  1714. * ----------------------------
  1715. */
  1716. static void
  1717. xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  1718. xmlXPathObjectPtr tmp, obj, point;
  1719. xmlLocationSetPtr newset = NULL;
  1720. xmlLocationSetPtr oldset = NULL;
  1721. CHECK_ARITY(1);
  1722. if ((ctxt->value == NULL) ||
  1723. ((ctxt->value->type != XPATH_LOCATIONSET) &&
  1724. (ctxt->value->type != XPATH_NODESET)))
  1725. XP_ERROR(XPATH_INVALID_TYPE)
  1726. obj = valuePop(ctxt);
  1727. if (obj->type == XPATH_NODESET) {
  1728. /*
  1729. * First convert to a location set
  1730. */
  1731. tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
  1732. xmlXPathFreeObject(obj);
  1733. if (tmp == NULL)
  1734. XP_ERROR(XPATH_MEMORY_ERROR)
  1735. obj = tmp;
  1736. }
  1737. newset = xmlXPtrLocationSetCreate(NULL);
  1738. if (newset == NULL) {
  1739. xmlXPathFreeObject(obj);
  1740. XP_ERROR(XPATH_MEMORY_ERROR);
  1741. }
  1742. oldset = (xmlLocationSetPtr) obj->user;
  1743. if (oldset != NULL) {
  1744. int i;
  1745. for (i = 0; i < oldset->locNr; i++) {
  1746. tmp = oldset->locTab[i];
  1747. if (tmp == NULL)
  1748. continue;
  1749. point = NULL;
  1750. switch (tmp->type) {
  1751. case XPATH_POINT:
  1752. point = xmlXPtrNewPoint(tmp->user, tmp->index);
  1753. break;
  1754. case XPATH_RANGE: {
  1755. xmlNodePtr node = tmp->user2;
  1756. if (node != NULL) {
  1757. if ((node->type == XML_ATTRIBUTE_NODE) ||
  1758. (node->type == XML_NAMESPACE_DECL)) {
  1759. xmlXPathFreeObject(obj);
  1760. xmlXPtrFreeLocationSet(newset);
  1761. XP_ERROR(XPTR_SYNTAX_ERROR);
  1762. }
  1763. point = xmlXPtrNewPoint(node, tmp->index2);
  1764. } else if (tmp->user == NULL) {
  1765. point = xmlXPtrNewPoint(node,
  1766. xmlXPtrNbLocChildren(node));
  1767. }
  1768. break;
  1769. }
  1770. default:
  1771. /*** Should we raise an error ?
  1772. xmlXPathFreeObject(obj);
  1773. xmlXPathFreeObject(newset);
  1774. XP_ERROR(XPATH_INVALID_TYPE)
  1775. ***/
  1776. break;
  1777. }
  1778. if (point != NULL)
  1779. xmlXPtrLocationSetAdd(newset, point);
  1780. }
  1781. }
  1782. xmlXPathFreeObject(obj);
  1783. valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
  1784. }
  1785. /**
  1786. * xmlXPtrCoveringRange:
  1787. * @ctxt: the XPointer Parser context
  1788. * @loc: the location for which the covering range must be computed
  1789. *
  1790. * A covering range is a range that wholly encompasses a location
  1791. * Section 5.3.3. Covering Ranges for All Location Types
  1792. * http://www.w3.org/TR/xptr#N2267
  1793. *
  1794. * Returns a new location or NULL in case of error
  1795. */
  1796. static xmlXPathObjectPtr
  1797. xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
  1798. if (loc == NULL)
  1799. return(NULL);
  1800. if ((ctxt == NULL) || (ctxt->context == NULL) ||
  1801. (ctxt->context->doc == NULL))
  1802. return(NULL);
  1803. switch (loc->type) {
  1804. case XPATH_POINT:
  1805. return(xmlXPtrNewRange(loc->user, loc->index,
  1806. loc->user, loc->index));
  1807. case XPATH_RANGE:
  1808. if (loc->user2 != NULL) {
  1809. return(xmlXPtrNewRange(loc->user, loc->index,
  1810. loc->user2, loc->index2));
  1811. } else {
  1812. xmlNodePtr node = (xmlNodePtr) loc->user;
  1813. if (node == (xmlNodePtr) ctxt->context->doc) {
  1814. return(xmlXPtrNewRange(node, 0, node,
  1815. xmlXPtrGetArity(node)));
  1816. } else {
  1817. switch (node->type) {
  1818. case XML_ATTRIBUTE_NODE:
  1819. /* !!! our model is slightly different than XPath */
  1820. return(xmlXPtrNewRange(node, 0, node,
  1821. xmlXPtrGetArity(node)));
  1822. case XML_ELEMENT_NODE:
  1823. case XML_TEXT_NODE:
  1824. case XML_CDATA_SECTION_NODE:
  1825. case XML_ENTITY_REF_NODE:
  1826. case XML_PI_NODE:
  1827. case XML_COMMENT_NODE:
  1828. case XML_DOCUMENT_NODE:
  1829. case XML_NOTATION_NODE:
  1830. case XML_HTML_DOCUMENT_NODE: {
  1831. int indx = xmlXPtrGetIndex(node);
  1832. node = node->parent;
  1833. return(xmlXPtrNewRange(node, indx - 1,
  1834. node, indx + 1));
  1835. }
  1836. default:
  1837. return(NULL);
  1838. }
  1839. }
  1840. }
  1841. default:
  1842. TODO /* missed one case ??? */
  1843. }
  1844. return(NULL);
  1845. }
  1846. /**
  1847. * xmlXPtrRangeFunction:
  1848. * @ctxt: the XPointer Parser context
  1849. * @nargs: the number of args
  1850. *
  1851. * Function implementing the range() function 5.4.3
  1852. * location-set range(location-set )
  1853. *
  1854. * The range function returns ranges covering the locations in
  1855. * the argument location-set. For each location x in the argument
  1856. * location-set, a range location representing the covering range of
  1857. * x is added to the result location-set.
  1858. */
  1859. static void
  1860. xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  1861. int i;
  1862. xmlXPathObjectPtr set;
  1863. xmlLocationSetPtr oldset;
  1864. xmlLocationSetPtr newset;
  1865. CHECK_ARITY(1);
  1866. if ((ctxt->value == NULL) ||
  1867. ((ctxt->value->type != XPATH_LOCATIONSET) &&
  1868. (ctxt->value->type != XPATH_NODESET)))
  1869. XP_ERROR(XPATH_INVALID_TYPE)
  1870. set = valuePop(ctxt);
  1871. if (set->type == XPATH_NODESET) {
  1872. xmlXPathObjectPtr tmp;
  1873. /*
  1874. * First convert to a location set
  1875. */
  1876. tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
  1877. xmlXPathFreeObject(set);
  1878. if (tmp == NULL)
  1879. XP_ERROR(XPATH_MEMORY_ERROR)
  1880. set = tmp;
  1881. }
  1882. oldset = (xmlLocationSetPtr) set->user;
  1883. /*
  1884. * The loop is to compute the covering range for each item and add it
  1885. */
  1886. newset = xmlXPtrLocationSetCreate(NULL);
  1887. if (newset == NULL) {
  1888. xmlXPathFreeObject(set);
  1889. XP_ERROR(XPATH_MEMORY_ERROR);
  1890. }
  1891. if (oldset != NULL) {
  1892. for (i = 0;i < oldset->locNr;i++) {
  1893. xmlXPtrLocationSetAdd(newset,
  1894. xmlXPtrCoveringRange(ctxt, oldset->locTab[i]));
  1895. }
  1896. }
  1897. /*
  1898. * Save the new value and cleanup
  1899. */
  1900. valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
  1901. xmlXPathFreeObject(set);
  1902. }
  1903. /**
  1904. * xmlXPtrInsideRange:
  1905. * @ctxt: the XPointer Parser context
  1906. * @loc: the location for which the inside range must be computed
  1907. *
  1908. * A inside range is a range described in the range-inside() description
  1909. *
  1910. * Returns a new location or NULL in case of error
  1911. */
  1912. static xmlXPathObjectPtr
  1913. xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
  1914. if (loc == NULL)
  1915. return(NULL);
  1916. if ((ctxt == NULL) || (ctxt->context == NULL) ||
  1917. (ctxt->context->doc == NULL))
  1918. return(NULL);
  1919. switch (loc->type) {
  1920. case XPATH_POINT: {
  1921. xmlNodePtr node = (xmlNodePtr) loc->user;
  1922. switch (node->type) {
  1923. case XML_PI_NODE:
  1924. case XML_COMMENT_NODE:
  1925. case XML_TEXT_NODE:
  1926. case XML_CDATA_SECTION_NODE: {
  1927. if (node->content == NULL) {
  1928. return(xmlXPtrNewRange(node, 0, node, 0));
  1929. } else {
  1930. return(xmlXPtrNewRange(node, 0, node,
  1931. xmlStrlen(node->content)));
  1932. }
  1933. }
  1934. case XML_ATTRIBUTE_NODE:
  1935. case XML_ELEMENT_NODE:
  1936. case XML_ENTITY_REF_NODE:
  1937. case XML_DOCUMENT_NODE:
  1938. case XML_NOTATION_NODE:
  1939. case XML_HTML_DOCUMENT_NODE: {
  1940. return(xmlXPtrNewRange(node, 0, node,
  1941. xmlXPtrGetArity(node)));
  1942. }
  1943. default:
  1944. break;
  1945. }
  1946. return(NULL);
  1947. }
  1948. case XPATH_RANGE: {
  1949. xmlNodePtr node = (xmlNodePtr) loc->user;
  1950. if (loc->user2 != NULL) {
  1951. return(xmlXPtrNewRange(node, loc->index,
  1952. loc->user2, loc->index2));
  1953. } else {
  1954. switch (node->type) {
  1955. case XML_PI_NODE:
  1956. case XML_COMMENT_NODE:
  1957. case XML_TEXT_NODE:
  1958. case XML_CDATA_SECTION_NODE: {
  1959. if (node->content == NULL) {
  1960. return(xmlXPtrNewRange(node, 0, node, 0));
  1961. } else {
  1962. return(xmlXPtrNewRange(node, 0, node,
  1963. xmlStrlen(node->content)));
  1964. }
  1965. }
  1966. case XML_ATTRIBUTE_NODE:
  1967. case XML_ELEMENT_NODE:
  1968. case XML_ENTITY_REF_NODE:
  1969. case XML_DOCUMENT_NODE:
  1970. case XML_NOTATION_NODE:
  1971. case XML_HTML_DOCUMENT_NODE: {
  1972. return(xmlXPtrNewRange(node, 0, node,
  1973. xmlXPtrGetArity(node)));
  1974. }
  1975. default:
  1976. break;
  1977. }
  1978. return(NULL);
  1979. }
  1980. }
  1981. default:
  1982. TODO /* missed one case ??? */
  1983. }
  1984. return(NULL);
  1985. }
  1986. /**
  1987. * xmlXPtrRangeInsideFunction:
  1988. * @ctxt: the XPointer Parser context
  1989. * @nargs: the number of args
  1990. *
  1991. * Function implementing the range-inside() function 5.4.3
  1992. * location-set range-inside(location-set )
  1993. *
  1994. * The range-inside function returns ranges covering the contents of
  1995. * the locations in the argument location-set. For each location x in
  1996. * the argument location-set, a range location is added to the result
  1997. * location-set. If x is a range location, then x is added to the
  1998. * result location-set. If x is not a range location, then x is used
  1999. * as the container location of the start and end points of the range
  2000. * location to be added; the index of the start point of the range is
  2001. * zero; if the end point is a character point then its index is the
  2002. * length of the string-value of x, and otherwise is the number of
  2003. * location children of x.
  2004. *
  2005. */
  2006. static void
  2007. xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2008. int i;
  2009. xmlXPathObjectPtr set;
  2010. xmlLocationSetPtr oldset;
  2011. xmlLocationSetPtr newset;
  2012. CHECK_ARITY(1);
  2013. if ((ctxt->value == NULL) ||
  2014. ((ctxt->value->type != XPATH_LOCATIONSET) &&
  2015. (ctxt->value->type != XPATH_NODESET)))
  2016. XP_ERROR(XPATH_INVALID_TYPE)
  2017. set = valuePop(ctxt);
  2018. if (set->type == XPATH_NODESET) {
  2019. xmlXPathObjectPtr tmp;
  2020. /*
  2021. * First convert to a location set
  2022. */
  2023. tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
  2024. xmlXPathFreeObject(set);
  2025. if (tmp == NULL)
  2026. XP_ERROR(XPATH_MEMORY_ERROR)
  2027. set = tmp;
  2028. }
  2029. /*
  2030. * The loop is to compute the covering range for each item and add it
  2031. */
  2032. newset = xmlXPtrLocationSetCreate(NULL);
  2033. if (newset == NULL) {
  2034. xmlXPathFreeObject(set);
  2035. XP_ERROR(XPATH_MEMORY_ERROR);
  2036. }
  2037. oldset = (xmlLocationSetPtr) set->user;
  2038. if (oldset != NULL) {
  2039. for (i = 0;i < oldset->locNr;i++) {
  2040. xmlXPtrLocationSetAdd(newset,
  2041. xmlXPtrInsideRange(ctxt, oldset->locTab[i]));
  2042. }
  2043. }
  2044. /*
  2045. * Save the new value and cleanup
  2046. */
  2047. valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
  2048. xmlXPathFreeObject(set);
  2049. }
  2050. /**
  2051. * xmlXPtrRangeToFunction:
  2052. * @ctxt: the XPointer Parser context
  2053. * @nargs: the number of args
  2054. *
  2055. * Implement the range-to() XPointer function
  2056. *
  2057. * Obsolete. range-to is not a real function but a special type of location
  2058. * step which is handled in xpath.c.
  2059. */
  2060. void
  2061. xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt,
  2062. int nargs ATTRIBUTE_UNUSED) {
  2063. XP_ERROR(XPATH_EXPR_ERROR);
  2064. }
  2065. /**
  2066. * xmlXPtrAdvanceNode:
  2067. * @cur: the node
  2068. * @level: incremented/decremented to show level in tree
  2069. *
  2070. * Advance to the next element or text node in document order
  2071. * TODO: add a stack for entering/exiting entities
  2072. *
  2073. * Returns -1 in case of failure, 0 otherwise
  2074. */
  2075. xmlNodePtr
  2076. xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) {
  2077. next:
  2078. if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
  2079. return(NULL);
  2080. if (cur->children != NULL) {
  2081. cur = cur->children ;
  2082. if (level != NULL)
  2083. (*level)++;
  2084. goto found;
  2085. }
  2086. skip: /* This label should only be needed if something is wrong! */
  2087. if (cur->next != NULL) {
  2088. cur = cur->next;
  2089. goto found;
  2090. }
  2091. do {
  2092. cur = cur->parent;
  2093. if (level != NULL)
  2094. (*level)--;
  2095. if (cur == NULL) return(NULL);
  2096. if (cur->next != NULL) {
  2097. cur = cur->next;
  2098. goto found;
  2099. }
  2100. } while (cur != NULL);
  2101. found:
  2102. if ((cur->type != XML_ELEMENT_NODE) &&
  2103. (cur->type != XML_TEXT_NODE) &&
  2104. (cur->type != XML_DOCUMENT_NODE) &&
  2105. (cur->type != XML_HTML_DOCUMENT_NODE) &&
  2106. (cur->type != XML_CDATA_SECTION_NODE)) {
  2107. if (cur->type == XML_ENTITY_REF_NODE) { /* Shouldn't happen */
  2108. TODO
  2109. goto skip;
  2110. }
  2111. goto next;
  2112. }
  2113. return(cur);
  2114. }
  2115. /**
  2116. * xmlXPtrAdvanceChar:
  2117. * @node: the node
  2118. * @indx: the indx
  2119. * @bytes: the number of bytes
  2120. *
  2121. * Advance a point of the associated number of bytes (not UTF8 chars)
  2122. *
  2123. * Returns -1 in case of failure, 0 otherwise
  2124. */
  2125. static int
  2126. xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) {
  2127. xmlNodePtr cur;
  2128. int pos;
  2129. int len;
  2130. if ((node == NULL) || (indx == NULL))
  2131. return(-1);
  2132. cur = *node;
  2133. if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
  2134. return(-1);
  2135. pos = *indx;
  2136. while (bytes >= 0) {
  2137. /*
  2138. * First position to the beginning of the first text node
  2139. * corresponding to this point
  2140. */
  2141. while ((cur != NULL) &&
  2142. ((cur->type == XML_ELEMENT_NODE) ||
  2143. (cur->type == XML_DOCUMENT_NODE) ||
  2144. (cur->type == XML_HTML_DOCUMENT_NODE))) {
  2145. if (pos > 0) {
  2146. cur = xmlXPtrGetNthChild(cur, pos);
  2147. pos = 0;
  2148. } else {
  2149. cur = xmlXPtrAdvanceNode(cur, NULL);
  2150. pos = 0;
  2151. }
  2152. }
  2153. if (cur == NULL) {
  2154. *node = NULL;
  2155. *indx = 0;
  2156. return(-1);
  2157. }
  2158. /*
  2159. * if there is no move needed return the current value.
  2160. */
  2161. if (pos == 0) pos = 1;
  2162. if (bytes == 0) {
  2163. *node = cur;
  2164. *indx = pos;
  2165. return(0);
  2166. }
  2167. /*
  2168. * We should have a text (or cdata) node ...
  2169. */
  2170. len = 0;
  2171. if ((cur->type != XML_ELEMENT_NODE) &&
  2172. (cur->content != NULL)) {
  2173. len = xmlStrlen(cur->content);
  2174. }
  2175. if (pos > len) {
  2176. /* Strange, the indx in the text node is greater than it's len */
  2177. STRANGE
  2178. pos = len;
  2179. }
  2180. if (pos + bytes >= len) {
  2181. bytes -= (len - pos);
  2182. cur = xmlXPtrAdvanceNode(cur, NULL);
  2183. pos = 0;
  2184. } else if (pos + bytes < len) {
  2185. pos += bytes;
  2186. *node = cur;
  2187. *indx = pos;
  2188. return(0);
  2189. }
  2190. }
  2191. return(-1);
  2192. }
  2193. /**
  2194. * xmlXPtrMatchString:
  2195. * @string: the string to search
  2196. * @start: the start textnode
  2197. * @startindex: the start index
  2198. * @end: the end textnode IN/OUT
  2199. * @endindex: the end index IN/OUT
  2200. *
  2201. * Check whether the document contains @string at the position
  2202. * (@start, @startindex) and limited by the (@end, @endindex) point
  2203. *
  2204. * Returns -1 in case of failure, 0 if not found, 1 if found in which case
  2205. * (@start, @startindex) will indicate the position of the beginning
  2206. * of the range and (@end, @endindex) will indicate the end
  2207. * of the range
  2208. */
  2209. static int
  2210. xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex,
  2211. xmlNodePtr *end, int *endindex) {
  2212. xmlNodePtr cur;
  2213. int pos; /* 0 based */
  2214. int len; /* in bytes */
  2215. int stringlen; /* in bytes */
  2216. int match;
  2217. if (string == NULL)
  2218. return(-1);
  2219. if ((start == NULL) || (start->type == XML_NAMESPACE_DECL))
  2220. return(-1);
  2221. if ((end == NULL) || (*end == NULL) ||
  2222. ((*end)->type == XML_NAMESPACE_DECL) || (endindex == NULL))
  2223. return(-1);
  2224. cur = start;
  2225. pos = startindex - 1;
  2226. stringlen = xmlStrlen(string);
  2227. while (stringlen > 0) {
  2228. if ((cur == *end) && (pos + stringlen > *endindex))
  2229. return(0);
  2230. if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
  2231. len = xmlStrlen(cur->content);
  2232. if (len >= pos + stringlen) {
  2233. match = (!xmlStrncmp(&cur->content[pos], string, stringlen));
  2234. if (match) {
  2235. *end = cur;
  2236. *endindex = pos + stringlen;
  2237. return(1);
  2238. } else {
  2239. return(0);
  2240. }
  2241. } else {
  2242. int sub = len - pos;
  2243. match = (!xmlStrncmp(&cur->content[pos], string, sub));
  2244. if (match) {
  2245. string = &string[sub];
  2246. stringlen -= sub;
  2247. } else {
  2248. return(0);
  2249. }
  2250. }
  2251. }
  2252. cur = xmlXPtrAdvanceNode(cur, NULL);
  2253. if (cur == NULL)
  2254. return(0);
  2255. pos = 0;
  2256. }
  2257. return(1);
  2258. }
  2259. /**
  2260. * xmlXPtrSearchString:
  2261. * @string: the string to search
  2262. * @start: the start textnode IN/OUT
  2263. * @startindex: the start index IN/OUT
  2264. * @end: the end textnode
  2265. * @endindex: the end index
  2266. *
  2267. * Search the next occurrence of @string within the document content
  2268. * until the (@end, @endindex) point is reached
  2269. *
  2270. * Returns -1 in case of failure, 0 if not found, 1 if found in which case
  2271. * (@start, @startindex) will indicate the position of the beginning
  2272. * of the range and (@end, @endindex) will indicate the end
  2273. * of the range
  2274. */
  2275. static int
  2276. xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex,
  2277. xmlNodePtr *end, int *endindex) {
  2278. xmlNodePtr cur;
  2279. const xmlChar *str;
  2280. int pos; /* 0 based */
  2281. int len; /* in bytes */
  2282. xmlChar first;
  2283. if (string == NULL)
  2284. return(-1);
  2285. if ((start == NULL) || (*start == NULL) ||
  2286. ((*start)->type == XML_NAMESPACE_DECL) || (startindex == NULL))
  2287. return(-1);
  2288. if ((end == NULL) || (endindex == NULL))
  2289. return(-1);
  2290. cur = *start;
  2291. pos = *startindex - 1;
  2292. first = string[0];
  2293. while (cur != NULL) {
  2294. if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
  2295. len = xmlStrlen(cur->content);
  2296. while (pos <= len) {
  2297. if (first != 0) {
  2298. str = xmlStrchr(&cur->content[pos], first);
  2299. if (str != NULL) {
  2300. pos = (str - (xmlChar *)(cur->content));
  2301. if (xmlXPtrMatchString(string, cur, pos + 1,
  2302. end, endindex)) {
  2303. *start = cur;
  2304. *startindex = pos + 1;
  2305. return(1);
  2306. }
  2307. pos++;
  2308. } else {
  2309. pos = len + 1;
  2310. }
  2311. } else {
  2312. /*
  2313. * An empty string is considered to match before each
  2314. * character of the string-value and after the final
  2315. * character.
  2316. */
  2317. *start = cur;
  2318. *startindex = pos + 1;
  2319. *end = cur;
  2320. *endindex = pos + 1;
  2321. return(1);
  2322. }
  2323. }
  2324. }
  2325. if ((cur == *end) && (pos >= *endindex))
  2326. return(0);
  2327. cur = xmlXPtrAdvanceNode(cur, NULL);
  2328. if (cur == NULL)
  2329. return(0);
  2330. pos = 1;
  2331. }
  2332. return(0);
  2333. }
  2334. /**
  2335. * xmlXPtrGetLastChar:
  2336. * @node: the node
  2337. * @index: the index
  2338. *
  2339. * Computes the point coordinates of the last char of this point
  2340. *
  2341. * Returns -1 in case of failure, 0 otherwise
  2342. */
  2343. static int
  2344. xmlXPtrGetLastChar(xmlNodePtr *node, int *indx) {
  2345. xmlNodePtr cur;
  2346. int pos, len = 0;
  2347. if ((node == NULL) || (*node == NULL) ||
  2348. ((*node)->type == XML_NAMESPACE_DECL) || (indx == NULL))
  2349. return(-1);
  2350. cur = *node;
  2351. pos = *indx;
  2352. if ((cur->type == XML_ELEMENT_NODE) ||
  2353. (cur->type == XML_DOCUMENT_NODE) ||
  2354. (cur->type == XML_HTML_DOCUMENT_NODE)) {
  2355. if (pos > 0) {
  2356. cur = xmlXPtrGetNthChild(cur, pos);
  2357. }
  2358. }
  2359. while (cur != NULL) {
  2360. if (cur->last != NULL)
  2361. cur = cur->last;
  2362. else if ((cur->type != XML_ELEMENT_NODE) &&
  2363. (cur->content != NULL)) {
  2364. len = xmlStrlen(cur->content);
  2365. break;
  2366. } else {
  2367. return(-1);
  2368. }
  2369. }
  2370. if (cur == NULL)
  2371. return(-1);
  2372. *node = cur;
  2373. *indx = len;
  2374. return(0);
  2375. }
  2376. /**
  2377. * xmlXPtrGetStartPoint:
  2378. * @obj: an range
  2379. * @node: the resulting node
  2380. * @indx: the resulting index
  2381. *
  2382. * read the object and return the start point coordinates.
  2383. *
  2384. * Returns -1 in case of failure, 0 otherwise
  2385. */
  2386. static int
  2387. xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
  2388. if ((obj == NULL) || (node == NULL) || (indx == NULL))
  2389. return(-1);
  2390. switch (obj->type) {
  2391. case XPATH_POINT:
  2392. *node = obj->user;
  2393. if (obj->index <= 0)
  2394. *indx = 0;
  2395. else
  2396. *indx = obj->index;
  2397. return(0);
  2398. case XPATH_RANGE:
  2399. *node = obj->user;
  2400. if (obj->index <= 0)
  2401. *indx = 0;
  2402. else
  2403. *indx = obj->index;
  2404. return(0);
  2405. default:
  2406. break;
  2407. }
  2408. return(-1);
  2409. }
  2410. /**
  2411. * xmlXPtrGetEndPoint:
  2412. * @obj: an range
  2413. * @node: the resulting node
  2414. * @indx: the resulting indx
  2415. *
  2416. * read the object and return the end point coordinates.
  2417. *
  2418. * Returns -1 in case of failure, 0 otherwise
  2419. */
  2420. static int
  2421. xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
  2422. if ((obj == NULL) || (node == NULL) || (indx == NULL))
  2423. return(-1);
  2424. switch (obj->type) {
  2425. case XPATH_POINT:
  2426. *node = obj->user;
  2427. if (obj->index <= 0)
  2428. *indx = 0;
  2429. else
  2430. *indx = obj->index;
  2431. return(0);
  2432. case XPATH_RANGE:
  2433. *node = obj->user;
  2434. if (obj->index <= 0)
  2435. *indx = 0;
  2436. else
  2437. *indx = obj->index;
  2438. return(0);
  2439. default:
  2440. break;
  2441. }
  2442. return(-1);
  2443. }
  2444. /**
  2445. * xmlXPtrStringRangeFunction:
  2446. * @ctxt: the XPointer Parser context
  2447. * @nargs: the number of args
  2448. *
  2449. * Function implementing the string-range() function
  2450. * range as described in 5.4.2
  2451. *
  2452. * ------------------------------
  2453. * [Definition: For each location in the location-set argument,
  2454. * string-range returns a set of string ranges, a set of substrings in a
  2455. * string. Specifically, the string-value of the location is searched for
  2456. * substrings that match the string argument, and the resulting location-set
  2457. * will contain a range location for each non-overlapping match.]
  2458. * An empty string is considered to match before each character of the
  2459. * string-value and after the final character. Whitespace in a string
  2460. * is matched literally, with no normalization except that provided by
  2461. * XML for line ends. The third argument gives the position of the first
  2462. * character to be in the resulting range, relative to the start of the
  2463. * match. The default value is 1, which makes the range start immediately
  2464. * before the first character of the matched string. The fourth argument
  2465. * gives the number of characters in the range; the default is that the
  2466. * range extends to the end of the matched string.
  2467. *
  2468. * Element boundaries, as well as entire embedded nodes such as processing
  2469. * instructions and comments, are ignored as defined in [XPath].
  2470. *
  2471. * If the string in the second argument is not found in the string-value
  2472. * of the location, or if a value in the third or fourth argument indicates
  2473. * a string that is beyond the beginning or end of the document, the
  2474. * expression fails.
  2475. *
  2476. * The points of the range-locations in the returned location-set will
  2477. * all be character points.
  2478. * ------------------------------
  2479. */
  2480. static void
  2481. xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2482. int i, startindex, endindex = 0, fendindex;
  2483. xmlNodePtr start, end = 0, fend;
  2484. xmlXPathObjectPtr set = NULL;
  2485. xmlLocationSetPtr oldset;
  2486. xmlLocationSetPtr newset = NULL;
  2487. xmlXPathObjectPtr string = NULL;
  2488. xmlXPathObjectPtr position = NULL;
  2489. xmlXPathObjectPtr number = NULL;
  2490. int found, pos = 0, num = 0;
  2491. /*
  2492. * Grab the arguments
  2493. */
  2494. if ((nargs < 2) || (nargs > 4))
  2495. XP_ERROR(XPATH_INVALID_ARITY);
  2496. if (nargs >= 4) {
  2497. if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NUMBER)) {
  2498. xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
  2499. goto error;
  2500. }
  2501. number = valuePop(ctxt);
  2502. if (number != NULL)
  2503. num = (int) number->floatval;
  2504. }
  2505. if (nargs >= 3) {
  2506. if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NUMBER)) {
  2507. xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
  2508. goto error;
  2509. }
  2510. position = valuePop(ctxt);
  2511. if (position != NULL)
  2512. pos = (int) position->floatval;
  2513. }
  2514. if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
  2515. xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
  2516. goto error;
  2517. }
  2518. string = valuePop(ctxt);
  2519. if ((ctxt->value == NULL) ||
  2520. ((ctxt->value->type != XPATH_LOCATIONSET) &&
  2521. (ctxt->value->type != XPATH_NODESET))) {
  2522. xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
  2523. goto error;
  2524. }
  2525. set = valuePop(ctxt);
  2526. newset = xmlXPtrLocationSetCreate(NULL);
  2527. if (newset == NULL) {
  2528. xmlXPathErr(ctxt, XPATH_MEMORY_ERROR);
  2529. goto error;
  2530. }
  2531. if (set->nodesetval == NULL) {
  2532. goto error;
  2533. }
  2534. if (set->type == XPATH_NODESET) {
  2535. xmlXPathObjectPtr tmp;
  2536. /*
  2537. * First convert to a location set
  2538. */
  2539. tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
  2540. xmlXPathFreeObject(set);
  2541. set = NULL;
  2542. if (tmp == NULL) {
  2543. xmlXPathErr(ctxt, XPATH_MEMORY_ERROR);
  2544. goto error;
  2545. }
  2546. set = tmp;
  2547. }
  2548. oldset = (xmlLocationSetPtr) set->user;
  2549. /*
  2550. * The loop is to search for each element in the location set
  2551. * the list of location set corresponding to that search
  2552. */
  2553. for (i = 0;i < oldset->locNr;i++) {
  2554. xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex);
  2555. xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex);
  2556. xmlXPtrAdvanceChar(&start, &startindex, 0);
  2557. xmlXPtrGetLastChar(&end, &endindex);
  2558. do {
  2559. fend = end;
  2560. fendindex = endindex;
  2561. found = xmlXPtrSearchString(string->stringval, &start, &startindex,
  2562. &fend, &fendindex);
  2563. if (found == 1) {
  2564. if (position == NULL) {
  2565. xmlXPtrLocationSetAdd(newset,
  2566. xmlXPtrNewRange(start, startindex, fend, fendindex));
  2567. } else if (xmlXPtrAdvanceChar(&start, &startindex,
  2568. pos - 1) == 0) {
  2569. if ((number != NULL) && (num > 0)) {
  2570. int rindx;
  2571. xmlNodePtr rend;
  2572. rend = start;
  2573. rindx = startindex - 1;
  2574. if (xmlXPtrAdvanceChar(&rend, &rindx,
  2575. num) == 0) {
  2576. xmlXPtrLocationSetAdd(newset,
  2577. xmlXPtrNewRange(start, startindex,
  2578. rend, rindx));
  2579. }
  2580. } else if ((number != NULL) && (num <= 0)) {
  2581. xmlXPtrLocationSetAdd(newset,
  2582. xmlXPtrNewRange(start, startindex,
  2583. start, startindex));
  2584. } else {
  2585. xmlXPtrLocationSetAdd(newset,
  2586. xmlXPtrNewRange(start, startindex,
  2587. fend, fendindex));
  2588. }
  2589. }
  2590. start = fend;
  2591. startindex = fendindex;
  2592. if (string->stringval[0] == 0)
  2593. startindex++;
  2594. }
  2595. } while (found == 1);
  2596. }
  2597. /*
  2598. * Save the new value and cleanup
  2599. */
  2600. error:
  2601. if (newset != NULL)
  2602. valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
  2603. xmlXPathFreeObject(set);
  2604. xmlXPathFreeObject(string);
  2605. if (position) xmlXPathFreeObject(position);
  2606. if (number) xmlXPathFreeObject(number);
  2607. }
  2608. /**
  2609. * xmlXPtrEvalRangePredicate:
  2610. * @ctxt: the XPointer Parser context
  2611. *
  2612. * [8] Predicate ::= '[' PredicateExpr ']'
  2613. * [9] PredicateExpr ::= Expr
  2614. *
  2615. * Evaluate a predicate as in xmlXPathEvalPredicate() but for
  2616. * a Location Set instead of a node set
  2617. */
  2618. void
  2619. xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) {
  2620. const xmlChar *cur;
  2621. xmlXPathObjectPtr res;
  2622. xmlXPathObjectPtr obj, tmp;
  2623. xmlLocationSetPtr newset = NULL;
  2624. xmlLocationSetPtr oldset;
  2625. int i;
  2626. if (ctxt == NULL) return;
  2627. SKIP_BLANKS;
  2628. if (CUR != '[') {
  2629. XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
  2630. }
  2631. NEXT;
  2632. SKIP_BLANKS;
  2633. /*
  2634. * Extract the old set, and then evaluate the result of the
  2635. * expression for all the element in the set. use it to grow
  2636. * up a new set.
  2637. */
  2638. CHECK_TYPE(XPATH_LOCATIONSET);
  2639. obj = valuePop(ctxt);
  2640. oldset = obj->user;
  2641. ctxt->context->node = NULL;
  2642. if ((oldset == NULL) || (oldset->locNr == 0)) {
  2643. ctxt->context->contextSize = 0;
  2644. ctxt->context->proximityPosition = 0;
  2645. xmlXPathEvalExpr(ctxt);
  2646. res = valuePop(ctxt);
  2647. if (res != NULL)
  2648. xmlXPathFreeObject(res);
  2649. valuePush(ctxt, obj);
  2650. CHECK_ERROR;
  2651. } else {
  2652. /*
  2653. * Save the expression pointer since we will have to evaluate
  2654. * it multiple times. Initialize the new set.
  2655. */
  2656. cur = ctxt->cur;
  2657. newset = xmlXPtrLocationSetCreate(NULL);
  2658. for (i = 0; i < oldset->locNr; i++) {
  2659. ctxt->cur = cur;
  2660. /*
  2661. * Run the evaluation with a node list made of a single item
  2662. * in the nodeset.
  2663. */
  2664. ctxt->context->node = oldset->locTab[i]->user;
  2665. tmp = xmlXPathNewNodeSet(ctxt->context->node);
  2666. valuePush(ctxt, tmp);
  2667. ctxt->context->contextSize = oldset->locNr;
  2668. ctxt->context->proximityPosition = i + 1;
  2669. xmlXPathEvalExpr(ctxt);
  2670. CHECK_ERROR;
  2671. /*
  2672. * The result of the evaluation need to be tested to
  2673. * decided whether the filter succeeded or not
  2674. */
  2675. res = valuePop(ctxt);
  2676. if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
  2677. xmlXPtrLocationSetAdd(newset,
  2678. xmlXPathObjectCopy(oldset->locTab[i]));
  2679. }
  2680. /*
  2681. * Cleanup
  2682. */
  2683. if (res != NULL)
  2684. xmlXPathFreeObject(res);
  2685. if (ctxt->value == tmp) {
  2686. res = valuePop(ctxt);
  2687. xmlXPathFreeObject(res);
  2688. }
  2689. ctxt->context->node = NULL;
  2690. }
  2691. /*
  2692. * The result is used as the new evaluation set.
  2693. */
  2694. xmlXPathFreeObject(obj);
  2695. ctxt->context->node = NULL;
  2696. ctxt->context->contextSize = -1;
  2697. ctxt->context->proximityPosition = -1;
  2698. valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
  2699. }
  2700. if (CUR != ']') {
  2701. XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
  2702. }
  2703. NEXT;
  2704. SKIP_BLANKS;
  2705. }
  2706. #endif /* LIBXML_XPTR_LOCS_ENABLED */
  2707. #endif