textreader.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. Copyright (c) 2010, Florian Reuter
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions
  6. are met:
  7. * Redistributions of source code must retain the above copyright
  8. notice, this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in
  11. the documentation and/or other materials provided with the
  12. distribution.
  13. * Neither the name of Florian Reuter nor the names of its contributors
  14. may be used to endorse or promote products derived from this
  15. software without specific prior written permission.
  16. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  17. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  19. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  20. COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  21. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  22. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  25. STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  27. OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. /** @file mce/textreader.h
  30. */
  31. #ifndef MCE_TEXTREADER_H
  32. #define MCE_TEXTREADER_H
  33. #ifdef __cplusplus
  34. extern "C" {
  35. #endif
  36. /**
  37. A handle to an MCE-aware libxml2 xmlTextReader.
  38. */
  39. typedef struct MCE_TEXTREADER mceTextReader_t;
  40. #ifdef __cplusplus
  41. } /* extern "C" */
  42. #endif
  43. #include <mce/config.h>
  44. #include <opc/opc.h>
  45. #include <mce/helper.h>
  46. #include <libxml/xmlwriter.h>
  47. #ifdef __cplusplus
  48. extern "C" {
  49. #endif
  50. struct MCE_TEXTREADER {
  51. xmlTextReaderPtr reader;
  52. mceCtx_t mceCtx;
  53. };
  54. /**
  55. Wrapper around an libxml2 xmlTextReaderRead function.
  56. \see http://xmlsoft.org/html/libxml-xmlreader.html#xmlTextReaderRead
  57. */
  58. int mceTextReaderRead(mceTextReader_t *mceTextReader);
  59. /**
  60. Wrapper around a libxml2 xmlTextReaderNext function.
  61. \see http://xmlsoft.org/html/libxml-xmlreader.html#xmlTextReaderNext
  62. */
  63. int mceTextReaderNext(mceTextReader_t *mceTextReader);
  64. /**
  65. Creates an mceTextReader from an XmlTextReader.
  66. \code
  67. mceTextReader reader;
  68. mceTextReaderInit(&reader, xmlNewTextReaderFilename("sample.xml"));
  69. // reader is ready to use.
  70. mceTextReaderCleanup(&reader);
  71. \endcode
  72. \see http://xmlsoft.org/html/libxml-xmlreader.html#xmlNewTextReaderFilename
  73. */
  74. int mceTextReaderInit(mceTextReader_t *mceTextReader, xmlTextReaderPtr reader);
  75. /**
  76. Cleanup MCE reader, i.e. free all resources. Also calls xmlTextReaderClose and xmlFreeTextReader.
  77. \see http://xmlsoft.org/html/libxml-xmlreader.html#xmlTextReaderClose
  78. \see http://xmlsoft.org/html/libxml-xmlreader.html#xmlFreeTextReader
  79. */
  80. int mceTextReaderCleanup(mceTextReader_t *mceTextReader);
  81. /**
  82. Reads all events \c mceTextReader and pipes them to \writer.
  83. \code
  84. mceTextReader reader;
  85. mceTextReaderInit(&reader, xmlNewTextReaderFilename("sample.xml"));
  86. mceTextReaderUnderstandsNamespace(&reader, _X("http://myextension"));
  87. xmlTextWriterPtr writer=xmlNewTextWriterFilename("out.xml", 0);
  88. mceTextReaderDump(&reader, writer, P_FALSE);
  89. xmlFreeTextWriter(writer);
  90. mceTextReaderCleanup(&reader);
  91. \endcode
  92. */
  93. int mceTextReaderDump(mceTextReader_t *mceTextReader, xmlTextWriter *writer, pbool_t fragment);
  94. /**
  95. Registers an MCE namespace.
  96. \see mceTextReaderDump()
  97. */
  98. int mceTextReaderUnderstandsNamespace(mceTextReader_t *mceTextReader, const xmlChar *ns);
  99. /**
  100. Disable MCE processing.
  101. \return Returns old value.
  102. */
  103. pbool_t mceTextReaderDisableMCE(mceTextReader_t *mceTextReader, pbool_t flag);
  104. /**
  105. Signal an error to the MCE processor.
  106. */
  107. void mceRaiseError(xmlTextReader *reader, mceCtx_t *ctx, mceError_t error, const xmlChar *str, ...);
  108. /**
  109. Internal function which does the MCE postprocessing. E.g. mceTextReaderRead() is implemented as
  110. \code
  111. mceTextReaderPostprocess(mceTextReader->reader, &mceTextReader->mceCtx, xmlTextReaderRead(mceTextReader->reader))
  112. \endcode
  113. This function is exposed to make existing libxm2 xmlTextReader MCE aware.
  114. */
  115. int mceTextReaderPostprocess(xmlTextReader *reader, mceCtx_t *ctx, int ret);
  116. /**
  117. Get the error code.
  118. */
  119. mceError_t mceTextReaderGetError(mceTextReader_t *mceTextReader);
  120. /**
  121. Helper macro to declare a start/end document block in a declarative way:
  122. \code
  123. mce_start_document(reader) {
  124. } mce_end_document(reader);
  125. \endcode
  126. \hideinitializer
  127. */
  128. #define mce_start_document(_reader_) \
  129. if (NULL!=(_reader_)) { \
  130. mceTextReaderRead(_reader_); \
  131. if (0)
  132. /**
  133. \see mce_start_document.
  134. \hideinitializer
  135. */
  136. #define mce_end_document(_reader_) \
  137. } /* if (NULL!=reader) */ \
  138. /**
  139. Container for mce_start_element and mce_start_attribute declarations.
  140. \see mce_match_element
  141. \see mce_match_attribute
  142. \hideinitializer
  143. */
  144. #define mce_start_choice(_reader_) \
  145. if (0)
  146. /**
  147. \see mce_start_choice
  148. \hideinitializer
  149. */
  150. #define mce_end_choice(_reader_)
  151. /**
  152. Skips the attributes.
  153. \see mce_match_element.
  154. \hideinitializer
  155. */
  156. #define mce_skip_attributes(_reader_) \
  157. mce_start_attributes(_reader_) { \
  158. } mce_end_attributes(_reader_);
  159. /**
  160. Skips the attributes.
  161. \see mce_match_attribute.
  162. \hideinitializer
  163. */
  164. #define mce_skip_children(_reader_) \
  165. mce_start_children(_reader_) { \
  166. } mce_end_children(_reader_);
  167. /**
  168. \see mce_start_element.
  169. \hideinitializer
  170. */
  171. #define mce_start_children(_reader_) \
  172. if (!xmlTextReaderIsEmptyElement((_reader_)->reader)) { \
  173. mceTextReaderRead(_reader_); do { \
  174. if (0)
  175. /**
  176. \see mce_start_element.
  177. \hideinitializer
  178. */
  179. #define mce_end_children(_reader_) \
  180. else { \
  181. if (XML_READER_TYPE_END_ELEMENT!=xmlTextReaderNodeType((_reader_)->reader)) { \
  182. mceTextReaderNext(_reader_); /*skip unhandled element */ \
  183. } \
  184. } \
  185. } while(XML_READER_TYPE_END_ELEMENT!=xmlTextReaderNodeType((_reader_)->reader) && \
  186. XML_READER_TYPE_NONE!=xmlTextReaderNodeType((_reader_)->reader)); \
  187. } /* if (!xmlTextReaderIsEmptyElement(reader->reader)) */
  188. /**
  189. Helper macro to match an element. Usefull for calling code in a seperate function:
  190. \code
  191. void handleElement(reader) {
  192. mce_start_choice(reader) {
  193. mce_start_element(reader, _X("ns"), _X("element")) {
  194. } mce_end_element(reader)
  195. } mce_end_choice(reader);
  196. }
  197. void parse(reader) {
  198. mce_start_document(reader) {
  199. mce_start_element(reader, _X("ns"), _X("ln")) {
  200. mce_skip_attributes(reader);
  201. mce_start_children(reader) {
  202. mce_match_element(reader, _X("ns"), _X("element")) {
  203. handleElement(reader);
  204. }
  205. } mce_end_children(reader);
  206. } mce_end_element();
  207. } mce_end_document(reader);
  208. }
  209. \endcode
  210. \hideinitializer
  211. */
  212. #define mce_match_element(_reader_, ns, ln) \
  213. } else if (XML_READER_TYPE_ELEMENT==xmlTextReaderNodeType((_reader_)->reader) \
  214. && (NULL==ns || 0==xmlStrcmp(ns, xmlTextReaderConstNamespaceUri((_reader_)->reader))) \
  215. && (NULL==ln || 0==xmlStrcmp(ln, xmlTextReaderConstLocalName((_reader_)->reader)))) {
  216. /**
  217. Helper macro to declare a element block in a declarative way:
  218. \code
  219. mce_start_element(reader) {
  220. mce_start_attributes(reader) {
  221. mce_start_attribute(reader, _X("ns"), _X("lnA")) {
  222. // code for handling lnA.
  223. } mce_end_attribute(reader);
  224. mce_start_attribute(reader, _X("ns"), _X("lnB")) {
  225. // code for handling lnB.
  226. } mce_end_attribute(reader);
  227. } mce_end_attributes(reader);
  228. mce_start_children(reader) {
  229. mce_start_element(reader, _X("ns"), _X("lnA")) {
  230. // code for handling lnA.
  231. } mce_end_element(reader);
  232. mce_start_element(reader, _X("ns"), _X("lnB")) {
  233. // code for handling lnB.
  234. } mce_end_element(reader);
  235. mce_start_text(reader) {
  236. // code for handling text.
  237. } mce_end_text(reader);
  238. } mce_end_children(reader);
  239. } mce_end_element(reader);
  240. \endcode
  241. \hideinitializer
  242. */
  243. #define mce_start_element(_reader_, ns, ln) \
  244. mce_match_element(_reader_, ns, ln)
  245. /**
  246. \see mce_start_element.
  247. \hideinitializer
  248. */
  249. #define mce_end_element(_reader_) \
  250. mceTextReaderNext(_reader_)
  251. /**
  252. Matches #TEXT without consuming it.
  253. \hideinitializer
  254. */
  255. #define mce_match_text(_reader_) \
  256. } else if (XML_READER_TYPE_TEXT==xmlTextReaderNodeType((_reader_)->reader) \
  257. || XML_READER_TYPE_SIGNIFICANT_WHITESPACE==xmlTextReaderNodeType((_reader_)->reader)) {
  258. /**
  259. \see mce_start_element.
  260. \hideinitializer
  261. */
  262. #define mce_start_text(_reader_) \
  263. mce_match_text(_reader_)
  264. /**
  265. \see mce_start_element.
  266. \hideinitializer
  267. */
  268. #define mce_end_text(_reader_) \
  269. mceTextReaderNext(_reader_)
  270. /**
  271. \see mce_start_element.
  272. \hideinitializer
  273. */
  274. #define mce_start_attributes(_reader_) \
  275. if (1==xmlTextReaderMoveToFirstAttribute((_reader_)->reader)) { \
  276. do { \
  277. if (0)
  278. /**
  279. \see mce_start_element.
  280. \hideinitializer
  281. */
  282. #define mce_end_attributes(_reader_) \
  283. else { /* skipped attribute */ } \
  284. } while(1==xmlTextReaderMoveToNextAttribute((_reader_)->reader)); \
  285. xmlTextReaderMoveToElement((_reader_)->reader); }
  286. /**
  287. Helper macro to match an attribute. Usefull for calling code in a seperate function:
  288. \code
  289. void handleA(reader) {
  290. mce_start_choice(reader) {
  291. mce_start_attribute(reader, _X("ns"), _X("attr")) {
  292. } mce_end_attribute(reader);
  293. } mce_end_choice(reader);
  294. }
  295. void parse(reader) {
  296. mce_start_document(reader) {
  297. mce_start_element(reader, _X("ns"), _X("ln")) {
  298. mce_start_attributes(reader) {
  299. mce_match_attribute(reader, _X("ns"), _X("attr")) {
  300. handleA(reader);
  301. }
  302. } mce_end_attributes(reader);
  303. mce_skip_children(reader);
  304. } mce_end_element();
  305. } mce_end_document(reader);
  306. }
  307. \endcode
  308. \hideinitializer
  309. */
  310. #define mce_match_attribute(_reader_, ns, ln) \
  311. } else if ((NULL==ns || 0==xmlStrcmp(ns, xmlTextReaderConstNamespaceUri((_reader_)->reader))) \
  312. && (NULL==ln || 0==xmlStrcmp(ln, xmlTextReaderConstLocalName((_reader_)->reader)))) {
  313. /**
  314. \see mce_start_element.
  315. \hideinitializer
  316. */
  317. #define mce_start_attribute(_reader_, ns, ln) \
  318. mce_match_attribute(_reader_, ns, ln)
  319. /**
  320. \see mce_start_element.
  321. \hideinitializer
  322. */
  323. #define mce_end_attribute(_reader_)
  324. /**
  325. Error handling for MCE parsers.
  326. \code
  327. mce_start_element(&reader, NULL, _X("Default")) {
  328. const xmlChar *ext=NULL;
  329. const xmlChar *type=NULL;
  330. mce_start_attributes(&reader) {
  331. mce_start_attribute(&reader, NULL, _X("Extension")) {
  332. ext=xmlTextReaderConstValue(reader.reader);
  333. } mce_end_attribute(&reader);
  334. mce_start_attribute(&reader, NULL, _X("ContentType")) {
  335. type=xmlTextReaderConstValue(reader.reader);
  336. } mce_end_attribute(&reader);
  337. } mce_end_attributes(&reader);
  338. mce_error_guard_start(&reader) {
  339. mce_error(&reader, NULL==ext || ext[0]==0, MCE_ERROR_VALIDATION, "Missing @Extension attribute!");
  340. mce_error(&reader, NULL==type || type[0]==0, MCE_ERROR_VALIDATION, "Missing @ContentType attribute!");
  341. opcContainerType *ct=insertType(c, type, OPC_TRUE);
  342. mce_error(&reader, NULL==ct, MCE_ERROR_MEMORY, NULL);
  343. opcContainerExtension *ce=opcContainerInsertExtension(c, ext, OPC_TRUE);
  344. mce_error(&reader, NULL==ce, MCE_ERROR_MEMORY, NULL);
  345. mce_errorf(&reader, NULL!=ce->type && 0!=xmlStrcmp(ce->type, type), MCE_ERROR_VALIDATION, "Extension \"%s\" is mapped to type \"%s\" as well as \"%s\"", ext, type, ce->type);
  346. ce->type=ct->type;
  347. } mce_error_guard_end(&reader);
  348. mce_skip_children(&reader);
  349. } mce_end_element(&reader);
  350. \endcode
  351. \hideinitializer
  352. */
  353. #define mce_error_guard_start(_reader_) if (MCE_ERROR_NONE==(_reader_)->mceCtx.error) do {
  354. /**
  355. \see mce_error_guard_start
  356. \hideinitializer
  357. */
  358. #define mce_error_guard_end(_reader_) } while(0)
  359. /**
  360. Signal an error if guard if false.
  361. \hideinitializer
  362. */
  363. #define mce_error(_reader_, guard, err, msg) if (guard) { (_reader_)->mceCtx.error=(err); fprintf(stderr, (NULL!=msg?msg:#err)); continue; }
  364. /**
  365. Signal an error if guard if false.
  366. \hideinitializer
  367. */
  368. #if defined(__GNUC__)
  369. #define mce_errorf(_reader_, guard, err, msg, ...) if (guard) { mceRaiseError((_reader_)->reader, &(_reader_)->mceCtx, err, _X((NULL!=msg?msg:#err)), ##__VA_ARGS__ ); continue; }
  370. #else
  371. #define mce_errorf(_reader_, guard, err, msg, ...) if (guard) { mceRaiseError((_reader_)->reader, &(_reader_)->mceCtx, err, _X((NULL!=msg?msg:#err)), __VA_ARGS__ ); continue; }
  372. #endif
  373. /**
  374. Only issues the error when in "strict mode".
  375. \hideinitializer
  376. */
  377. #define mce_error_strict mce_error
  378. /**
  379. \see mce_error_strict
  380. \hideinitializer
  381. */
  382. #define mce_error_strictf mce_errorf
  383. /**
  384. Marker for a MCE defintion.
  385. \hideinitializer
  386. */
  387. #define mce_def
  388. /**
  389. Marker for a MCE reference.
  390. \hideinitializer
  391. */
  392. #define mce_ref(r) (r)
  393. #ifdef __cplusplus
  394. } /* extern "C" */
  395. #endif
  396. #endif /* MCE_TEXTREADER_H */