entities.c 30 KB

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