PageRenderTime 49ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/plugins/ImageMagick-6.3.2/magick/xml-tree.c

https://bitbucket.org/sisko/operation-caribou
C | 2576 lines | 2216 code | 54 blank | 306 comment | 345 complexity | 875da4f7b580631ab13a82cb5e1651eb MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. % %
  4. % %
  5. % %
  6. % X X M M L %
  7. % X X MM MM L %
  8. % X M M M L %
  9. % X X M M L %
  10. % X X M M LLLLL %
  11. % %
  12. % TTTTT RRRR EEEEE EEEEE %
  13. % T R R E E %
  14. % T RRRR EEE EEE %
  15. % T R R E E %
  16. % T R R EEEEE EEEEE %
  17. % %
  18. % %
  19. % XML Tree Methods %
  20. % %
  21. % Software Design %
  22. % John Cristy %
  23. % December 2004 %
  24. % %
  25. % %
  26. % Copyright 1999-2006 ImageMagick Studio LLC, a non-profit organization %
  27. % dedicated to making software imaging solutions freely available. %
  28. % %
  29. % You may not use this file except in compliance with the License. You may %
  30. % obtain a copy of the License at %
  31. % %
  32. % http://www.imagemagick.org/script/license.php %
  33. % %
  34. % Unless required by applicable law or agreed to in writing, software %
  35. % distributed under the License is distributed on an "AS IS" BASIS, %
  36. % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
  37. % See the License for the specific language governing permissions and %
  38. % limitations under the License. %
  39. % %
  40. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  41. %
  42. % This module implements the standard handy xml-tree methods for storing and
  43. % retrieving nodes and attributes from an XML string.
  44. %
  45. */
  46. /*
  47. Include declarations.
  48. */
  49. #include "magick/studio.h"
  50. #include "magick/blob.h"
  51. #include "magick/exception.h"
  52. #include "magick/exception-private.h"
  53. #include "magick/log.h"
  54. #include "magick/memory_.h"
  55. #include "magick/semaphore.h"
  56. #include "magick/string_.h"
  57. #include "magick/xml-tree.h"
  58. #include "magick/utility.h"
  59. /*
  60. Define declarations.
  61. */
  62. #define NumberPredefinedEntities 10
  63. #define XMLWhitespace "\t\r\n "
  64. /*
  65. Typedef declarations.
  66. */
  67. struct _XMLTreeInfo
  68. {
  69. char
  70. *tag,
  71. **attributes,
  72. *content;
  73. size_t
  74. offset;
  75. XMLTreeInfo
  76. *parent,
  77. *next,
  78. *sibling,
  79. *ordered,
  80. *child;
  81. MagickBooleanType
  82. debug;
  83. SemaphoreInfo
  84. *semaphore;
  85. unsigned long
  86. signature;
  87. };
  88. typedef struct _XMLTreeRoot
  89. XMLTreeRoot;
  90. struct _XMLTreeRoot
  91. {
  92. struct _XMLTreeInfo
  93. root;
  94. XMLTreeInfo
  95. *node;
  96. MagickBooleanType
  97. standalone;
  98. char
  99. ***processing_instructions,
  100. **entities,
  101. ***attributes;
  102. MagickBooleanType
  103. debug;
  104. SemaphoreInfo
  105. *semaphore;
  106. unsigned long
  107. signature;
  108. };
  109. /*
  110. Global declarations.
  111. */
  112. static char
  113. *sentinel[] = { (char *) NULL };
  114. /*
  115. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  116. % %
  117. % %
  118. % %
  119. % A d d C h i l d T o X M L T r e e %
  120. % %
  121. % %
  122. % %
  123. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  124. %
  125. % AddChildToXMLTree() adds a child tag at an offset relative to the start of
  126. % the parent tag's character content. Return the child tag.
  127. %
  128. % The format of the AddChildToXMLTree method is:
  129. %
  130. % XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info,const char *tag,
  131. % const size_t offset)
  132. %
  133. % A description of each parameter follows:
  134. %
  135. % o xml_info: The xml info.
  136. %
  137. % o tag: The tag.
  138. %
  139. % o offset: The tag offset.
  140. %
  141. */
  142. MagickExport XMLTreeInfo *AddChildToXMLTree(XMLTreeInfo *xml_info,
  143. const char *tag,const size_t offset)
  144. {
  145. XMLTreeInfo
  146. *child;
  147. if (xml_info == (XMLTreeInfo *) NULL)
  148. return((XMLTreeInfo *) NULL);
  149. child=(XMLTreeInfo *) AcquireMagickMemory(sizeof(*child));
  150. if (child == (XMLTreeInfo *) NULL)
  151. return((XMLTreeInfo *) NULL);
  152. (void) ResetMagickMemory(child,0,sizeof(*child));
  153. child->tag=ConstantString(tag);
  154. child->attributes=sentinel;
  155. child->content=ConstantString("");
  156. child->debug=IsEventLogging();
  157. child->signature=MagickSignature;
  158. return(InsertTagIntoXMLTree(xml_info,child,offset));
  159. }
  160. /*
  161. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  162. % %
  163. % %
  164. % %
  165. % A d d P a t h T o X M L T r e e %
  166. % %
  167. % %
  168. % %
  169. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  170. %
  171. % AddPathToXMLTree() adds a child tag at an offset relative to the start of
  172. % the parent tag's character content. This method returns the child tag.
  173. %
  174. % The format of the AddPathToXMLTree method is:
  175. %
  176. % XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info,const char *path,
  177. % const size_t offset)
  178. %
  179. % A description of each parameter follows:
  180. %
  181. % o xml_info: The xml info.
  182. %
  183. % o path: The path.
  184. %
  185. % o offset: The tag offset.
  186. %
  187. */
  188. MagickExport XMLTreeInfo *AddPathToXMLTree(XMLTreeInfo *xml_info,
  189. const char *path,const size_t offset)
  190. {
  191. char
  192. **components,
  193. subnode[MaxTextExtent],
  194. tag[MaxTextExtent];
  195. long
  196. j;
  197. register long
  198. i;
  199. XMLTreeInfo
  200. *child,
  201. *node;
  202. unsigned long
  203. number_components;
  204. assert(xml_info != (XMLTreeInfo *) NULL);
  205. assert((xml_info->signature == MagickSignature) ||
  206. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  207. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  208. node=xml_info;
  209. components=GetPathComponents(path,&number_components);
  210. if (components == (char **) NULL)
  211. return((XMLTreeInfo *) NULL);
  212. for (i=0; i < (long) number_components; i++)
  213. {
  214. GetPathComponent(components[i],SubimagePath,subnode);
  215. GetPathComponent(components[i],CanonicalPath,tag);
  216. child=GetXMLTreeChild(node,tag);
  217. if (child == (XMLTreeInfo *) NULL)
  218. child=AddChildToXMLTree(node,tag,offset);
  219. node=child;
  220. if (node == (XMLTreeInfo *) NULL)
  221. break;
  222. for (j=atol(subnode)-1; j > 0; j--)
  223. {
  224. node=GetXMLTreeOrdered(node);
  225. if (node == (XMLTreeInfo *) NULL)
  226. break;
  227. }
  228. if (node == (XMLTreeInfo *) NULL)
  229. break;
  230. components[i]=(char *) RelinquishMagickMemory(components[i]);
  231. }
  232. for ( ; i < (long) number_components; i++)
  233. components[i]=(char *) RelinquishMagickMemory(components[i]);
  234. components=(char **) RelinquishMagickMemory(components);
  235. return(node);
  236. }
  237. /*
  238. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  239. % %
  240. % %
  241. % %
  242. % C a n o n i c a l X M L C o n t e n t %
  243. % %
  244. % %
  245. % %
  246. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  247. %
  248. % CanonicalXMLContent() converts text to canonical XML content by converting
  249. % to UTF-8, substituting predefined entities, wrapping as CDATA, or encoding
  250. % as base-64 as required.
  251. %
  252. % The format of the CanonicalXMLContent method is:
  253. %
  254. % char *CanonicalXMLContent(const char *content)
  255. %
  256. % A description of each parameter follows:
  257. %
  258. % o content: The content.
  259. %
  260. */
  261. static unsigned char *ConvertLatin1ToUTF8(const unsigned char *content)
  262. {
  263. register const unsigned char
  264. *p;
  265. register unsigned char
  266. *q;
  267. size_t
  268. length;
  269. unsigned char
  270. *utf8;
  271. unsigned int
  272. c;
  273. length=0;
  274. for (p=content; *p != '\0'; p++)
  275. length+=(*p & 0x80) != 0 ? 2 : 1;
  276. utf8=(unsigned char *) AcquireMagickMemory((length+1)*sizeof(*utf8));
  277. if (utf8 == (unsigned char *) NULL)
  278. return((unsigned char *) NULL);
  279. q=utf8;
  280. for (p=content; *p != '\0'; p++)
  281. {
  282. c=(*p);
  283. if ((c & 0x80) == 0)
  284. *q++=c;
  285. else
  286. {
  287. *q++=0xc0 | ((c >> 6) & 0x3f);
  288. *q++=0x80 | (c & 0x3f);
  289. }
  290. }
  291. *q='\0';
  292. return(utf8);
  293. }
  294. MagickExport char *CanonicalXMLContent(const char *content,
  295. const MagickBooleanType pedantic)
  296. {
  297. char
  298. *base64,
  299. *canonical_content;
  300. register const unsigned char
  301. *p;
  302. register long
  303. i;
  304. size_t
  305. length;
  306. unsigned char
  307. *utf8;
  308. unsigned long
  309. extent;
  310. utf8=ConvertLatin1ToUTF8((const unsigned char *) content);
  311. if (utf8 == (unsigned char *) NULL)
  312. return((char *) NULL);
  313. for (p=utf8; *p != '\0'; p++)
  314. if ((*p < 0x20) && (*p != 0x09) && (*p != 0x0a) && (*p != 0x0d))
  315. break;
  316. if (*p != '\0')
  317. {
  318. /*
  319. String is binary, base64-encode it.
  320. */
  321. base64=Base64Encode(utf8,strlen((char *) utf8),&length);
  322. utf8=(unsigned char *) RelinquishMagickMemory(utf8);
  323. if (base64 == (char *) NULL)
  324. return((char *) NULL);
  325. canonical_content=AcquireString("<base64>");
  326. (void) ConcatenateString(&canonical_content,base64);
  327. base64=(char *) RelinquishMagickMemory(base64);
  328. (void) ConcatenateString(&canonical_content,"</base64>");
  329. return(canonical_content);
  330. }
  331. /*
  332. Substitute predefined entities.
  333. */
  334. i=0;
  335. canonical_content=AcquireString((char *) NULL);
  336. extent=MaxTextExtent;
  337. for (p=utf8; *p != '\0'; p++)
  338. {
  339. if ((i+MaxTextExtent) > (long) extent)
  340. {
  341. extent+=MaxTextExtent;
  342. canonical_content=(char *) ResizeMagickMemory(canonical_content,
  343. extent*sizeof(*canonical_content));
  344. if (canonical_content == (char *) NULL)
  345. return(canonical_content);
  346. }
  347. switch (*p)
  348. {
  349. case '&':
  350. {
  351. i+=FormatMagickString(canonical_content+i,extent,"&amp;");
  352. break;
  353. }
  354. case '<':
  355. {
  356. i+=FormatMagickString(canonical_content+i,extent,"&lt;");
  357. break;
  358. }
  359. case '>':
  360. {
  361. i+=FormatMagickString(canonical_content+i,extent,"&gt;");
  362. break;
  363. }
  364. case '"':
  365. {
  366. i+=FormatMagickString(canonical_content+i,extent,"&quot;");
  367. break;
  368. }
  369. case '\n':
  370. {
  371. if (pedantic == MagickFalse)
  372. {
  373. canonical_content[i++]=(char) (*p);
  374. break;
  375. }
  376. i+=FormatMagickString(canonical_content+i,extent,"&#xA;");
  377. break;
  378. }
  379. case '\t':
  380. {
  381. if (pedantic == MagickFalse)
  382. {
  383. canonical_content[i++]=(char) (*p);
  384. break;
  385. }
  386. i+=FormatMagickString(canonical_content+i,extent,"&#x9;");
  387. break;
  388. }
  389. case '\r':
  390. {
  391. i+=FormatMagickString(canonical_content+i,extent,"&#xD;");
  392. break;
  393. }
  394. default:
  395. {
  396. canonical_content[i++]=(char) (*p);
  397. break;
  398. }
  399. }
  400. }
  401. canonical_content[i]='\0';
  402. utf8=(unsigned char *) RelinquishMagickMemory(utf8);
  403. return(canonical_content);
  404. }
  405. /*
  406. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  407. % %
  408. % %
  409. % %
  410. % D e s t r o y X M L T r e e %
  411. % %
  412. % %
  413. % %
  414. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  415. %
  416. % DestroyXMLTree() destroys the xml-tree.
  417. %
  418. % The format of the DestroyXMLTree method is:
  419. %
  420. % XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info)
  421. %
  422. % A description of each parameter follows:
  423. %
  424. % o xml_info: The xml info.
  425. %
  426. */
  427. static char **DestroyXMLTreeAttributes(char **attributes)
  428. {
  429. register long
  430. i;
  431. /*
  432. Destroy a tag attribute list.
  433. */
  434. if ((attributes == (char **) NULL) || (attributes == sentinel))
  435. return((char **) NULL);
  436. for (i=0; attributes[i] != (char *) NULL; i+=2)
  437. {
  438. /*
  439. Destroy attribute tag and value.
  440. */
  441. if (attributes[i] != (char *) NULL)
  442. attributes[i]=(char *) RelinquishMagickMemory(attributes[i]);
  443. if (attributes[i+1] != (char *) NULL)
  444. attributes[i+1]=(char *) RelinquishMagickMemory(attributes[i+1]);
  445. }
  446. attributes=(char **) RelinquishMagickMemory(attributes);
  447. return((char **) NULL);
  448. }
  449. MagickExport XMLTreeInfo *DestroyXMLTree(XMLTreeInfo *xml_info)
  450. {
  451. char
  452. **attributes;
  453. long
  454. j;
  455. register long
  456. i;
  457. XMLTreeRoot
  458. *root;
  459. assert(xml_info != (XMLTreeInfo *) NULL);
  460. assert((xml_info->signature == MagickSignature) ||
  461. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  462. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  463. if (xml_info->child != (XMLTreeInfo *) NULL)
  464. xml_info->child=DestroyXMLTree(xml_info->child);
  465. if (xml_info->ordered != (XMLTreeInfo *) NULL)
  466. xml_info->ordered=DestroyXMLTree(xml_info->ordered);
  467. if (xml_info->parent == (XMLTreeInfo *) NULL)
  468. {
  469. /*
  470. Free root tag allocations.
  471. */
  472. root=(XMLTreeRoot *) xml_info;
  473. for (i=NumberPredefinedEntities; root->entities[i]; i+=2)
  474. root->entities[i+1]=(char *) RelinquishMagickMemory(
  475. root->entities[i+1]);
  476. root->entities=(char **) RelinquishMagickMemory(root->entities);
  477. for (i=0; root->attributes[i] != (char **) NULL; i++)
  478. {
  479. attributes=root->attributes[i];
  480. if (attributes[0] != (char *) NULL)
  481. attributes[0]=(char *) RelinquishMagickMemory(attributes[0]);
  482. for (j=1; attributes[j] != (char *) NULL; j+=3)
  483. {
  484. if (attributes[j] != (char *) NULL)
  485. attributes[j]=(char *) RelinquishMagickMemory(attributes[j]);
  486. if (attributes[j+1] != (char *) NULL)
  487. attributes[j+1]=(char *) RelinquishMagickMemory(attributes[j+1]);
  488. if (attributes[j+2] != (char *) NULL)
  489. attributes[j+2]=(char *) RelinquishMagickMemory(attributes[j+2]);
  490. }
  491. attributes=(char **) RelinquishMagickMemory(attributes);
  492. }
  493. if (root->attributes[0] != (char **) NULL)
  494. root->attributes=(char ***) RelinquishMagickMemory(root->attributes);
  495. for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
  496. {
  497. for (j=1; root->processing_instructions[i][j]; j++);
  498. root->processing_instructions[i][j+1]=(char *)
  499. RelinquishMagickMemory(root->processing_instructions[i][j+1]);
  500. root->processing_instructions[i]=(char **)
  501. RelinquishMagickMemory(root->processing_instructions[i]);
  502. }
  503. if (root->processing_instructions[0] != (char **) NULL)
  504. root->processing_instructions=(char ***)
  505. RelinquishMagickMemory(root->processing_instructions);
  506. }
  507. xml_info->attributes=DestroyXMLTreeAttributes(xml_info->attributes);
  508. xml_info->content=(char *) RelinquishMagickMemory(xml_info->content);
  509. xml_info->tag=(char *) RelinquishMagickMemory(xml_info->tag);
  510. xml_info=(XMLTreeInfo *) RelinquishMagickMemory(xml_info);
  511. return((XMLTreeInfo *) NULL);
  512. }
  513. /*
  514. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  515. % %
  516. % %
  517. % %
  518. % G e t N e x t X M L T r e e T a g %
  519. % %
  520. % %
  521. % %
  522. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  523. %
  524. % GetNextXMLTreeTag() returns the next tag or NULL if not found.
  525. %
  526. % The format of the GetNextXMLTreeTag method is:
  527. %
  528. % XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info)
  529. %
  530. % A description of each parameter follows:
  531. %
  532. % o xml_info: The xml info.
  533. %
  534. */
  535. MagickExport XMLTreeInfo *GetNextXMLTreeTag(XMLTreeInfo *xml_info)
  536. {
  537. assert(xml_info != (XMLTreeInfo *) NULL);
  538. assert((xml_info->signature == MagickSignature) ||
  539. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  540. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  541. return(xml_info->next);
  542. }
  543. /*
  544. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  545. % %
  546. % %
  547. % %
  548. % G e t X M L T r e e A t t r i b u t e %
  549. % %
  550. % %
  551. % %
  552. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  553. %
  554. % GetXMLTreeAttribute() returns the value of the attribute tag with the
  555. % specified tag if found, otherwise NULL.
  556. %
  557. % The format of the GetXMLTreeAttribute method is:
  558. %
  559. % XMLTreeInfo *GetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag)
  560. %
  561. % A description of each parameter follows:
  562. %
  563. % o xml_info: The xml info.
  564. %
  565. % o tag: The attribute tag.
  566. %
  567. */
  568. MagickExport const char *GetXMLTreeAttribute(XMLTreeInfo *xml_info,
  569. const char *tag)
  570. {
  571. long
  572. j;
  573. register long
  574. i;
  575. XMLTreeRoot
  576. *root;
  577. assert(xml_info != (XMLTreeInfo *) NULL);
  578. assert((xml_info->signature == MagickSignature) ||
  579. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  580. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  581. if (xml_info->attributes == (char **) NULL)
  582. return((const char *) NULL);
  583. i=0;
  584. while ((xml_info->attributes[i] != (char *) NULL) &&
  585. (strcmp(xml_info->attributes[i],tag) != 0))
  586. i+=2;
  587. if (xml_info->attributes[i] != (char *) NULL)
  588. return(xml_info->attributes[i+1]);
  589. root=(XMLTreeRoot*) xml_info;
  590. while (root->root.parent != (XMLTreeInfo *) NULL)
  591. root=(XMLTreeRoot *) root->root.parent;
  592. i=0;
  593. while ((root->attributes[i] != (char **) NULL) &&
  594. (strcmp(root->attributes[i][0],xml_info->tag) != 0))
  595. i++;
  596. if (root->attributes[i] == (char **) NULL)
  597. return((const char *) NULL);
  598. j=1;
  599. while ((root->attributes[i][j] != (char *) NULL) &&
  600. (strcmp(root->attributes[i][j],tag) != 0))
  601. j+=3;
  602. if (root->attributes[i][j] == (char *) NULL)
  603. return((const char *) NULL);
  604. return(root->attributes[i][j+1]);
  605. }
  606. /*
  607. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  608. % %
  609. % %
  610. % %
  611. % G e t X M L T r e e C h i l d %
  612. % %
  613. % %
  614. % %
  615. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  616. %
  617. % GetXMLTreeChild() returns the first child tag with the specified tag if
  618. % found, otherwise NULL.
  619. %
  620. % The format of the GetXMLTreeChild method is:
  621. %
  622. % XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag)
  623. %
  624. % A description of each parameter follows:
  625. %
  626. % o xml_info: The xml info.
  627. %
  628. */
  629. MagickExport XMLTreeInfo *GetXMLTreeChild(XMLTreeInfo *xml_info,const char *tag)
  630. {
  631. XMLTreeInfo
  632. *child;
  633. assert(xml_info != (XMLTreeInfo *) NULL);
  634. assert((xml_info->signature == MagickSignature) ||
  635. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  636. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  637. child=xml_info->child;
  638. if (tag != (const char *) NULL)
  639. while ((child != (XMLTreeInfo *) NULL) && (strcmp(child->tag,tag) != 0))
  640. child=child->sibling;
  641. return(child);
  642. }
  643. /*
  644. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  645. % %
  646. % %
  647. % %
  648. % G e t X M L T r e e C o n t e n t %
  649. % %
  650. % %
  651. % %
  652. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  653. %
  654. % GetXMLTreeContent() returns any content associated with specified
  655. % xml-tree node.
  656. %
  657. % The format of the GetXMLTreeContent method is:
  658. %
  659. % XMLTreeInfo *GetXMLTreeContent(XMLTreeInfo *xml_info)
  660. %
  661. % A description of each parameter follows:
  662. %
  663. % o xml_info: The xml info.
  664. %
  665. */
  666. MagickExport const char *GetXMLTreeContent(XMLTreeInfo *xml_info)
  667. {
  668. assert(xml_info != (XMLTreeInfo *) NULL);
  669. assert((xml_info->signature == MagickSignature) ||
  670. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  671. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  672. return(xml_info->content);
  673. }
  674. /*
  675. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  676. % %
  677. % %
  678. % %
  679. % G e t X M L T r e e O r d e r e d %
  680. % %
  681. % %
  682. % %
  683. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  684. %
  685. % GetXMLTreeOrdered() returns the next ordered node if found, otherwise NULL.
  686. %
  687. % The format of the GetXMLTreeOrdered method is:
  688. %
  689. % XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info)
  690. %
  691. % A description of each parameter follows:
  692. %
  693. % o xml_info: The xml info.
  694. %
  695. */
  696. MagickExport XMLTreeInfo *GetXMLTreeOrdered(XMLTreeInfo *xml_info)
  697. {
  698. assert(xml_info != (XMLTreeInfo *) NULL);
  699. assert((xml_info->signature == MagickSignature) ||
  700. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  701. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  702. return(xml_info->ordered);
  703. }
  704. /*
  705. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  706. % %
  707. % %
  708. % %
  709. % G e t X M L T r e e P a t h %
  710. % %
  711. % %
  712. % %
  713. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  714. %
  715. % GetXMLTreePath() traverses the XML-tree as defined by the specified path
  716. % and returns the node if found, otherwise NULL.
  717. %
  718. % The format of the GetXMLTreePath method is:
  719. %
  720. % XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path)
  721. %
  722. % A description of each parameter follows:
  723. %
  724. % o xml_info: The xml info.
  725. %
  726. % o path: The path (e.g. property/elapsed-time).
  727. %
  728. */
  729. MagickExport XMLTreeInfo *GetXMLTreePath(XMLTreeInfo *xml_info,const char *path)
  730. {
  731. char
  732. **components,
  733. subnode[MaxTextExtent],
  734. tag[MaxTextExtent];
  735. long
  736. j;
  737. register long
  738. i;
  739. XMLTreeInfo
  740. *node;
  741. unsigned long
  742. number_components;
  743. assert(xml_info != (XMLTreeInfo *) NULL);
  744. assert((xml_info->signature == MagickSignature) ||
  745. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  746. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  747. node=xml_info;
  748. components=GetPathComponents(path,&number_components);
  749. if (components == (char **) NULL)
  750. return((XMLTreeInfo *) NULL);
  751. for (i=0; i < (long) number_components; i++)
  752. {
  753. GetPathComponent(components[i],SubimagePath,subnode);
  754. GetPathComponent(components[i],CanonicalPath,tag);
  755. node=GetXMLTreeChild(node,tag);
  756. if (node == (XMLTreeInfo *) NULL)
  757. break;
  758. for (j=atol(subnode)-1; j > 0; j--)
  759. {
  760. node=GetXMLTreeOrdered(node);
  761. if (node == (XMLTreeInfo *) NULL)
  762. break;
  763. }
  764. if (node == (XMLTreeInfo *) NULL)
  765. break;
  766. components[i]=(char *) RelinquishMagickMemory(components[i]);
  767. }
  768. for ( ; i < (long) number_components; i++)
  769. components[i]=(char *) RelinquishMagickMemory(components[i]);
  770. components=(char **) RelinquishMagickMemory(components);
  771. return(node);
  772. }
  773. /*
  774. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  775. % %
  776. % %
  777. % %
  778. % G e t X M L T r e e P r o c e s s i n g I n s t r u c t i o n s %
  779. % %
  780. % %
  781. % %
  782. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  783. %
  784. % GetXMLTreeProcessingInstructions() returns a null terminated array of
  785. % processing instructions for the given target.
  786. %
  787. % The format of the GetXMLTreeProcessingInstructions method is:
  788. %
  789. % XMLTreeInfo *GetXMLTreeProcessingInstructions(XMLTreeInfo *xml_info,
  790. % const char *target)
  791. %
  792. % A description of each parameter follows:
  793. %
  794. % o xml_info: The xml info.
  795. %
  796. */
  797. MagickExport const char **GetXMLTreeProcessingInstructions(
  798. XMLTreeInfo *xml_info,const char *target)
  799. {
  800. register long
  801. i;
  802. XMLTreeRoot
  803. *root;
  804. assert(xml_info != (XMLTreeInfo *) NULL);
  805. assert((xml_info->signature == MagickSignature) ||
  806. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  807. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  808. root=(XMLTreeRoot *) xml_info;
  809. while (root->root.parent != (XMLTreeInfo *) NULL)
  810. root=(XMLTreeRoot *) root->root.parent;
  811. i=0;
  812. while ((root->processing_instructions[i] != (char **) NULL) &&
  813. (strcmp(root->processing_instructions[i][0],target) != 0))
  814. i++;
  815. if (root->processing_instructions[i] == (char **) NULL)
  816. return((const char **) sentinel);
  817. return((const char **) (root->processing_instructions[i]+1));
  818. }
  819. /*
  820. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  821. % %
  822. % %
  823. % %
  824. % G e t X M L T r e e S i b l i n g %
  825. % %
  826. % %
  827. % %
  828. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  829. %
  830. % GetXMLTreeSibling() returns the node sibling if found, otherwise NULL.
  831. %
  832. % The format of the GetXMLTreeSibling method is:
  833. %
  834. % XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info)
  835. %
  836. % A description of each parameter follows:
  837. %
  838. % o xml_info: The xml info.
  839. %
  840. */
  841. MagickExport XMLTreeInfo *GetXMLTreeSibling(XMLTreeInfo *xml_info)
  842. {
  843. assert(xml_info != (XMLTreeInfo *) NULL);
  844. assert((xml_info->signature == MagickSignature) ||
  845. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  846. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  847. return(xml_info->sibling);
  848. }
  849. /*
  850. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  851. % %
  852. % %
  853. % %
  854. % G e t X M L T r e e T a g %
  855. % %
  856. % %
  857. % %
  858. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  859. %
  860. % GetXMLTreeTag() returns the tag associated with specified xml-tree node.
  861. %
  862. % The format of the GetXMLTreeTag method is:
  863. %
  864. % XMLTreeInfo *GetXMLTreeTag(XMLTreeInfo *xml_info)
  865. %
  866. % A description of each parameter follows:
  867. %
  868. % o xml_info: The xml info.
  869. %
  870. */
  871. MagickExport const char *GetXMLTreeTag(XMLTreeInfo *xml_info)
  872. {
  873. assert(xml_info != (XMLTreeInfo *) NULL);
  874. assert((xml_info->signature == MagickSignature) ||
  875. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  876. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  877. return(xml_info->tag);
  878. }
  879. /*
  880. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  881. % %
  882. % %
  883. % %
  884. % I n s e r t I n t o T a g X M L T r e e %
  885. % %
  886. % %
  887. % %
  888. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  889. %
  890. % InsertTagIntoXMLTree() inserts a tag at an offset relative to the start of
  891. % the parent tag's character content. This method returns the child tag.
  892. %
  893. % The format of the InsertTagIntoXMLTree method is:
  894. %
  895. % XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info,
  896. % XMLTreeInfo *child,const size_t offset)
  897. %
  898. % A description of each parameter follows:
  899. %
  900. % o xml_info: The xml info.
  901. %
  902. % o child: The child tag.
  903. %
  904. % o offset: The tag offset.
  905. %
  906. */
  907. MagickExport XMLTreeInfo *InsertTagIntoXMLTree(XMLTreeInfo *xml_info,
  908. XMLTreeInfo *child,const size_t offset)
  909. {
  910. XMLTreeInfo
  911. *head,
  912. *node,
  913. *previous;
  914. child->ordered=(XMLTreeInfo *) NULL;
  915. child->sibling=(XMLTreeInfo *) NULL;
  916. child->next=(XMLTreeInfo *) NULL;
  917. child->offset=offset;
  918. child->parent=xml_info;
  919. if (xml_info->child == (XMLTreeInfo *) NULL)
  920. {
  921. xml_info->child=child;
  922. return(child);
  923. }
  924. head=xml_info->child;
  925. if (head->offset > offset)
  926. {
  927. child->ordered=head;
  928. xml_info->child=child;
  929. }
  930. else
  931. {
  932. node=head;
  933. while ((node->ordered != (XMLTreeInfo *) NULL) &&
  934. (node->ordered->offset <= offset))
  935. node=node->ordered;
  936. child->ordered=node->ordered;
  937. node->ordered=child;
  938. }
  939. previous=(XMLTreeInfo *) NULL;
  940. node=head;
  941. while ((node != (XMLTreeInfo *) NULL) && (strcmp(node->tag,child->tag) != 0))
  942. {
  943. previous=node;
  944. node=node->sibling;
  945. }
  946. if ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset))
  947. {
  948. while ((node->next != (XMLTreeInfo *) NULL) &&
  949. (node->next->offset <= offset))
  950. node=node->next;
  951. child->next=node->next;
  952. node->next=child;
  953. }
  954. else
  955. {
  956. if ((previous != (XMLTreeInfo *) NULL) && (node != (XMLTreeInfo *) NULL))
  957. previous->sibling=node->sibling;
  958. child->next=node;
  959. previous=(XMLTreeInfo *) NULL;
  960. node=head;
  961. while ((node != (XMLTreeInfo *) NULL) && (node->offset <= offset))
  962. {
  963. previous=node;
  964. node=node->sibling;
  965. }
  966. child->sibling=node;
  967. if (previous != (XMLTreeInfo *) NULL)
  968. previous->sibling=child;
  969. }
  970. return(child);
  971. }
  972. /*
  973. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  974. % %
  975. % %
  976. % %
  977. % N e w X M L T r e e %
  978. % %
  979. % %
  980. % %
  981. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  982. %
  983. % NewXMLTree() returns a XMLTreeInfo xml-tree as defined by the specified
  984. % XML string.
  985. %
  986. % The format of the NewXMLTree method is:
  987. %
  988. % XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception)
  989. %
  990. % A description of each parameter follows:
  991. %
  992. % o xml: The XML string.
  993. %
  994. % o exception: Return any errors or warnings in this structure.
  995. %
  996. */
  997. static char *ConvertUTF16ToUTF8(const char *content,size_t *length)
  998. {
  999. char
  1000. *utf8;
  1001. int
  1002. bits,
  1003. byte,
  1004. c,
  1005. encoding;
  1006. long
  1007. j;
  1008. register long
  1009. i;
  1010. size_t
  1011. max_length;
  1012. utf8=(char *) AcquireMagickMemory((*length)*sizeof(*utf8));
  1013. if (utf8 == (char *) NULL)
  1014. return((char *) NULL);
  1015. encoding=(*content == '\xFE') ? 1 : (*content == '\xFF') ? 0 : -1;
  1016. if (encoding == -1)
  1017. {
  1018. /*
  1019. Already UTF-8.
  1020. */
  1021. (void) CopyMagickMemory(utf8,content,*length);
  1022. return(utf8);
  1023. }
  1024. j=0;
  1025. max_length=(*length);
  1026. for (i=2; i < (long) (*length-1); i+=2)
  1027. {
  1028. c=(encoding != 0) ? ((content[i] & 0xff) << 8) | (content[i+1] & 0xff) :
  1029. ((content[i+1] & 0xff) << 8) | (content[i] & 0xff);
  1030. if ((c >= 0xd800) && (c <= 0xdfff) && ((i+=2) < (long) (*length-1)))
  1031. {
  1032. byte=(encoding != 0) ? ((content[i] & 0xff) << 8) |
  1033. (content[i+1] & 0xff) : ((content[i+1] & 0xff) << 8) |
  1034. (content[i] & 0xff);
  1035. c=(((c & 0x3ff) << 10) | (byte & 0x3ff))+0x10000;
  1036. }
  1037. if ((size_t) (j+MaxTextExtent) > max_length)
  1038. {
  1039. max_length=(size_t) j+MaxTextExtent;
  1040. utf8=(char *) ResizeMagickMemory(utf8,max_length*sizeof(*utf8));
  1041. if (utf8 == (char *) NULL)
  1042. return(utf8);
  1043. }
  1044. if (c < 0x80)
  1045. {
  1046. utf8[j]=c;
  1047. j++;
  1048. continue;
  1049. }
  1050. /*
  1051. Multi-byte UTF-8 sequence.
  1052. */
  1053. byte=c;
  1054. for (bits=0; byte != 0; byte/=2)
  1055. bits++;
  1056. bits=(bits-2)/5;
  1057. utf8[j++]=(0xFF << (7-bits)) | (c >> (6*bits));
  1058. while (bits != 0)
  1059. {
  1060. bits--;
  1061. utf8[j]=0x80 | ((c >> (6*bits)) & 0x3f);
  1062. j++;
  1063. }
  1064. }
  1065. *length=(size_t) j;
  1066. return((char *) ResizeMagickMemory(utf8,*length*sizeof(*utf8)));
  1067. }
  1068. static char *ParseEntities(char *xml,char **entities,char state)
  1069. {
  1070. char
  1071. *entity;
  1072. int
  1073. byte,
  1074. c;
  1075. register char
  1076. *p,
  1077. *q;
  1078. register long
  1079. i;
  1080. size_t
  1081. extent,
  1082. length;
  1083. ssize_t
  1084. offset;
  1085. /*
  1086. Normalize line endings.
  1087. */
  1088. p=xml;
  1089. q=xml;
  1090. for ( ; *xml != '\0'; xml++)
  1091. while (*xml == '\r')
  1092. {
  1093. *(xml++)='\n';
  1094. if (*xml == '\n')
  1095. (void) CopyMagickMemory(xml,xml+1,strlen(xml));
  1096. }
  1097. for (xml=p; ; )
  1098. {
  1099. while ((*xml != '\0') && (*xml != '&') && ((*xml != '%') ||
  1100. (state != '%')) && (isspace((int) ((unsigned char) *xml) == 0)))
  1101. xml++;
  1102. if (*xml == '\0')
  1103. break;
  1104. /*
  1105. States include:
  1106. '&' for general entity decoding
  1107. '%' for parameter entity decoding
  1108. 'c' for CDATA sections
  1109. ' ' for attributes normalization
  1110. '*' for non-CDATA attributes normalization
  1111. */
  1112. if ((state != 'c') && (strncmp(xml,"&#",2) == 0))
  1113. {
  1114. /*
  1115. Character reference.
  1116. */
  1117. if (xml[2] != 'x')
  1118. c=strtol(xml+2,&entity,10); /* base 10 */
  1119. else
  1120. c=strtol(xml+3,&entity,16); /* base 16 */
  1121. if ((c == 0) || (*entity != ';'))
  1122. {
  1123. /*
  1124. Not a character reference.
  1125. */
  1126. xml++;
  1127. continue;
  1128. }
  1129. if (c < 0x80)
  1130. *(xml++)=c;
  1131. else
  1132. {
  1133. /*
  1134. Multi-byte UTF-8 sequence.
  1135. */
  1136. byte=c;
  1137. for (i=0; byte != 0; byte/=2)
  1138. i++;
  1139. i=(i-2)/5;
  1140. *xml=(char) ((0xFF << (7-i)) | (c >> (6*i)));
  1141. xml++;
  1142. while (i != 0)
  1143. {
  1144. i--;
  1145. *xml=(char) (0x80 | ((c >> (6*i)) & 0x3F));
  1146. xml++;
  1147. }
  1148. }
  1149. (void) CopyMagickMemory(xml,strchr(xml,';')+1,strlen(strchr(xml,';')));
  1150. }
  1151. else
  1152. if (((*xml == '&') && ((state == '&') || (state == ' ') ||
  1153. (state == '*'))) || ((state == '%') && (*xml == '%')))
  1154. {
  1155. /*
  1156. Find entity in the list.
  1157. */
  1158. i=0;
  1159. while ((entities[i] != (char *) NULL) &&
  1160. (strncmp(xml+1,entities[i],strlen(entities[i])) != 0))
  1161. i+=2;
  1162. if (entities[i++] == (char *) NULL)
  1163. xml++;
  1164. else
  1165. {
  1166. /*
  1167. Found a match.
  1168. */
  1169. length=strlen(entities[i]);
  1170. entity=strchr(xml,';');
  1171. if (length > (size_t) (entity-xml))
  1172. {
  1173. offset=(ssize_t) (xml-p);
  1174. extent=(size_t) (offset+length+strlen(entity));
  1175. if (p != q)
  1176. p=(char *) ResizeMagickMemory(p,extent*sizeof(*p));
  1177. else
  1178. {
  1179. char
  1180. *xml;
  1181. xml=(char *) AcquireMagickMemory(extent*sizeof(*xml));
  1182. if (xml != (char *) NULL)
  1183. {
  1184. (void) CopyMagickString(xml,p,extent*sizeof(*xml));
  1185. p=xml;
  1186. }
  1187. }
  1188. if (p == (char *) NULL)
  1189. ThrowMagickFatalException(ResourceLimitFatalError,
  1190. "UnableToAcquireString",xml);
  1191. xml=p+offset;
  1192. entity=strchr(xml,';');
  1193. }
  1194. (void) CopyMagickMemory(xml+length,entity+1,strlen(entity));
  1195. (void) strncpy(xml,entities[i],length);
  1196. }
  1197. }
  1198. else
  1199. if (((state == ' ') || (state == '*')) &&
  1200. (isspace((int) ((unsigned char) *xml) != 0)))
  1201. *(xml++)=' ';
  1202. else
  1203. xml++;
  1204. }
  1205. if (state == '*')
  1206. {
  1207. /*
  1208. Normalize spaces for non-CDATA attributes.
  1209. */
  1210. for (xml=p; *xml != '\0'; xml++)
  1211. {
  1212. i=(long) strspn(xml," ");
  1213. if (i != 0)
  1214. (void) CopyMagickMemory(xml,xml+i,strlen(xml+i)+1);
  1215. while ((*xml != '\0') && (*xml != ' '))
  1216. xml++;
  1217. }
  1218. xml--;
  1219. if ((xml >= p) && (*xml == ' '))
  1220. *xml='\0';
  1221. }
  1222. return(p == q ? ConstantString(p) : p);
  1223. }
  1224. void ParseCharacterContent(XMLTreeRoot *root,char *xml,const size_t length,
  1225. const char state)
  1226. {
  1227. XMLTreeInfo
  1228. *xml_info;
  1229. xml_info=root->node;
  1230. if ((xml_info == (XMLTreeInfo *) NULL) || (xml_info->tag == (char *) NULL) ||
  1231. (length == 0))
  1232. return;
  1233. xml[length]='\0';
  1234. xml=ParseEntities(xml,root->entities,state);
  1235. if (*xml_info->content != '\0')
  1236. {
  1237. (void) ConcatenateString(&xml_info->content,xml);
  1238. xml=(char *) RelinquishMagickMemory(xml);
  1239. }
  1240. else
  1241. {
  1242. if (xml_info->content != (char *) NULL)
  1243. xml_info->content=(char *) RelinquishMagickMemory(xml_info->content);
  1244. xml_info->content=xml;
  1245. }
  1246. }
  1247. static XMLTreeInfo *ParseCloseTag(XMLTreeRoot *root,char *tag,
  1248. char *magick_unused(xml),ExceptionInfo *exception)
  1249. {
  1250. if ((root->node == (XMLTreeInfo *) NULL) ||
  1251. (root->node->tag == (char *) NULL) || (strcmp(tag,root->node->tag) != 0))
  1252. {
  1253. (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
  1254. "ParseError","unexpected closing tag </%s>",tag);
  1255. return(&root->root);
  1256. }
  1257. root->node=root->node->parent;
  1258. return((XMLTreeInfo *) NULL);
  1259. }
  1260. static MagickBooleanType ValidateEntities(char *tag,char *xml,char **entities)
  1261. {
  1262. register long
  1263. i;
  1264. /*
  1265. Check for circular entity references.
  1266. */
  1267. for ( ; ; xml++)
  1268. {
  1269. while ((*xml != '\0') && (*xml != '&'))
  1270. xml++;
  1271. if (*xml == '\0')
  1272. return(MagickTrue);
  1273. if (strncmp(xml+1,tag,strlen(tag)) == 0)
  1274. return(MagickFalse);
  1275. i=0;
  1276. while ((entities[i] != (char *) NULL) &&
  1277. (strncmp(entities[i],xml+1,strlen(entities[i]) == 0)))
  1278. i+=2;
  1279. if ((entities[i] != (char *) NULL) &&
  1280. (ValidateEntities(tag,entities[i+1],entities) == 0))
  1281. return(MagickFalse);
  1282. }
  1283. return(MagickTrue);
  1284. }
  1285. static void ParseProcessingInstructions(XMLTreeRoot *root,char *xml,
  1286. size_t length)
  1287. {
  1288. char
  1289. *target;
  1290. long
  1291. j;
  1292. register long
  1293. i;
  1294. target=xml;
  1295. xml[length]='\0';
  1296. xml+=strcspn(xml,XMLWhitespace);
  1297. if (*xml != '\0')
  1298. {
  1299. *xml='\0';
  1300. xml+=strspn(xml+1,XMLWhitespace)+1;
  1301. }
  1302. if (strcmp(target,"xml") == 0)
  1303. {
  1304. xml=strstr(xml,"standalone");
  1305. if ((xml != (char *) NULL) &&
  1306. (strncmp(xml+strspn(xml+10,XMLWhitespace "='\"")+10,"yes",3) == 0))
  1307. root->standalone=MagickTrue;
  1308. return;
  1309. }
  1310. if (root->processing_instructions[0] == (char **) NULL)
  1311. {
  1312. root->processing_instructions=(char ***) AcquireMagickMemory(sizeof(
  1313. *root->processing_instructions));
  1314. if (root->processing_instructions ==(char ***) NULL)
  1315. ThrowMagickFatalException(ResourceLimitFatalError,
  1316. "UnableToAcquireString",xml);
  1317. *root->processing_instructions=(char **) NULL;
  1318. }
  1319. i=0;
  1320. while ((root->processing_instructions[i] != (char **) NULL) &&
  1321. (strcmp(target,root->processing_instructions[i][0]) != 0))
  1322. i++;
  1323. if (root->processing_instructions[i] == (char **) NULL)
  1324. {
  1325. root->processing_instructions=(char ***) ResizeMagickMemory(
  1326. root->processing_instructions,(size_t) (i+2)*
  1327. sizeof(*root->processing_instructions));
  1328. if (root->processing_instructions == (char ***) NULL)
  1329. ThrowMagickFatalException(ResourceLimitFatalError,
  1330. "UnableToAcquireString",xml);
  1331. root->processing_instructions[i]=(char **) AcquireMagickMemory(3*
  1332. sizeof(**root->processing_instructions));
  1333. if (root->processing_instructions[i] == (char **) NULL)
  1334. ThrowMagickFatalException(ResourceLimitFatalError,
  1335. "UnableToAcquireString",xml);
  1336. root->processing_instructions[i][0]=ConstantString(target);
  1337. root->processing_instructions[i][1]=(char *) NULL;
  1338. root->processing_instructions[i+1]=(char **) NULL;
  1339. }
  1340. j=1;
  1341. while (root->processing_instructions[i][j] != (char *) NULL)
  1342. j++;
  1343. root->processing_instructions[i]=(char **) ResizeMagickMemory(
  1344. root->processing_instructions[i],(size_t) (j+3)*sizeof(
  1345. **root->processing_instructions));
  1346. if (root->processing_instructions[i] == (char **) NULL)
  1347. ThrowMagickFatalException(ResourceLimitFatalError,"UnableToAcquireString",
  1348. xml);
  1349. root->processing_instructions[i][j+2]=(char *) ResizeMagickMemory(
  1350. root->processing_instructions[i][j+1],(size_t) (j+1)* sizeof(
  1351. **root->processing_instructions));
  1352. if (root->processing_instructions[i][j+2] == (char *) NULL)
  1353. ThrowMagickFatalException(ResourceLimitFatalError,"UnableToAcquireString",
  1354. xml);
  1355. (void) CopyMagickString(root->processing_instructions[i][j+2]+j-1,
  1356. root->root.tag != (char *) NULL ? ">" : "<",2);
  1357. root->processing_instructions[i][j+1]=(char *) NULL;
  1358. root->processing_instructions[i][j]=ConstantString(xml);
  1359. }
  1360. static MagickBooleanType ParseInternalDoctype(XMLTreeRoot *root,char *xml,
  1361. size_t length,ExceptionInfo *exception)
  1362. {
  1363. char
  1364. *c,
  1365. **entities,
  1366. *n,
  1367. **predefined_entitites,
  1368. q,
  1369. *t,
  1370. *v;
  1371. long
  1372. j;
  1373. register long
  1374. i;
  1375. n=(char *) NULL;
  1376. predefined_entitites=(char **) AcquireMagickMemory(sizeof(sentinel));
  1377. if (predefined_entitites == (char **) NULL)
  1378. {
  1379. char
  1380. *message;
  1381. message=GetExceptionMessage(errno);
  1382. (void) ThrowMagickException(exception,GetMagickModule(),
  1383. ResourceLimitError,"MemoryAllocationFailed","`%s'",message);
  1384. message=(char *) RelinquishMagickMemory(message);
  1385. return(MagickFalse);
  1386. }
  1387. (void) CopyMagickMemory(predefined_entitites,sentinel,sizeof(sentinel));
  1388. for (xml[length]='\0'; xml != (char *) NULL; )
  1389. {
  1390. while ((*xml != '\0') && (*xml != '<') && (*xml != '%'))
  1391. xml++;
  1392. if (*xml == '\0')
  1393. break;
  1394. if (strncmp(xml,"<!ENTITY",8) == 0)
  1395. {
  1396. /*
  1397. Parse entity definitions.
  1398. */
  1399. xml+=strspn(xml+8,XMLWhitespace)+8;
  1400. c=xml;
  1401. n=xml+strspn(xml,XMLWhitespace "%");
  1402. xml=n+strcspn(n,XMLWhitespace);
  1403. *xml=';';
  1404. v=xml+strspn(xml+1,XMLWhitespace)+1;
  1405. q=(*v);
  1406. v++;
  1407. if ((q != '"') && (q != '\''))
  1408. {
  1409. /*
  1410. Skip externals.
  1411. */
  1412. xml=strchr(xml,'>');
  1413. continue;
  1414. }
  1415. entities=(*c == '%') ? predefined_entitites : root->entities;
  1416. for (i=0; entities[i] != (char *) NULL; i++);
  1417. entities=(char **) ResizeMagickMemory(entities,(size_t) (i+3)*
  1418. sizeof(*entities));
  1419. if (entities == (char **) NULL)
  1420. ThrowMagickFatalException(ResourceLimitFatalError,
  1421. "UnableToAcquireString",xml);
  1422. if (*c == '%')
  1423. predefined_entitites=entities;
  1424. else
  1425. root->entities=entities;
  1426. xml++;
  1427. *xml='\0';
  1428. xml=strchr(v,q);
  1429. if (xml != (char *) NULL)
  1430. {
  1431. *xml='\0';
  1432. xml++;
  1433. }
  1434. entities[i+1]=ParseEntities(v,predefined_entitites,'%');
  1435. entities[i+2]=(char *) NULL;
  1436. if (ValidateEntities(n,entities[i+1],entities) != MagickFalse)
  1437. entities[i]=n;
  1438. else
  1439. {
  1440. if (entities[i+1] != v)
  1441. entities[i+1]=(char *) RelinquishMagickMemory(entities[i+1]);
  1442. (void) ThrowMagickException(exception,GetMagickModule(),
  1443. OptionWarning,"ParseError","circular entity declaration &%s",n);
  1444. pred

Large files files are truncated, but you can click here to view the full file