PageRenderTime 69ms CodeModel.GetById 27ms RepoModel.GetById 0ms 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
  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. predefined_entitites=(char **)
  1445. RelinquishMagickMemory(predefined_entitites);
  1446. return(MagickFalse);
  1447. }
  1448. }
  1449. else
  1450. if (strncmp(xml,"<!ATTLIST",9) == 0)
  1451. {
  1452. /*
  1453. Parse default attributes.
  1454. */
  1455. t=xml+strspn(xml+9,XMLWhitespace)+9;
  1456. if (*t == '\0')
  1457. {
  1458. (void) ThrowMagickException(exception,GetMagickModule(),
  1459. OptionWarning,"ParseError","unclosed <!ATTLIST");
  1460. predefined_entitites=(char **)
  1461. RelinquishMagickMemory(predefined_entitites);
  1462. return(MagickFalse);
  1463. }
  1464. xml=t+strcspn(t,XMLWhitespace ">");
  1465. if (*xml == '>')
  1466. continue;
  1467. *xml='\0';
  1468. i=0;
  1469. while ((root->attributes[i] != (char **) NULL) &&
  1470. (strcmp(n,root->attributes[i][0]) != 0))
  1471. i++;
  1472. while (*(n=++xml+strspn(xml,XMLWhitespace)) && (*n != '>'))
  1473. {
  1474. xml=n+strcspn(n,XMLWhitespace);
  1475. if (*xml != '\0')
  1476. *xml='\0';
  1477. else
  1478. {
  1479. (void) ThrowMagickException(exception,GetMagickModule(),
  1480. OptionWarning,"ParseError","malformed <!ATTLIST");
  1481. predefined_entitites=(char **)
  1482. RelinquishMagickMemory(predefined_entitites);
  1483. return(MagickFalse);
  1484. }
  1485. xml+=strspn(xml+1,XMLWhitespace)+1;
  1486. c=(char *) (strncmp(xml,"CDATA",5) != 0 ? "*" : " ");
  1487. if (strncmp(xml,"NOTATION",8) == 0)
  1488. xml+=strspn(xml+8,XMLWhitespace)+8;
  1489. xml=(*xml == '(') ? strchr(xml,')') : xml+
  1490. strcspn(xml,XMLWhitespace);
  1491. if (xml == (char *) NULL)
  1492. {
  1493. (void) ThrowMagickException(exception,GetMagickModule(),
  1494. OptionWarning,"ParseError","malformed <!ATTLIST");
  1495. predefined_entitites=(char **)
  1496. RelinquishMagickMemory(predefined_entitites);
  1497. return(MagickFalse);
  1498. }
  1499. xml+=strspn(xml,XMLWhitespace ")");
  1500. if (strncmp(xml,"#FIXED",6) == 0)
  1501. xml+=strspn(xml+6,XMLWhitespace)+6;
  1502. if (*xml == '#')
  1503. {
  1504. xml+=strcspn(xml,XMLWhitespace ">")-1;
  1505. if (*c == ' ')
  1506. continue;
  1507. v=(char *) NULL;
  1508. }
  1509. else
  1510. if (((*xml == '"') || (*xml == '\'')) &&
  1511. ((xml=strchr(v=xml+1,*xml)) != (char *) NULL))
  1512. *xml='\0';
  1513. else
  1514. {
  1515. (void) ThrowMagickException(exception,GetMagickModule(),
  1516. OptionWarning,"ParseError","malformed <!ATTLIST");
  1517. predefined_entitites=(char **)
  1518. RelinquishMagickMemory(predefined_entitites);
  1519. return(MagickFalse);
  1520. }
  1521. if (root->attributes[i] == (char **) NULL)
  1522. {
  1523. /*
  1524. New attribute tag.
  1525. */
  1526. if (i == 0)
  1527. root->attributes=(char ***) AcquireMagickMemory(2*sizeof(
  1528. *root->attributes));
  1529. else
  1530. root->attributes=(char ***) ResizeMagickMemory(
  1531. root->attributes,(size_t) (i+2)*
  1532. sizeof(*root->attributes));
  1533. if (root->attributes == (char ***) NULL)
  1534. ThrowMagickFatalException(ResourceLimitFatalError,
  1535. "UnableToAcquireString",xml);
  1536. root->attributes[i]=(char **) AcquireMagickMemory(2*
  1537. sizeof(*root->attributes));
  1538. if (root->attributes[i] == (char **) NULL)
  1539. ThrowMagickFatalException(ResourceLimitFatalError,
  1540. "UnableToAcquireString",xml);
  1541. root->attributes[i][0]=ConstantString(t);
  1542. root->attributes[i][1]=(char *) NULL;
  1543. root->attributes[i+1]=(char **) NULL;
  1544. }
  1545. for (j=1; root->attributes[i][j] != (char *) NULL; j+=3);
  1546. root->attributes[i]=(char **) ResizeMagickMemory(
  1547. root->attributes[i],(size_t) (j+4)*sizeof(*root->attributes));
  1548. if (root->attributes[i] == (char **) NULL)
  1549. ThrowMagickFatalException(ResourceLimitFatalError,
  1550. "UnableToAcquireString",xml);
  1551. root->attributes[i][j+3]=(char *) NULL;
  1552. root->attributes[i][j+2]=ConstantString(c);
  1553. root->attributes[i][j+1]=(char *) NULL;
  1554. if (v != (char *) NULL)
  1555. root->attributes[i][j+1]=ParseEntities(v,root->entities,*c);
  1556. root->attributes[i][j]=ConstantString(n);
  1557. }
  1558. }
  1559. else
  1560. if (strncmp(xml, "<!--", 4) == 0)
  1561. xml=strstr(xml+4,"-->");
  1562. else
  1563. if (strncmp(xml,"<?", 2) == 0)
  1564. {
  1565. c=xml+2;
  1566. xml=strstr(c,"?>");
  1567. if (xml != (char *) NULL)
  1568. {
  1569. ParseProcessingInstructions(root,c,(size_t) (xml-c));
  1570. xml++;
  1571. }
  1572. }
  1573. else
  1574. if (*xml == '<')
  1575. xml=strchr(xml,'>');
  1576. else
  1577. if ((*(xml++) == '%') && (root->standalone == MagickFalse))
  1578. break;
  1579. }
  1580. predefined_entitites=(char **) RelinquishMagickMemory(predefined_entitites);
  1581. return(MagickTrue);
  1582. }
  1583. static void ParseOpenTag(XMLTreeRoot *root,char *tag,char **attributes)
  1584. {
  1585. XMLTreeInfo
  1586. *xml_info;
  1587. xml_info=root->node;
  1588. if (xml_info->tag == (char *) NULL)
  1589. xml_info->tag=ConstantString(tag);
  1590. else
  1591. xml_info=AddChildToXMLTree(xml_info,tag,strlen(xml_info->content));
  1592. xml_info->attributes=attributes;
  1593. root->node=xml_info;
  1594. }
  1595. MagickExport XMLTreeInfo *NewXMLTree(const char *xml,ExceptionInfo *exception)
  1596. {
  1597. char
  1598. **attribute,
  1599. **attributes,
  1600. *tag,
  1601. *utf8;
  1602. int
  1603. c,
  1604. terminal;
  1605. long
  1606. j,
  1607. l;
  1608. register char
  1609. *p;
  1610. register long
  1611. i;
  1612. size_t
  1613. length;
  1614. MagickBooleanType
  1615. status;
  1616. XMLTreeRoot
  1617. *root;
  1618. /*
  1619. Convert xml-string to UTF8.
  1620. */
  1621. length=strlen(xml);
  1622. if (length == 0)
  1623. {
  1624. (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
  1625. "ParseError","root tag missing");
  1626. return((XMLTreeInfo *) NULL);
  1627. }
  1628. root=(XMLTreeRoot *) NewXMLTreeTag((char *) NULL);
  1629. utf8=ConvertUTF16ToUTF8(xml,&length);
  1630. if (utf8 == (char *) NULL)
  1631. {
  1632. char
  1633. *message;
  1634. message=GetExceptionMessage(errno);
  1635. (void) ThrowMagickException(exception,GetMagickModule(),
  1636. ResourceLimitError,"MemoryAllocationFailed","`%s'",message);
  1637. message=(char *) RelinquishMagickMemory(message);
  1638. return((XMLTreeInfo *) NULL);
  1639. }
  1640. terminal=utf8[length-1];
  1641. utf8[length-1]='\0';
  1642. p=utf8;
  1643. while ((*p != '\0') && (*p != '<'))
  1644. p++;
  1645. if (*p == '\0')
  1646. {
  1647. (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
  1648. "ParseError","root tag missing");
  1649. return((XMLTreeInfo *) NULL);
  1650. }
  1651. attribute=(char **) NULL;
  1652. for (p++; ; p++)
  1653. {
  1654. attributes=(char **) sentinel;
  1655. tag=p;
  1656. if ((isalpha((int) ((unsigned char) *p)) !=0) || (*p == '_') ||
  1657. (*p == ':') || (*p < '\0'))
  1658. {
  1659. /*
  1660. Tag.
  1661. */
  1662. if (root->node == (XMLTreeInfo *) NULL)
  1663. {
  1664. (void) ThrowMagickException(exception,GetMagickModule(),
  1665. OptionWarning,"ParseError","root tag missing");
  1666. return(&root->root);
  1667. }
  1668. p+=strcspn(p,XMLWhitespace "/>");
  1669. while (isspace((int) ((unsigned char) *p)) != 0)
  1670. *p++='\0';
  1671. if ((*p != '\0') && (*p != '/') && (*p != '>'))
  1672. {
  1673. /*
  1674. Find tag in default attributes list.
  1675. */
  1676. i=0;
  1677. while ((root->attributes[i] != (char **) NULL) &&
  1678. (strcmp(root->attributes[i][0],tag) != 0))
  1679. i++;
  1680. attribute=root->attributes[i];
  1681. }
  1682. for (l=0; (*p != '\0') && (*p != '/') && (*p != '>'); l+=2)
  1683. {
  1684. /*
  1685. Attribute.
  1686. */
  1687. if (l == 0)
  1688. attributes=(char **) AcquireMagickMemory(4*sizeof(*attributes));
  1689. else
  1690. attributes=(char **) ResizeMagickMemory(attributes,(size_t) (l+4)*
  1691. sizeof(*attributes));
  1692. if (attributes == (char **) NULL)
  1693. ThrowMagickFatalException(ResourceLimitFatalError,
  1694. "UnableToAcquireString",xml);
  1695. if (attributes == (char **) NULL)
  1696. {
  1697. char
  1698. *message;
  1699. message=GetExceptionMessage(errno);
  1700. (void) ThrowMagickException(exception,GetMagickModule(),
  1701. ResourceLimitError,"MemoryAllocationFailed","`%s'",message);
  1702. message=(char *) RelinquishMagickMemory(message);
  1703. return(&root->root);
  1704. }
  1705. attributes[l+2]=(char *) NULL;
  1706. attributes[l+1]=(char *) NULL;
  1707. attributes[l]=p;
  1708. p+=strcspn(p,XMLWhitespace "=/>");
  1709. if ((*p != '=') && (isspace((int) ((unsigned char) *p)) == 0))
  1710. attributes[l]=ConstantString("");
  1711. else
  1712. {
  1713. *p++='\0';
  1714. p+=strspn(p,XMLWhitespace "=");
  1715. c=(*p);
  1716. if ((c == '"') || (c == '\''))
  1717. {
  1718. /*
  1719. Attributes value.
  1720. */
  1721. p++;
  1722. attributes[l+1]=p;
  1723. while ((*p != '\0') && (*p != c))
  1724. p++;
  1725. if (*p != '\0')
  1726. *p++='\0';
  1727. else
  1728. {
  1729. (void) DestroyXMLTreeAttributes(attributes);
  1730. (void) ThrowMagickException(exception,GetMagickModule(),
  1731. OptionWarning,"ParseError","missing %c",c);
  1732. return(&root->root);
  1733. }
  1734. j=1;
  1735. while ((attribute != (char **) NULL) &&
  1736. (attribute[j] != (char *) NULL) &&
  1737. (strcmp(attribute[j],attributes[l]) != 0))
  1738. j+=3;
  1739. attributes[l+1]=ParseEntities(attributes[l+1],root->entities,
  1740. (attribute != (char **) NULL) && (attribute[j] !=
  1741. (char *) NULL) ? *attribute[j+2] : ' ');
  1742. }
  1743. attributes[l]=ConstantString(attributes[l]);
  1744. }
  1745. while (isspace((int) ((unsigned char) *p)) != 0)
  1746. p++;
  1747. }
  1748. if (*p == '/')
  1749. {
  1750. /*
  1751. Self closing tag.
  1752. */
  1753. *p++='\0';
  1754. if (((*p != '\0') && (*p != '>')) ||
  1755. ((*p == '\0') && (terminal != '>')))
  1756. {
  1757. if (l != 0)
  1758. (void) DestroyXMLTreeAttributes(attributes);
  1759. (void) ThrowMagickException(exception,GetMagickModule(),
  1760. OptionWarning,"ParseError","missing >");
  1761. return(&root->root);
  1762. }
  1763. ParseOpenTag(root,tag,attributes);
  1764. (void) ParseCloseTag(root,tag,p,exception);
  1765. }
  1766. else
  1767. {
  1768. c=(*p);
  1769. if ((*p == '>') || ((*p == '\0') && (terminal == '>')))
  1770. {
  1771. *p='\0';
  1772. ParseOpenTag(root,tag,attributes);
  1773. *p=c;
  1774. }
  1775. else
  1776. {
  1777. if (l != 0)
  1778. (void) DestroyXMLTreeAttributes(attributes);
  1779. (void) ThrowMagickException(exception,GetMagickModule(),
  1780. OptionWarning,"ParseError","missing >");
  1781. return(&root->root);
  1782. }
  1783. }
  1784. }
  1785. else
  1786. if (*p == '/')
  1787. {
  1788. /*
  1789. Close tag.
  1790. */
  1791. tag=p+1;
  1792. p+=strcspn(tag,XMLWhitespace ">")+1;
  1793. c=(*p);
  1794. if ((c == '\0') && (terminal != '>'))
  1795. {
  1796. (void) ThrowMagickException(exception,GetMagickModule(),
  1797. OptionWarning,"ParseError","missing >");
  1798. return(&root->root);
  1799. }
  1800. *p='\0';
  1801. if (ParseCloseTag(root,tag,p,exception) != (XMLTreeInfo *) NULL)
  1802. return(&root->root);
  1803. *p=c;
  1804. if (isspace((int) ((unsigned char) *p)) != 0)
  1805. p+=strspn(p,XMLWhitespace);
  1806. }
  1807. else
  1808. if (strncmp(p,"!--",3) == 0)
  1809. {
  1810. /*
  1811. Comment.
  1812. */
  1813. p=strstr(p+3,"--");
  1814. if ((p == (char *) NULL) || ((*(p+=2) != '>') && (*p != '\0')) ||
  1815. ((*p == '\0') && (terminal != '>')))
  1816. {
  1817. (void) ThrowMagickException(exception,GetMagickModule(),
  1818. OptionWarning,"ParseError","unclosed <!--");
  1819. return(&root->root);
  1820. }
  1821. }
  1822. else
  1823. if (strncmp(p,"![CDATA[",8) == 0)
  1824. {
  1825. /*
  1826. Cdata.
  1827. */
  1828. p=strstr(p,"]]>");
  1829. if (p != (char *) NULL)
  1830. {
  1831. p+=2;
  1832. ParseCharacterContent(root,tag+8,(size_t) (p-tag-10),'c');
  1833. }
  1834. else
  1835. {
  1836. (void) ThrowMagickException(exception,GetMagickModule(),
  1837. OptionWarning,"ParseError","unclosed <![CDATA[");
  1838. return(&root->root);
  1839. }
  1840. }
  1841. else
  1842. if (strncmp(p,"!DOCTYPE",8) == 0)
  1843. {
  1844. /*
  1845. DTD.
  1846. */
  1847. for (l=0; (*p != '\0') && (((l == 0) && (*p != '>')) ||
  1848. ((l != 0) && ((*p != ']') ||
  1849. (*(p+strspn(p+1,XMLWhitespace)+1) != '>'))));
  1850. l=(*p == '[') ? 1 : l)
  1851. p+=strcspn(p+1,"[]>")+1;
  1852. if ((*p == '\0') && (terminal != '>'))
  1853. {
  1854. (void) ThrowMagickException(exception,GetMagickModule(),
  1855. OptionWarning,"ParseError","unclosed <!DOCTYPE");
  1856. return(&root->root);
  1857. }
  1858. if (l != 0)
  1859. tag=strchr(tag,'[')+1;
  1860. if (l != 0)
  1861. {
  1862. status=ParseInternalDoctype(root,tag,(size_t) (p-tag),
  1863. exception);
  1864. if (status == MagickFalse)
  1865. return(&root->root);
  1866. p++;
  1867. }
  1868. }
  1869. else
  1870. if (*p == '?')
  1871. {
  1872. /*
  1873. Processing instructions.
  1874. */
  1875. do
  1876. {
  1877. p=strchr(p,'?');
  1878. if (p == (char *) NULL)
  1879. break;
  1880. p++;
  1881. } while ((*p != '\0') && (*p != '>'));
  1882. if ((p == (char *) NULL) || ((*p == '\0') &&
  1883. (terminal != '>')))
  1884. {
  1885. (void) ThrowMagickException(exception,GetMagickModule(),
  1886. OptionWarning,"ParseError","unclosed <?");
  1887. return(&root->root);
  1888. }
  1889. ParseProcessingInstructions(root,tag+1,(size_t) (p-tag-2));
  1890. }
  1891. else
  1892. {
  1893. (void) ThrowMagickException(exception,GetMagickModule(),
  1894. OptionWarning,"ParseError","unexpected <");
  1895. return(&root->root);
  1896. }
  1897. if ((p == (char *) NULL) || (*p == '\0'))
  1898. break;
  1899. *p++='\0';
  1900. tag=p;
  1901. if ((*p != '\0') && (*p != '<'))
  1902. {
  1903. /*
  1904. Tag character content.
  1905. */
  1906. while ((*p != '\0') && (*p != '<'))
  1907. p++;
  1908. if (*p == '\0')
  1909. break;
  1910. ParseCharacterContent(root,tag,(size_t) (p-tag),'&');
  1911. }
  1912. else
  1913. if (*p == '\0')
  1914. break;
  1915. }
  1916. utf8=(char *) RelinquishMagickMemory(utf8);
  1917. if (root->node == (XMLTreeInfo *) NULL)
  1918. return(&root->root);
  1919. if (root->node->tag == (char *) NULL)
  1920. {
  1921. (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
  1922. "ParseError","root tag missing");
  1923. return(&root->root);
  1924. }
  1925. (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
  1926. "ParseError","unclosed tag: `%s'",root->node->tag);
  1927. return(&root->root);
  1928. }
  1929. /*
  1930. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1931. % %
  1932. % %
  1933. % %
  1934. % N e w X M L T r e e T a g %
  1935. % %
  1936. % %
  1937. % %
  1938. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1939. %
  1940. % NewXMLTreeTag() returns a new empty xml structure for the xml-tree tag.
  1941. %
  1942. % The format of the NewXMLTreeTag method is:
  1943. %
  1944. % XMLTreeInfo *NewXMLTreeTag(const char *tag)
  1945. %
  1946. % A description of each parameter follows:
  1947. %
  1948. % o tag: The tag.
  1949. %
  1950. */
  1951. MagickExport XMLTreeInfo *NewXMLTreeTag(const char *tag)
  1952. {
  1953. static char
  1954. *predefined_entities[NumberPredefinedEntities+1] =
  1955. {
  1956. "lt;", "&#60;", "gt;", "&#62;", "quot;", "&#34;",
  1957. "apos;", "&#39;", "amp;", "&#38;", (char *) NULL
  1958. };
  1959. XMLTreeRoot
  1960. *root;
  1961. root=(XMLTreeRoot *) AcquireMagickMemory(sizeof(*root));
  1962. if (root == (XMLTreeRoot *) NULL)
  1963. return((XMLTreeInfo *) NULL);
  1964. (void) ResetMagickMemory(root,0,sizeof(*root));
  1965. root->root.tag=(char *) NULL;
  1966. if (tag != (char *) NULL)
  1967. root->root.tag=ConstantString(tag);
  1968. root->node=(&root->root);
  1969. root->root.content=ConstantString("");
  1970. root->entities=(char **) AcquireMagickMemory(sizeof(predefined_entities));
  1971. if (root->entities == (char **) NULL)
  1972. return((XMLTreeInfo *) NULL);
  1973. (void) CopyMagickMemory(root->entities,predefined_entities,
  1974. sizeof(predefined_entities));
  1975. root->root.attributes=sentinel;
  1976. root->attributes=(char ***) sentinel;
  1977. root->processing_instructions=(char ***) sentinel;
  1978. root->debug=IsEventLogging();
  1979. root->signature=MagickSignature;
  1980. return(&root->root);
  1981. }
  1982. /*
  1983. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1984. % %
  1985. % %
  1986. % %
  1987. % P r u n e T a g F r o m X M L T r e e %
  1988. % %
  1989. % %
  1990. % %
  1991. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1992. %
  1993. % PruneTagFromXMLTree() prunes a tag from the xml-tree along with all its
  1994. % subtags.
  1995. %
  1996. % The format of the PruneTagFromXMLTree method is:
  1997. %
  1998. % XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info)
  1999. %
  2000. % A description of each parameter follows:
  2001. %
  2002. % o xml_info: The xml info.
  2003. %
  2004. */
  2005. MagickExport XMLTreeInfo *PruneTagFromXMLTree(XMLTreeInfo *xml_info)
  2006. {
  2007. XMLTreeInfo
  2008. *node;
  2009. assert(xml_info != (XMLTreeInfo *) NULL);
  2010. assert((xml_info->signature == MagickSignature) ||
  2011. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  2012. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  2013. if (xml_info->next != (XMLTreeInfo *) NULL)
  2014. xml_info->next->sibling=xml_info->sibling;
  2015. if (xml_info->parent != (XMLTreeInfo *) NULL)
  2016. {
  2017. node=xml_info->parent->child;
  2018. if (node == xml_info)
  2019. xml_info->parent->child=xml_info->ordered;
  2020. else
  2021. {
  2022. while (node->ordered != xml_info)
  2023. node=node->ordered;
  2024. node->ordered=node->ordered->ordered;
  2025. node=xml_info->parent->child;
  2026. if (strcmp(node->tag,xml_info->tag) != 0)
  2027. {
  2028. while (strcmp(node->sibling->tag,xml_info->tag) != 0)
  2029. node=node->sibling;
  2030. if (node->sibling != xml_info)
  2031. node=node->sibling;
  2032. else
  2033. node->sibling=(xml_info->next != (XMLTreeInfo *) NULL) ?
  2034. xml_info->next : node->sibling->sibling;
  2035. }
  2036. while ((node->next != (XMLTreeInfo *) NULL) &&
  2037. (node->next != xml_info))
  2038. node=node->next;
  2039. if (node->next != (XMLTreeInfo *) NULL)
  2040. node->next=node->next->next;
  2041. }
  2042. }
  2043. xml_info->ordered=(XMLTreeInfo *) NULL;
  2044. xml_info->sibling=(XMLTreeInfo *) NULL;
  2045. xml_info->next=(XMLTreeInfo *) NULL;
  2046. return(xml_info);
  2047. }
  2048. /*
  2049. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2050. % %
  2051. % %
  2052. % %
  2053. % S e t X M L T r e e A t t r i b u t e %
  2054. % %
  2055. % %
  2056. % %
  2057. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2058. %
  2059. % SetXMLTreeAttribute() sets the tag attributes or adds a new attribute if not
  2060. % found. A value of NULL removes the specified attribute.
  2061. %
  2062. % The format of the SetXMLTreeAttribute method is:
  2063. %
  2064. % XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info,const char *tag,
  2065. % const char *value)
  2066. %
  2067. % A description of each parameter follows:
  2068. %
  2069. % o xml_info: The xml info.
  2070. %
  2071. % o tag: The attribute tag.
  2072. %
  2073. % o value: The attribute value.
  2074. %
  2075. */
  2076. MagickExport XMLTreeInfo *SetXMLTreeAttribute(XMLTreeInfo *xml_info,
  2077. const char *tag,const char *value)
  2078. {
  2079. long
  2080. j;
  2081. register long
  2082. i;
  2083. size_t
  2084. length;
  2085. assert(xml_info != (XMLTreeInfo *) NULL);
  2086. assert((xml_info->signature == MagickSignature) ||
  2087. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  2088. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  2089. i=0;
  2090. while ((xml_info->attributes[i] != (char *) NULL) &&
  2091. (strcmp(xml_info->attributes[i],tag) != 0))
  2092. i+=2;
  2093. if (xml_info->attributes[i] == (char *) NULL)
  2094. {
  2095. /*
  2096. Add new attribute tag.
  2097. */
  2098. if (value == (const char *) NULL)
  2099. return(xml_info);
  2100. if (xml_info->attributes != sentinel)
  2101. xml_info->attributes=(char **) ResizeMagickMemory(
  2102. xml_info->attributes,(size_t) (i+4)*sizeof(*xml_info->attributes));
  2103. else
  2104. {
  2105. xml_info->attributes=(char **) AcquireMagickMemory(4*sizeof(
  2106. *xml_info->attributes));
  2107. if (xml_info->attributes != (char **) NULL)
  2108. xml_info->attributes[1]=ConstantString("");
  2109. }
  2110. if (xml_info->attributes == (char **) NULL)
  2111. ThrowMagickFatalException(ResourceLimitFatalError,
  2112. "UnableToAcquireString",tag);
  2113. xml_info->attributes[i]=ConstantString(tag);
  2114. xml_info->attributes[i+2]=(char *) NULL;
  2115. length=strlen(xml_info->attributes[i+1]);
  2116. }
  2117. /*
  2118. Add new value to an existing attribute.
  2119. */
  2120. for (j=i; xml_info->attributes[j] != (char *) NULL; j+=2);
  2121. if (xml_info->attributes[i+1] != (char *) NULL)
  2122. xml_info->attributes[i+1]=(char *) RelinquishMagickMemory(
  2123. xml_info->attributes[i+1]);
  2124. if (value != (const char *) NULL)
  2125. {
  2126. xml_info->attributes[i+1]=ConstantString(value);
  2127. return(xml_info);
  2128. }
  2129. if (xml_info->attributes[i] != (char *) NULL)
  2130. xml_info->attributes[i]=(char *) RelinquishMagickMemory(
  2131. xml_info->attributes[i]);
  2132. (void) CopyMagickMemory(xml_info->attributes+i,xml_info->attributes+i+2,
  2133. (size_t) (j-i+2)*sizeof(*xml_info->attributes));
  2134. xml_info->attributes=(char **) ResizeMagickMemory(xml_info->attributes,
  2135. (size_t) (j+2)*sizeof(*xml_info->attributes));
  2136. if (xml_info->attributes == (char **) NULL)
  2137. ThrowMagickFatalException(ResourceLimitFatalError,"UnableToAcquireString",
  2138. tag);
  2139. (void) CopyMagickMemory(xml_info->attributes[j+1]+(i/2),
  2140. xml_info->attributes[j+1]+(i/2)+1,(size_t) (j/2)-(i/2)*
  2141. sizeof(*xml_info->attributes));
  2142. return(xml_info);
  2143. }
  2144. /*
  2145. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2146. % %
  2147. % %
  2148. % %
  2149. % S e t X M L T r e e C o n t e n t %
  2150. % %
  2151. % %
  2152. % %
  2153. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2154. %
  2155. % SetXMLTreeContent() sets the character content for the given tag and
  2156. % returns the tag.
  2157. %
  2158. % The format of the SetXMLTreeContent method is:
  2159. %
  2160. % XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info,
  2161. % const char *content)
  2162. %
  2163. % A description of each parameter follows:
  2164. %
  2165. % o xml_info: The xml info.
  2166. %
  2167. % o content: The content.
  2168. %
  2169. */
  2170. MagickExport XMLTreeInfo *SetXMLTreeContent(XMLTreeInfo *xml_info,
  2171. const char *content)
  2172. {
  2173. assert(xml_info != (XMLTreeInfo *) NULL);
  2174. assert((xml_info->signature == MagickSignature) ||
  2175. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  2176. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  2177. if (xml_info->content != (char *) NULL)
  2178. xml_info->content=(char *) RelinquishMagickMemory(xml_info->content);
  2179. xml_info->content=(char *) ConstantString(content);
  2180. return(xml_info);
  2181. }
  2182. /*
  2183. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2184. % %
  2185. % %
  2186. % %
  2187. % X M L T r e e I n f o T o X M L %
  2188. % %
  2189. % %
  2190. % %
  2191. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2192. %
  2193. % XMLTreeInfoToXML() converts an xml-tree to an XML string.
  2194. %
  2195. % The format of the XMLTreeInfoToXML method is:
  2196. %
  2197. % XMLTreeInfo *XMLTreeInfoToXML(XMLTreeInfo *xml_info)
  2198. %
  2199. % A description of each parameter follows:
  2200. %
  2201. % o xml_info: The xml info.
  2202. %
  2203. */
  2204. static char *EncodePredefinedEntities(const char *source,ssize_t offset,
  2205. char **destination,size_t *length,size_t *max_length,
  2206. MagickBooleanType pedantic)
  2207. {
  2208. char
  2209. *canonical_content;
  2210. if (offset < 0)
  2211. canonical_content=CanonicalXMLContent(source,pedantic);
  2212. else
  2213. {
  2214. char
  2215. *content;
  2216. content=AcquireString(source);
  2217. content[offset]='\0';
  2218. canonical_content=CanonicalXMLContent(content,pedantic);
  2219. content=(char *) RelinquishMagickMemory(content);
  2220. }
  2221. if (canonical_content == (char *) NULL)
  2222. return(*destination);
  2223. if ((*length+strlen(canonical_content)+MaxTextExtent) > *max_length)
  2224. {
  2225. *max_length=(*length)+strlen(canonical_content)+MaxTextExtent;
  2226. *destination=(char *) ResizeMagickMemory(*destination,*max_length*
  2227. sizeof(**destination));
  2228. if (*destination == (char *) NULL)
  2229. return(*destination);
  2230. }
  2231. *length+=FormatMagickString(*destination+(*length),*max_length,"%s",
  2232. canonical_content);
  2233. canonical_content=(char *) RelinquishMagickMemory(canonical_content);
  2234. return(*destination);
  2235. }
  2236. static char *XMLTreeTagToXML(XMLTreeInfo *xml_info,char **source,size_t *length,
  2237. size_t *max_length,size_t start,char ***attributes)
  2238. {
  2239. char
  2240. *content;
  2241. const char
  2242. *attribute;
  2243. long
  2244. j;
  2245. register long
  2246. i;
  2247. size_t
  2248. offset;
  2249. content="";
  2250. if (xml_info->parent != (XMLTreeInfo *) NULL)
  2251. content=xml_info->parent->content;
  2252. offset=0;
  2253. *source=EncodePredefinedEntities(content+start,(ssize_t) (xml_info->offset-
  2254. start),source,length,max_length,MagickFalse);
  2255. if ((*length+strlen(xml_info->tag)+MaxTextExtent) > *max_length)
  2256. {
  2257. *max_length=(*length)+strlen(xml_info->tag)+MaxTextExtent;
  2258. *source=(char *) ResizeMagickMemory(*source,*max_length*sizeof(*source));
  2259. if (*source == (char *) NULL)
  2260. return(*source);
  2261. }
  2262. *length+=FormatMagickString(*source+(*length),*max_length,"<%s",
  2263. xml_info->tag);
  2264. for (i=0; xml_info->attributes[i]; i+=2)
  2265. {
  2266. attribute=GetXMLTreeAttribute(xml_info,xml_info->attributes[i]);
  2267. if (attribute != xml_info->attributes[i+1])
  2268. continue;
  2269. if ((*length+strlen(xml_info->attributes[i])+MaxTextExtent) > *max_length)
  2270. {
  2271. *max_length=(*length)+strlen(xml_info->attributes[i])+MaxTextExtent;
  2272. *source=(char *) ResizeMagickMemory(*source,*max_length*
  2273. sizeof(**source));
  2274. if (*source == (char *) NULL)
  2275. return((char *) NULL);
  2276. }
  2277. *length+=FormatMagickString(*source+(*length),*max_length," %s=\"",
  2278. xml_info->attributes[i]);
  2279. (void) EncodePredefinedEntities(xml_info->attributes[i+1],-1,source,length,
  2280. max_length,MagickTrue);
  2281. *length+=FormatMagickString(*source+(*length),*max_length,"\"");
  2282. }
  2283. i=0;
  2284. while ((attributes[i] != (char **) NULL) &&
  2285. (strcmp(attributes[i][0],xml_info->tag) != 0))
  2286. i++;
  2287. j=1;
  2288. while ((attributes[i] != (char **) NULL) &&
  2289. (attributes[i][j] != (char *) NULL))
  2290. {
  2291. if ((attributes[i][j+1] == (char *) NULL) ||
  2292. (GetXMLTreeAttribute(xml_info,attributes[i][j]) != attributes[i][j+1]))
  2293. {
  2294. j+=3;
  2295. continue;
  2296. }
  2297. if ((*length+strlen(attributes[i][j])+MaxTextExtent) > *max_length)
  2298. {
  2299. *max_length=(*length)+strlen(attributes[i][j])+MaxTextExtent;
  2300. *source=(char *) ResizeMagickMemory(*source,*max_length*
  2301. sizeof(**source));
  2302. if (*source == (char *) NULL)
  2303. return((char *) NULL);
  2304. }
  2305. *length+=FormatMagickString(*source+(*length),*max_length," %s=\"",
  2306. attributes[i][j]);
  2307. (void) EncodePredefinedEntities(attributes[i][j+1],-1,source,length,
  2308. max_length,MagickTrue);
  2309. *length+=FormatMagickString(*source+(*length),*max_length,"\"");
  2310. j+=3;
  2311. }
  2312. *length+=FormatMagickString(*source+(*length),*max_length,">");
  2313. if (xml_info->child != (XMLTreeInfo *) NULL)
  2314. *source=XMLTreeTagToXML(xml_info->child,source,length,max_length,0,
  2315. attributes);
  2316. else
  2317. *source=EncodePredefinedEntities(xml_info->content,-1,source,length,
  2318. max_length,MagickFalse);
  2319. if ((*length+strlen(xml_info->tag)+MaxTextExtent) > *max_length)
  2320. {
  2321. *max_length=(*length)+strlen(xml_info->tag)+MaxTextExtent;
  2322. *source=(char *) ResizeMagickMemory(*source,*max_length*sizeof(**source));
  2323. if (*source == (char *) NULL)
  2324. return((char *) NULL);
  2325. }
  2326. *length+=FormatMagickString(*source+(*length),*max_length,"</%s>",
  2327. xml_info->tag);
  2328. while ((content[offset] != '\0') && (offset < xml_info->offset))
  2329. offset++;
  2330. if (xml_info->ordered != (XMLTreeInfo *) NULL)
  2331. content=XMLTreeTagToXML(xml_info->ordered,source,length,max_length,offset,
  2332. attributes);
  2333. else
  2334. content=EncodePredefinedEntities(content+offset,-1,source,length,max_length,
  2335. MagickFalse);
  2336. return(content);
  2337. }
  2338. MagickExport char *XMLTreeInfoToXML(XMLTreeInfo *xml_info)
  2339. {
  2340. char
  2341. *xml;
  2342. long
  2343. j,
  2344. k;
  2345. register char
  2346. *p,
  2347. *q;
  2348. register long
  2349. i;
  2350. size_t
  2351. length,
  2352. max_length;
  2353. XMLTreeInfo
  2354. *ordered,
  2355. *parent;
  2356. XMLTreeRoot
  2357. *root;
  2358. assert(xml_info != (XMLTreeInfo *) NULL);
  2359. assert((xml_info->signature == MagickSignature) ||
  2360. (((XMLTreeRoot *) xml_info)->signature == MagickSignature));
  2361. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  2362. if (xml_info->tag == (char *) NULL)
  2363. return((char *) NULL);
  2364. xml=AcquireString((char *) NULL);
  2365. length=0;
  2366. max_length=MaxTextExtent;
  2367. root=(XMLTreeRoot *) xml_info;
  2368. while (root->root.parent != (XMLTreeInfo *) NULL)
  2369. root=(XMLTreeRoot *) root->root.parent;
  2370. parent=(XMLTreeInfo *) NULL;
  2371. if (xml_info != (XMLTreeInfo *) NULL)
  2372. parent=xml_info->parent;
  2373. if (parent == (XMLTreeInfo *) NULL)
  2374. for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
  2375. {
  2376. /*
  2377. Pre-root processing instructions.
  2378. */
  2379. for (k=2; root->processing_instructions[i][k-1]; k++);
  2380. p=root->processing_instructions[i][1];
  2381. for (j=1; p != (char *) NULL; j++)
  2382. {
  2383. if (root->processing_instructions[i][k][j-1] == '>')
  2384. {
  2385. p=root->processing_instructions[i][j];
  2386. continue;
  2387. }
  2388. q=root->processing_instructions[i][0];
  2389. if ((length+strlen(p)+strlen(q)+MaxTextExtent) > max_length)
  2390. {
  2391. max_length=length+strlen(p)+strlen(q)+MaxTextExtent;
  2392. xml=(char *) ResizeMagickMemory(xml,max_length);
  2393. if (xml == (char *) NULL)
  2394. return(xml);
  2395. }
  2396. length+=FormatMagickString(xml+length,max_length,"<?%s%s%s?>\n",q,
  2397. *p != '\0' ? " " : "",p);
  2398. p=root->processing_instructions[i][j];
  2399. }
  2400. }
  2401. ordered=(XMLTreeInfo *) NULL;
  2402. if (xml_info != (XMLTreeInfo *) NULL)
  2403. ordered=xml_info->ordered;
  2404. xml_info->parent=(XMLTreeInfo *) NULL;
  2405. xml_info->ordered=(XMLTreeInfo *) NULL;
  2406. xml=XMLTreeTagToXML(xml_info,&xml,&length,&max_length,0,root->attributes);
  2407. xml_info->parent=parent;
  2408. xml_info->ordered=ordered;
  2409. if (parent == (XMLTreeInfo *) NULL)
  2410. for (i=0; root->processing_instructions[i] != (char **) NULL; i++)
  2411. {
  2412. /*
  2413. Post-root processing instructions.
  2414. */
  2415. for (k=2; root->processing_instructions[i][k-1]; k++);
  2416. p=root->processing_instructions[i][1];
  2417. for (j=1; p != (char *) NULL; j++)
  2418. {
  2419. if (root->processing_instructions[i][k][j-1] == '<')
  2420. {
  2421. p=root->processing_instructions[i][j];
  2422. continue;
  2423. }
  2424. q=root->processing_instructions[i][0];
  2425. if ((length+strlen(p)+strlen(q)+MaxTextExtent) > max_length)
  2426. {
  2427. max_length=length+strlen(p)+strlen(q)+MaxTextExtent;
  2428. xml=(char *) ResizeMagickMemory(xml,max_length*sizeof(*xml));
  2429. if (xml == (char *) NULL)
  2430. return(xml);
  2431. }
  2432. length+=FormatMagickString(xml+length,max_length,"\n<?%s%s%s?>",q,
  2433. *p != '\0' ? " " : "",p);
  2434. p=root->processing_instructions[i][j];
  2435. }
  2436. }
  2437. return((char *) ResizeMagickMemory(xml,length+1));
  2438. }