entities.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022
  1. /*
  2. * entities.c : implementation for the XML entities handling
  3. *
  4. * See Copyright for the status of this software.
  5. *
  6. * daniel@veillard.com
  7. */
  8. #define IN_LIBXML
  9. #include "libxml.h"
  10. #include <string.h>
  11. #ifdef HAVE_STDLIB_H
  12. #include <stdlib.h>
  13. #endif
  14. #include <libxml/xmlmemory.h>
  15. #include <libxml/hash.h>
  16. #include <libxml/entities.h>
  17. #include <libxml/parser.h>
  18. #include <libxml/parserInternals.h>
  19. #include <libxml/xmlerror.h>
  20. #include <libxml/globals.h>
  21. #include <libxml/dict.h>
  22. /*
  23. * The XML predefined entities.
  24. */
  25. static xmlEntity xmlEntityLt = {
  26. NULL, XML_ENTITY_DECL, BAD_CAST "lt",
  27. NULL, NULL, NULL, NULL, NULL, NULL,
  28. BAD_CAST "<", BAD_CAST "<", 1,
  29. XML_INTERNAL_PREDEFINED_ENTITY,
  30. NULL, NULL, NULL, NULL, 0, 1
  31. };
  32. static xmlEntity xmlEntityGt = {
  33. NULL, XML_ENTITY_DECL, BAD_CAST "gt",
  34. NULL, NULL, NULL, NULL, NULL, NULL,
  35. BAD_CAST ">", BAD_CAST ">", 1,
  36. XML_INTERNAL_PREDEFINED_ENTITY,
  37. NULL, NULL, NULL, NULL, 0, 1
  38. };
  39. static xmlEntity xmlEntityAmp = {
  40. NULL, XML_ENTITY_DECL, BAD_CAST "amp",
  41. NULL, NULL, NULL, NULL, NULL, NULL,
  42. BAD_CAST "&", BAD_CAST "&", 1,
  43. XML_INTERNAL_PREDEFINED_ENTITY,
  44. NULL, NULL, NULL, NULL, 0, 1
  45. };
  46. static xmlEntity xmlEntityQuot = {
  47. NULL, XML_ENTITY_DECL, BAD_CAST "quot",
  48. NULL, NULL, NULL, NULL, NULL, NULL,
  49. BAD_CAST "\"", BAD_CAST "\"", 1,
  50. XML_INTERNAL_PREDEFINED_ENTITY,
  51. NULL, NULL, NULL, NULL, 0, 1
  52. };
  53. static xmlEntity xmlEntityApos = {
  54. NULL, XML_ENTITY_DECL, BAD_CAST "apos",
  55. NULL, NULL, NULL, NULL, NULL, NULL,
  56. BAD_CAST "'", BAD_CAST "'", 1,
  57. XML_INTERNAL_PREDEFINED_ENTITY,
  58. NULL, NULL, NULL, NULL, 0, 1
  59. };
  60. /**
  61. * xmlEntitiesErrMemory:
  62. * @extra: extra informations
  63. *
  64. * Handle an out of memory condition
  65. */
  66. static void
  67. xmlEntitiesErrMemory(const char *extra)
  68. {
  69. __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra);
  70. }
  71. /**
  72. * xmlEntitiesErr:
  73. * @code: the error code
  74. * @msg: the message
  75. *
  76. * Handle an out of memory condition
  77. */
  78. static void
  79. xmlEntitiesErr(xmlParserErrors code, const char *msg)
  80. {
  81. __xmlSimpleError(XML_FROM_TREE, code, NULL, msg, NULL);
  82. }
  83. /*
  84. * xmlFreeEntity : clean-up an entity record.
  85. */
  86. static void
  87. xmlFreeEntity(xmlEntityPtr entity)
  88. {
  89. xmlDictPtr dict = NULL;
  90. if (entity == NULL)
  91. return;
  92. if (entity->doc != NULL)
  93. dict = entity->doc->dict;
  94. if ((entity->children) && (entity->owner == 1) &&
  95. (entity == (xmlEntityPtr) entity->children->parent))
  96. xmlFreeNodeList(entity->children);
  97. if (dict != NULL) {
  98. if ((entity->name != NULL) && (!xmlDictOwns(dict, entity->name)))
  99. xmlFree((char *) entity->name);
  100. if ((entity->ExternalID != NULL) &&
  101. (!xmlDictOwns(dict, entity->ExternalID)))
  102. xmlFree((char *) entity->ExternalID);
  103. if ((entity->SystemID != NULL) &&
  104. (!xmlDictOwns(dict, entity->SystemID)))
  105. xmlFree((char *) entity->SystemID);
  106. if ((entity->URI != NULL) && (!xmlDictOwns(dict, entity->URI)))
  107. xmlFree((char *) entity->URI);
  108. if ((entity->content != NULL)
  109. && (!xmlDictOwns(dict, entity->content)))
  110. xmlFree((char *) entity->content);
  111. if ((entity->orig != NULL) && (!xmlDictOwns(dict, entity->orig)))
  112. xmlFree((char *) entity->orig);
  113. } else {
  114. if (entity->name != NULL)
  115. xmlFree((char *) entity->name);
  116. if (entity->ExternalID != NULL)
  117. xmlFree((char *) entity->ExternalID);
  118. if (entity->SystemID != NULL)
  119. xmlFree((char *) entity->SystemID);
  120. if (entity->URI != NULL)
  121. xmlFree((char *) entity->URI);
  122. if (entity->content != NULL)
  123. xmlFree((char *) entity->content);
  124. if (entity->orig != NULL)
  125. xmlFree((char *) entity->orig);
  126. }
  127. xmlFree(entity);
  128. }
  129. /*
  130. * xmlCreateEntity:
  131. *
  132. * internal routine doing the entity node strutures allocations
  133. */
  134. static xmlEntityPtr
  135. xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type,
  136. const xmlChar *ExternalID, const xmlChar *SystemID,
  137. const xmlChar *content) {
  138. xmlEntityPtr ret;
  139. ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
  140. if (ret == NULL) {
  141. xmlEntitiesErrMemory("xmlCreateEntity: malloc failed");
  142. return(NULL);
  143. }
  144. memset(ret, 0, sizeof(xmlEntity));
  145. ret->type = XML_ENTITY_DECL;
  146. ret->checked = 0;
  147. /*
  148. * fill the structure.
  149. */
  150. ret->etype = (xmlEntityType) type;
  151. if (dict == NULL) {
  152. ret->name = xmlStrdup(name);
  153. if (ExternalID != NULL)
  154. ret->ExternalID = xmlStrdup(ExternalID);
  155. if (SystemID != NULL)
  156. ret->SystemID = xmlStrdup(SystemID);
  157. } else {
  158. ret->name = xmlDictLookup(dict, name, -1);
  159. if (ExternalID != NULL)
  160. ret->ExternalID = xmlDictLookup(dict, ExternalID, -1);
  161. if (SystemID != NULL)
  162. ret->SystemID = xmlDictLookup(dict, SystemID, -1);
  163. }
  164. if (content != NULL) {
  165. ret->length = xmlStrlen(content);
  166. if ((dict != NULL) && (ret->length < 5))
  167. ret->content = (xmlChar *)
  168. xmlDictLookup(dict, content, ret->length);
  169. else
  170. ret->content = xmlStrndup(content, ret->length);
  171. } else {
  172. ret->length = 0;
  173. ret->content = NULL;
  174. }
  175. ret->URI = NULL; /* to be computed by the layer knowing
  176. the defining entity */
  177. ret->orig = NULL;
  178. ret->owner = 0;
  179. return(ret);
  180. }
  181. /*
  182. * xmlAddEntity : register a new entity for an entities table.
  183. */
  184. static xmlEntityPtr
  185. xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type,
  186. const xmlChar *ExternalID, const xmlChar *SystemID,
  187. const xmlChar *content) {
  188. xmlDictPtr dict = NULL;
  189. xmlEntitiesTablePtr table = NULL;
  190. xmlEntityPtr ret;
  191. if (name == NULL)
  192. return(NULL);
  193. if (dtd == NULL)
  194. return(NULL);
  195. if (dtd->doc != NULL)
  196. dict = dtd->doc->dict;
  197. switch (type) {
  198. case XML_INTERNAL_GENERAL_ENTITY:
  199. case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
  200. case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
  201. if (dtd->entities == NULL)
  202. dtd->entities = xmlHashCreateDict(0, dict);
  203. table = dtd->entities;
  204. break;
  205. case XML_INTERNAL_PARAMETER_ENTITY:
  206. case XML_EXTERNAL_PARAMETER_ENTITY:
  207. if (dtd->pentities == NULL)
  208. dtd->pentities = xmlHashCreateDict(0, dict);
  209. table = dtd->pentities;
  210. break;
  211. case XML_INTERNAL_PREDEFINED_ENTITY:
  212. return(NULL);
  213. }
  214. if (table == NULL)
  215. return(NULL);
  216. ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content);
  217. if (ret == NULL)
  218. return(NULL);
  219. ret->doc = dtd->doc;
  220. if (xmlHashAddEntry(table, name, ret)) {
  221. /*
  222. * entity was already defined at another level.
  223. */
  224. xmlFreeEntity(ret);
  225. return(NULL);
  226. }
  227. return(ret);
  228. }
  229. /**
  230. * xmlGetPredefinedEntity:
  231. * @name: the entity name
  232. *
  233. * Check whether this name is an predefined entity.
  234. *
  235. * Returns NULL if not, otherwise the entity
  236. */
  237. xmlEntityPtr
  238. xmlGetPredefinedEntity(const xmlChar *name) {
  239. if (name == NULL) return(NULL);
  240. switch (name[0]) {
  241. case 'l':
  242. if (xmlStrEqual(name, BAD_CAST "lt"))
  243. return(&xmlEntityLt);
  244. break;
  245. case 'g':
  246. if (xmlStrEqual(name, BAD_CAST "gt"))
  247. return(&xmlEntityGt);
  248. break;
  249. case 'a':
  250. if (xmlStrEqual(name, BAD_CAST "amp"))
  251. return(&xmlEntityAmp);
  252. if (xmlStrEqual(name, BAD_CAST "apos"))
  253. return(&xmlEntityApos);
  254. break;
  255. case 'q':
  256. if (xmlStrEqual(name, BAD_CAST "quot"))
  257. return(&xmlEntityQuot);
  258. break;
  259. default:
  260. break;
  261. }
  262. return(NULL);
  263. }
  264. /**
  265. * xmlAddDtdEntity:
  266. * @doc: the document
  267. * @name: the entity name
  268. * @type: the entity type XML_xxx_yyy_ENTITY
  269. * @ExternalID: the entity external ID if available
  270. * @SystemID: the entity system ID if available
  271. * @content: the entity content
  272. *
  273. * Register a new entity for this document DTD external subset.
  274. *
  275. * Returns a pointer to the entity or NULL in case of error
  276. */
  277. xmlEntityPtr
  278. xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
  279. const xmlChar *ExternalID, const xmlChar *SystemID,
  280. const xmlChar *content) {
  281. xmlEntityPtr ret;
  282. xmlDtdPtr dtd;
  283. if (doc == NULL) {
  284. xmlEntitiesErr(XML_DTD_NO_DOC,
  285. "xmlAddDtdEntity: document is NULL");
  286. return(NULL);
  287. }
  288. if (doc->extSubset == NULL) {
  289. xmlEntitiesErr(XML_DTD_NO_DTD,
  290. "xmlAddDtdEntity: document without external subset");
  291. return(NULL);
  292. }
  293. dtd = doc->extSubset;
  294. ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
  295. if (ret == NULL) return(NULL);
  296. /*
  297. * Link it to the DTD
  298. */
  299. ret->parent = dtd;
  300. ret->doc = dtd->doc;
  301. if (dtd->last == NULL) {
  302. dtd->children = dtd->last = (xmlNodePtr) ret;
  303. } else {
  304. dtd->last->next = (xmlNodePtr) ret;
  305. ret->prev = dtd->last;
  306. dtd->last = (xmlNodePtr) ret;
  307. }
  308. return(ret);
  309. }
  310. /**
  311. * xmlAddDocEntity:
  312. * @doc: the document
  313. * @name: the entity name
  314. * @type: the entity type XML_xxx_yyy_ENTITY
  315. * @ExternalID: the entity external ID if available
  316. * @SystemID: the entity system ID if available
  317. * @content: the entity content
  318. *
  319. * Register a new entity for this document.
  320. *
  321. * Returns a pointer to the entity or NULL in case of error
  322. */
  323. xmlEntityPtr
  324. xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
  325. const xmlChar *ExternalID, const xmlChar *SystemID,
  326. const xmlChar *content) {
  327. xmlEntityPtr ret;
  328. xmlDtdPtr dtd;
  329. if (doc == NULL) {
  330. xmlEntitiesErr(XML_DTD_NO_DOC,
  331. "xmlAddDocEntity: document is NULL");
  332. return(NULL);
  333. }
  334. if (doc->intSubset == NULL) {
  335. xmlEntitiesErr(XML_DTD_NO_DTD,
  336. "xmlAddDocEntity: document without internal subset");
  337. return(NULL);
  338. }
  339. dtd = doc->intSubset;
  340. ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
  341. if (ret == NULL) return(NULL);
  342. /*
  343. * Link it to the DTD
  344. */
  345. ret->parent = dtd;
  346. ret->doc = dtd->doc;
  347. if (dtd->last == NULL) {
  348. dtd->children = dtd->last = (xmlNodePtr) ret;
  349. } else {
  350. dtd->last->next = (xmlNodePtr) ret;
  351. ret->prev = dtd->last;
  352. dtd->last = (xmlNodePtr) ret;
  353. }
  354. return(ret);
  355. }
  356. /**
  357. * xmlNewEntity:
  358. * @doc: the document
  359. * @name: the entity name
  360. * @type: the entity type XML_xxx_yyy_ENTITY
  361. * @ExternalID: the entity external ID if available
  362. * @SystemID: the entity system ID if available
  363. * @content: the entity content
  364. *
  365. * Create a new entity, this differs from xmlAddDocEntity() that if
  366. * the document is NULL or has no internal subset defined, then an
  367. * unlinked entity structure will be returned, it is then the responsability
  368. * of the caller to link it to the document later or free it when not needed
  369. * anymore.
  370. *
  371. * Returns a pointer to the entity or NULL in case of error
  372. */
  373. xmlEntityPtr
  374. xmlNewEntity(xmlDocPtr doc, const xmlChar *name, int type,
  375. const xmlChar *ExternalID, const xmlChar *SystemID,
  376. const xmlChar *content) {
  377. xmlEntityPtr ret;
  378. xmlDictPtr dict;
  379. if ((doc != NULL) && (doc->intSubset != NULL)) {
  380. return(xmlAddDocEntity(doc, name, type, ExternalID, SystemID, content));
  381. }
  382. if (doc != NULL)
  383. dict = doc->dict;
  384. else
  385. dict = NULL;
  386. ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content);
  387. if (ret == NULL)
  388. return(NULL);
  389. ret->doc = doc;
  390. return(ret);
  391. }
  392. /**
  393. * xmlGetEntityFromTable:
  394. * @table: an entity table
  395. * @name: the entity name
  396. * @parameter: look for parameter entities
  397. *
  398. * Do an entity lookup in the table.
  399. * returns the corresponding parameter entity, if found.
  400. *
  401. * Returns A pointer to the entity structure or NULL if not found.
  402. */
  403. static xmlEntityPtr
  404. xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) {
  405. return((xmlEntityPtr) xmlHashLookup(table, name));
  406. }
  407. /**
  408. * xmlGetParameterEntity:
  409. * @doc: the document referencing the entity
  410. * @name: the entity name
  411. *
  412. * Do an entity lookup in the internal and external subsets and
  413. * returns the corresponding parameter entity, if found.
  414. *
  415. * Returns A pointer to the entity structure or NULL if not found.
  416. */
  417. xmlEntityPtr
  418. xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
  419. xmlEntitiesTablePtr table;
  420. xmlEntityPtr ret;
  421. if (doc == NULL)
  422. return(NULL);
  423. if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) {
  424. table = (xmlEntitiesTablePtr) doc->intSubset->pentities;
  425. ret = xmlGetEntityFromTable(table, name);
  426. if (ret != NULL)
  427. return(ret);
  428. }
  429. if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) {
  430. table = (xmlEntitiesTablePtr) doc->extSubset->pentities;
  431. return(xmlGetEntityFromTable(table, name));
  432. }
  433. return(NULL);
  434. }
  435. /**
  436. * xmlGetDtdEntity:
  437. * @doc: the document referencing the entity
  438. * @name: the entity name
  439. *
  440. * Do an entity lookup in the DTD entity hash table and
  441. * returns the corresponding entity, if found.
  442. * Note: the first argument is the document node, not the DTD node.
  443. *
  444. * Returns A pointer to the entity structure or NULL if not found.
  445. */
  446. xmlEntityPtr
  447. xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
  448. xmlEntitiesTablePtr table;
  449. if (doc == NULL)
  450. return(NULL);
  451. if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
  452. table = (xmlEntitiesTablePtr) doc->extSubset->entities;
  453. return(xmlGetEntityFromTable(table, name));
  454. }
  455. return(NULL);
  456. }
  457. /**
  458. * xmlGetDocEntity:
  459. * @doc: the document referencing the entity
  460. * @name: the entity name
  461. *
  462. * Do an entity lookup in the document entity hash table and
  463. * returns the corresponding entity, otherwise a lookup is done
  464. * in the predefined entities too.
  465. *
  466. * Returns A pointer to the entity structure or NULL if not found.
  467. */
  468. xmlEntityPtr
  469. xmlGetDocEntity(xmlDocPtr doc, const xmlChar *name) {
  470. xmlEntityPtr cur;
  471. xmlEntitiesTablePtr table;
  472. if (doc != NULL) {
  473. if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
  474. table = (xmlEntitiesTablePtr) doc->intSubset->entities;
  475. cur = xmlGetEntityFromTable(table, name);
  476. if (cur != NULL)
  477. return(cur);
  478. }
  479. if (doc->standalone != 1) {
  480. if ((doc->extSubset != NULL) &&
  481. (doc->extSubset->entities != NULL)) {
  482. table = (xmlEntitiesTablePtr) doc->extSubset->entities;
  483. cur = xmlGetEntityFromTable(table, name);
  484. if (cur != NULL)
  485. return(cur);
  486. }
  487. }
  488. }
  489. return(xmlGetPredefinedEntity(name));
  490. }
  491. /*
  492. * Macro used to grow the current buffer.
  493. */
  494. #define growBufferReentrant() { \
  495. buffer_size *= 2; \
  496. buffer = (xmlChar *) \
  497. xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \
  498. if (buffer == NULL) { \
  499. xmlEntitiesErrMemory("xmlEncodeEntitiesReentrant: realloc failed");\
  500. return(NULL); \
  501. } \
  502. }
  503. /**
  504. * xmlEncodeEntitiesReentrant:
  505. * @doc: the document containing the string
  506. * @input: A string to convert to XML.
  507. *
  508. * Do a global encoding of a string, replacing the predefined entities
  509. * and non ASCII values with their entities and CharRef counterparts.
  510. * Contrary to xmlEncodeEntities, this routine is reentrant, and result
  511. * must be deallocated.
  512. *
  513. * Returns A newly allocated string with the substitution done.
  514. */
  515. xmlChar *
  516. xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
  517. const xmlChar *cur = input;
  518. xmlChar *buffer = NULL;
  519. xmlChar *out = NULL;
  520. int buffer_size = 0;
  521. int html = 0;
  522. if (input == NULL) return(NULL);
  523. if (doc != NULL)
  524. html = (doc->type == XML_HTML_DOCUMENT_NODE);
  525. /*
  526. * allocate an translation buffer.
  527. */
  528. buffer_size = 1000;
  529. buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
  530. if (buffer == NULL) {
  531. xmlEntitiesErrMemory("xmlEncodeEntitiesReentrant: malloc failed");
  532. return(NULL);
  533. }
  534. out = buffer;
  535. while (*cur != '\0') {
  536. if (out - buffer > buffer_size - 100) {
  537. int indx = out - buffer;
  538. growBufferReentrant();
  539. out = &buffer[indx];
  540. }
  541. /*
  542. * By default one have to encode at least '<', '>', '"' and '&' !
  543. */
  544. if (*cur == '<') {
  545. *out++ = '&';
  546. *out++ = 'l';
  547. *out++ = 't';
  548. *out++ = ';';
  549. } else if (*cur == '>') {
  550. *out++ = '&';
  551. *out++ = 'g';
  552. *out++ = 't';
  553. *out++ = ';';
  554. } else if (*cur == '&') {
  555. *out++ = '&';
  556. *out++ = 'a';
  557. *out++ = 'm';
  558. *out++ = 'p';
  559. *out++ = ';';
  560. } else if (((*cur >= 0x20) && (*cur < 0x80)) ||
  561. (*cur == '\n') || (*cur == '\t') || ((html) && (*cur == '\r'))) {
  562. /*
  563. * default case, just copy !
  564. */
  565. *out++ = *cur;
  566. } else if (*cur >= 0x80) {
  567. if (((doc != NULL) && (doc->encoding != NULL)) || (html)) {
  568. /*
  569. * Bjørn Reese <br@sseusa.com> provided the patch
  570. xmlChar xc;
  571. xc = (*cur & 0x3F) << 6;
  572. if (cur[1] != 0) {
  573. xc += *(++cur) & 0x3F;
  574. *out++ = xc;
  575. } else
  576. */
  577. *out++ = *cur;
  578. } else {
  579. /*
  580. * We assume we have UTF-8 input.
  581. */
  582. char buf[11], *ptr;
  583. int val = 0, l = 1;
  584. if (*cur < 0xC0) {
  585. xmlEntitiesErr(XML_CHECK_NOT_UTF8,
  586. "xmlEncodeEntitiesReentrant : input not UTF-8");
  587. if (doc != NULL)
  588. doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
  589. snprintf(buf, sizeof(buf), "&#%d;", *cur);
  590. buf[sizeof(buf) - 1] = 0;
  591. ptr = buf;
  592. while (*ptr != 0) *out++ = *ptr++;
  593. cur++;
  594. continue;
  595. } else if (*cur < 0xE0) {
  596. val = (cur[0]) & 0x1F;
  597. val <<= 6;
  598. val |= (cur[1]) & 0x3F;
  599. l = 2;
  600. } else if (*cur < 0xF0) {
  601. val = (cur[0]) & 0x0F;
  602. val <<= 6;
  603. val |= (cur[1]) & 0x3F;
  604. val <<= 6;
  605. val |= (cur[2]) & 0x3F;
  606. l = 3;
  607. } else if (*cur < 0xF8) {
  608. val = (cur[0]) & 0x07;
  609. val <<= 6;
  610. val |= (cur[1]) & 0x3F;
  611. val <<= 6;
  612. val |= (cur[2]) & 0x3F;
  613. val <<= 6;
  614. val |= (cur[3]) & 0x3F;
  615. l = 4;
  616. }
  617. if ((l == 1) || (!IS_CHAR(val))) {
  618. xmlEntitiesErr(XML_ERR_INVALID_CHAR,
  619. "xmlEncodeEntitiesReentrant : char out of range\n");
  620. if (doc != NULL)
  621. doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
  622. snprintf(buf, sizeof(buf), "&#%d;", *cur);
  623. buf[sizeof(buf) - 1] = 0;
  624. ptr = buf;
  625. while (*ptr != 0) *out++ = *ptr++;
  626. cur++;
  627. continue;
  628. }
  629. /*
  630. * We could do multiple things here. Just save as a char ref
  631. */
  632. snprintf(buf, sizeof(buf), "&#x%X;", val);
  633. buf[sizeof(buf) - 1] = 0;
  634. ptr = buf;
  635. while (*ptr != 0) *out++ = *ptr++;
  636. cur += l;
  637. continue;
  638. }
  639. } else if (IS_BYTE_CHAR(*cur)) {
  640. char buf[11], *ptr;
  641. snprintf(buf, sizeof(buf), "&#%d;", *cur);
  642. buf[sizeof(buf) - 1] = 0;
  643. ptr = buf;
  644. while (*ptr != 0) *out++ = *ptr++;
  645. }
  646. cur++;
  647. }
  648. *out = 0;
  649. return(buffer);
  650. }
  651. /**
  652. * xmlEncodeSpecialChars:
  653. * @doc: the document containing the string
  654. * @input: A string to convert to XML.
  655. *
  656. * Do a global encoding of a string, replacing the predefined entities
  657. * this routine is reentrant, and result must be deallocated.
  658. *
  659. * Returns A newly allocated string with the substitution done.
  660. */
  661. xmlChar *
  662. xmlEncodeSpecialChars(xmlDocPtr doc ATTRIBUTE_UNUSED, const xmlChar *input) {
  663. const xmlChar *cur = input;
  664. xmlChar *buffer = NULL;
  665. xmlChar *out = NULL;
  666. int buffer_size = 0;
  667. if (input == NULL) return(NULL);
  668. /*
  669. * allocate an translation buffer.
  670. */
  671. buffer_size = 1000;
  672. buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
  673. if (buffer == NULL) {
  674. xmlEntitiesErrMemory("xmlEncodeSpecialChars: malloc failed");
  675. return(NULL);
  676. }
  677. out = buffer;
  678. while (*cur != '\0') {
  679. if (out - buffer > buffer_size - 10) {
  680. int indx = out - buffer;
  681. growBufferReentrant();
  682. out = &buffer[indx];
  683. }
  684. /*
  685. * By default one have to encode at least '<', '>', '"' and '&' !
  686. */
  687. if (*cur == '<') {
  688. *out++ = '&';
  689. *out++ = 'l';
  690. *out++ = 't';
  691. *out++ = ';';
  692. } else if (*cur == '>') {
  693. *out++ = '&';
  694. *out++ = 'g';
  695. *out++ = 't';
  696. *out++ = ';';
  697. } else if (*cur == '&') {
  698. *out++ = '&';
  699. *out++ = 'a';
  700. *out++ = 'm';
  701. *out++ = 'p';
  702. *out++ = ';';
  703. } else if (*cur == '"') {
  704. *out++ = '&';
  705. *out++ = 'q';
  706. *out++ = 'u';
  707. *out++ = 'o';
  708. *out++ = 't';
  709. *out++ = ';';
  710. } else if (*cur == '\r') {
  711. *out++ = '&';
  712. *out++ = '#';
  713. *out++ = '1';
  714. *out++ = '3';
  715. *out++ = ';';
  716. } else {
  717. /*
  718. * Works because on UTF-8, all extended sequences cannot
  719. * result in bytes in the ASCII range.
  720. */
  721. *out++ = *cur;
  722. }
  723. cur++;
  724. }
  725. *out = 0;
  726. return(buffer);
  727. }
  728. /**
  729. * xmlCreateEntitiesTable:
  730. *
  731. * create and initialize an empty entities hash table.
  732. * This really doesn't make sense and should be deprecated
  733. *
  734. * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
  735. */
  736. xmlEntitiesTablePtr
  737. xmlCreateEntitiesTable(void) {
  738. return((xmlEntitiesTablePtr) xmlHashCreate(0));
  739. }
  740. /**
  741. * xmlFreeEntityWrapper:
  742. * @entity: An entity
  743. * @name: its name
  744. *
  745. * Deallocate the memory used by an entities in the hash table.
  746. */
  747. static void
  748. xmlFreeEntityWrapper(xmlEntityPtr entity,
  749. const xmlChar *name ATTRIBUTE_UNUSED) {
  750. if (entity != NULL)
  751. xmlFreeEntity(entity);
  752. }
  753. /**
  754. * xmlFreeEntitiesTable:
  755. * @table: An entity table
  756. *
  757. * Deallocate the memory used by an entities hash table.
  758. */
  759. void
  760. xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
  761. xmlHashFree(table, (xmlHashDeallocator) xmlFreeEntityWrapper);
  762. }
  763. #ifdef LIBXML_TREE_ENABLED
  764. /**
  765. * xmlCopyEntity:
  766. * @ent: An entity
  767. *
  768. * Build a copy of an entity
  769. *
  770. * Returns the new xmlEntitiesPtr or NULL in case of error.
  771. */
  772. static xmlEntityPtr
  773. xmlCopyEntity(xmlEntityPtr ent) {
  774. xmlEntityPtr cur;
  775. cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
  776. if (cur == NULL) {
  777. xmlEntitiesErrMemory("xmlCopyEntity:: malloc failed");
  778. return(NULL);
  779. }
  780. memset(cur, 0, sizeof(xmlEntity));
  781. cur->type = XML_ENTITY_DECL;
  782. cur->etype = ent->etype;
  783. if (ent->name != NULL)
  784. cur->name = xmlStrdup(ent->name);
  785. if (ent->ExternalID != NULL)
  786. cur->ExternalID = xmlStrdup(ent->ExternalID);
  787. if (ent->SystemID != NULL)
  788. cur->SystemID = xmlStrdup(ent->SystemID);
  789. if (ent->content != NULL)
  790. cur->content = xmlStrdup(ent->content);
  791. if (ent->orig != NULL)
  792. cur->orig = xmlStrdup(ent->orig);
  793. if (ent->URI != NULL)
  794. cur->URI = xmlStrdup(ent->URI);
  795. return(cur);
  796. }
  797. /**
  798. * xmlCopyEntitiesTable:
  799. * @table: An entity table
  800. *
  801. * Build a copy of an entity table.
  802. *
  803. * Returns the new xmlEntitiesTablePtr or NULL in case of error.
  804. */
  805. xmlEntitiesTablePtr
  806. xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
  807. return(xmlHashCopy(table, (xmlHashCopier) xmlCopyEntity));
  808. }
  809. #endif /* LIBXML_TREE_ENABLED */
  810. #ifdef LIBXML_OUTPUT_ENABLED
  811. /**
  812. * xmlDumpEntityContent:
  813. * @buf: An XML buffer.
  814. * @content: The entity content.
  815. *
  816. * This will dump the quoted string value, taking care of the special
  817. * treatment required by %
  818. */
  819. static void
  820. xmlDumpEntityContent(xmlBufferPtr buf, const xmlChar *content) {
  821. if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return;
  822. if (xmlStrchr(content, '%')) {
  823. const xmlChar * base, *cur;
  824. xmlBufferCCat(buf, "\"");
  825. base = cur = content;
  826. while (*cur != 0) {
  827. if (*cur == '"') {
  828. if (base != cur)
  829. xmlBufferAdd(buf, base, cur - base);
  830. xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
  831. cur++;
  832. base = cur;
  833. } else if (*cur == '%') {
  834. if (base != cur)
  835. xmlBufferAdd(buf, base, cur - base);
  836. xmlBufferAdd(buf, BAD_CAST "&#x25;", 6);
  837. cur++;
  838. base = cur;
  839. } else {
  840. cur++;
  841. }
  842. }
  843. if (base != cur)
  844. xmlBufferAdd(buf, base, cur - base);
  845. xmlBufferCCat(buf, "\"");
  846. } else {
  847. xmlBufferWriteQuotedString(buf, content);
  848. }
  849. }
  850. /**
  851. * xmlDumpEntityDecl:
  852. * @buf: An XML buffer.
  853. * @ent: An entity table
  854. *
  855. * This will dump the content of the entity table as an XML DTD definition
  856. */
  857. void
  858. xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) {
  859. if ((buf == NULL) || (ent == NULL)) return;
  860. switch (ent->etype) {
  861. case XML_INTERNAL_GENERAL_ENTITY:
  862. xmlBufferWriteChar(buf, "<!ENTITY ");
  863. xmlBufferWriteCHAR(buf, ent->name);
  864. xmlBufferWriteChar(buf, " ");
  865. if (ent->orig != NULL)
  866. xmlBufferWriteQuotedString(buf, ent->orig);
  867. else
  868. xmlDumpEntityContent(buf, ent->content);
  869. xmlBufferWriteChar(buf, ">\n");
  870. break;
  871. case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
  872. xmlBufferWriteChar(buf, "<!ENTITY ");
  873. xmlBufferWriteCHAR(buf, ent->name);
  874. if (ent->ExternalID != NULL) {
  875. xmlBufferWriteChar(buf, " PUBLIC ");
  876. xmlBufferWriteQuotedString(buf, ent->ExternalID);
  877. xmlBufferWriteChar(buf, " ");
  878. xmlBufferWriteQuotedString(buf, ent->SystemID);
  879. } else {
  880. xmlBufferWriteChar(buf, " SYSTEM ");
  881. xmlBufferWriteQuotedString(buf, ent->SystemID);
  882. }
  883. xmlBufferWriteChar(buf, ">\n");
  884. break;
  885. case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
  886. xmlBufferWriteChar(buf, "<!ENTITY ");
  887. xmlBufferWriteCHAR(buf, ent->name);
  888. if (ent->ExternalID != NULL) {
  889. xmlBufferWriteChar(buf, " PUBLIC ");
  890. xmlBufferWriteQuotedString(buf, ent->ExternalID);
  891. xmlBufferWriteChar(buf, " ");
  892. xmlBufferWriteQuotedString(buf, ent->SystemID);
  893. } else {
  894. xmlBufferWriteChar(buf, " SYSTEM ");
  895. xmlBufferWriteQuotedString(buf, ent->SystemID);
  896. }
  897. if (ent->content != NULL) { /* Should be true ! */
  898. xmlBufferWriteChar(buf, " NDATA ");
  899. if (ent->orig != NULL)
  900. xmlBufferWriteCHAR(buf, ent->orig);
  901. else
  902. xmlBufferWriteCHAR(buf, ent->content);
  903. }
  904. xmlBufferWriteChar(buf, ">\n");
  905. break;
  906. case XML_INTERNAL_PARAMETER_ENTITY:
  907. xmlBufferWriteChar(buf, "<!ENTITY % ");
  908. xmlBufferWriteCHAR(buf, ent->name);
  909. xmlBufferWriteChar(buf, " ");
  910. if (ent->orig == NULL)
  911. xmlDumpEntityContent(buf, ent->content);
  912. else
  913. xmlBufferWriteQuotedString(buf, ent->orig);
  914. xmlBufferWriteChar(buf, ">\n");
  915. break;
  916. case XML_EXTERNAL_PARAMETER_ENTITY:
  917. xmlBufferWriteChar(buf, "<!ENTITY % ");
  918. xmlBufferWriteCHAR(buf, ent->name);
  919. if (ent->ExternalID != NULL) {
  920. xmlBufferWriteChar(buf, " PUBLIC ");
  921. xmlBufferWriteQuotedString(buf, ent->ExternalID);
  922. xmlBufferWriteChar(buf, " ");
  923. xmlBufferWriteQuotedString(buf, ent->SystemID);
  924. } else {
  925. xmlBufferWriteChar(buf, " SYSTEM ");
  926. xmlBufferWriteQuotedString(buf, ent->SystemID);
  927. }
  928. xmlBufferWriteChar(buf, ">\n");
  929. break;
  930. default:
  931. xmlEntitiesErr(XML_DTD_UNKNOWN_ENTITY,
  932. "xmlDumpEntitiesDecl: internal: unknown type entity type");
  933. }
  934. }
  935. /**
  936. * xmlDumpEntityDeclScan:
  937. * @ent: An entity table
  938. * @buf: An XML buffer.
  939. *
  940. * When using the hash table scan function, arguments need to be reversed
  941. */
  942. static void
  943. xmlDumpEntityDeclScan(xmlEntityPtr ent, xmlBufferPtr buf) {
  944. xmlDumpEntityDecl(buf, ent);
  945. }
  946. /**
  947. * xmlDumpEntitiesTable:
  948. * @buf: An XML buffer.
  949. * @table: An entity table
  950. *
  951. * This will dump the content of the entity table as an XML DTD definition
  952. */
  953. void
  954. xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
  955. xmlHashScan(table, (xmlHashScanner)xmlDumpEntityDeclScan, buf);
  956. }
  957. #endif /* LIBXML_OUTPUT_ENABLED */
  958. #define bottom_entities
  959. #include "elfgcchack.h"