LCOV - code coverage report
Current view: top level - monetdb5/modules/atoms - xml.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 144 473 30.4 %
Date: 2024-11-14 20:04:02 Functions: 13 23 56.5 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * @f xml
      15             :  * @a Sjoerd Mullender, Niels Nes, Martin Kersten
      16             :  * @v 0.1
      17             :  * @+ MAL support for XQL
      18             :  * This module contains the primitives needed in the SQL
      19             :  * front-end to support SQL/XML.
      20             :  */
      21             : #include "monetdb_config.h"
      22             : #include "xml.h"
      23             : #include "mal_interpreter.h"
      24             : 
      25             : #ifdef HAVE_LIBXML
      26             : #include <libxml/parser.h>
      27             : #include <libxml/xmlmemory.h>
      28             : 
      29             : /* The xml atom is used to represent XML data.  It is implemented as a
      30             :    subtype of str.  The first character of the string representation
      31             :    indicates the type of XML data.  There are three possibilities:
      32             :    * D - an XML document (possibly including <?xml?> and DOCTYPE);
      33             :    * C - XML content, i.e. something that can occur inside an XML element;
      34             :    * A - XML name/attribute pair.
      35             : */
      36             : 
      37             : size_t
      38         119 : XMLquotestring(const char *s, char *buf, size_t len)
      39             : {
      40         119 :         size_t i = 0;
      41             : 
      42         119 :         assert(len > 0);
      43         918 :         while (*s && i + 6 < len) {
      44         799 :                 if (*s == '&') {
      45           0 :                         buf[i++] = '&';
      46           0 :                         buf[i++] = 'a';
      47           0 :                         buf[i++] = 'm';
      48           0 :                         buf[i++] = 'p';
      49           0 :                         buf[i++] = ';';
      50             :                 } else if (*s == '<') {
      51           0 :                         buf[i++] = '&';
      52           0 :                         buf[i++] = 'l';
      53           0 :                         buf[i++] = 't';
      54           0 :                         buf[i++] = ';';
      55             :                 } else if (*s == '>') {
      56           0 :                         buf[i++] = '&';
      57           0 :                         buf[i++] = 'g';
      58           0 :                         buf[i++] = 't';
      59           0 :                         buf[i++] = ';';
      60             :                 } else if (*s == '"') {
      61           0 :                         buf[i++] = '&';
      62           0 :                         buf[i++] = 'q';
      63           0 :                         buf[i++] = 'u';
      64           0 :                         buf[i++] = 'o';
      65           0 :                         buf[i++] = 't';
      66           0 :                         buf[i++] = ';';
      67             :                 } else if (*s == '\'') {
      68           0 :                         buf[i++] = '&';
      69           0 :                         buf[i++] = 'a';
      70           0 :                         buf[i++] = 'p';
      71           0 :                         buf[i++] = 'o';
      72           0 :                         buf[i++] = 's';
      73           0 :                         buf[i++] = ';';
      74         799 :                 } else if ((*s & 0xFF) < 0x20) {
      75           0 :                         int n = snprintf(buf, len - i, "&#%d;", *s & 0xFF);
      76             : 
      77           0 :                         if (n < 0)
      78             :                                 break;
      79           0 :                         i += n;
      80             :                 } else {
      81         799 :                         buf[i++] = *s;
      82             :                 }
      83         799 :                 s++;
      84             :         }
      85         119 :         if (i < len)
      86         119 :                 buf[i] = 0;
      87             :         else
      88           0 :                 buf[len - 1] = 0;
      89         119 :         return i;
      90             : }
      91             : 
      92             : size_t
      93           0 : XMLunquotestring(const char **p, char q, char *buf)
      94             : {
      95           0 :         const char *s = *p;
      96           0 :         size_t i = 0;
      97             : 
      98           0 :         while (*s && *s != q) {
      99           0 :                 if (*s == '&') {
     100           0 :                         s++;
     101           0 :                         if (strncmp(s, "lt;", 3) == 0) {
     102           0 :                                 buf[i++] = '<';
     103           0 :                                 s += 3;
     104           0 :                         } else if (strncmp(s, "gt;", 3) == 0) {
     105           0 :                                 buf[i++] = '>';
     106           0 :                                 s += 3;
     107           0 :                         } else if (strncmp(s, "apos;", 5) == 0) {
     108           0 :                                 buf[i++] = '\'';
     109           0 :                                 s += 5;
     110           0 :                         } else if (strncmp(s, "quot;", 5) == 0) {
     111           0 :                                 buf[i++] = '"';
     112           0 :                                 s += 5;
     113           0 :                         } else if (strncmp(s, "amp;", 4) == 0) {
     114           0 :                                 buf[i++] = '&';
     115           0 :                                 s += 4;
     116           0 :                         } else if (*s == '#') {
     117           0 :                                 char *e;
     118           0 :                                 int base;
     119           0 :                                 unsigned long n;        /* type unsigned long returned by strtoul() */
     120             : 
     121           0 :                                 s++;
     122           0 :                                 if (*s == 'x' || *s == 'X') {
     123           0 :                                         s++;
     124           0 :                                         base = 16;
     125             :                                 } else
     126             :                                         base = 10;
     127           0 :                                 n = strtoul(s, &e, base);
     128           0 :                                 assert(e > s && *e == ';');
     129           0 :                                 assert(n <= 0x7FFFFFFF);
     130           0 :                                 s = e + 1;
     131           0 :                                 if (n <= 0x7F)
     132           0 :                                         buf[i++] = (char) n;
     133           0 :                                 else if (n <= 0x7FF) {
     134           0 :                                         buf[i++] = (char) (0xC0 | (n >> 6));
     135           0 :                                         buf[i++] = (char) (0x80 | (n & 0x3F));
     136           0 :                                 } else if (n <= 0xFFFF) {
     137           0 :                                         buf[i++] = (char) (0xE0 | (n >> 12));
     138           0 :                                         buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
     139           0 :                                         buf[i++] = (char) (0x80 | (n & 0x3F));
     140           0 :                                 } else if (n <= 0x1FFFFF) {
     141           0 :                                         buf[i++] = (char) (0xF0 | (n >> 18));
     142           0 :                                         buf[i++] = (char) (0x80 | ((n >> 12) & 0x3F));
     143           0 :                                         buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
     144           0 :                                         buf[i++] = (char) (0x80 | (n & 0x3F));
     145           0 :                                 } else if (n <= 0x3FFFFFF) {
     146           0 :                                         buf[i++] = (char) (0xF8 | (n >> 24));
     147           0 :                                         buf[i++] = (char) (0x80 | ((n >> 18) & 0x3F));
     148           0 :                                         buf[i++] = (char) (0x80 | ((n >> 12) & 0x3F));
     149           0 :                                         buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
     150           0 :                                         buf[i++] = (char) (0x80 | (n & 0x3F));
     151           0 :                                 } else if (n <= 0x7FFFFFFF) {
     152           0 :                                         buf[i++] = (char) (0xFC | (n >> 30));
     153           0 :                                         buf[i++] = (char) (0x80 | ((n >> 24) & 0x3F));
     154           0 :                                         buf[i++] = (char) (0x80 | ((n >> 18) & 0x3F));
     155           0 :                                         buf[i++] = (char) (0x80 | ((n >> 12) & 0x3F));
     156           0 :                                         buf[i++] = (char) (0x80 | ((n >> 6) & 0x3F));
     157           0 :                                         buf[i++] = (char) (0x80 | (n & 0x3F));
     158             :                                 }
     159             :                         } else {
     160             :                                 /* unrecognized entity: just leave it */
     161           0 :                                 buf[i++] = '&';
     162             :                         }
     163             :                 } else
     164           0 :                         buf[i++] = *s++;
     165             :         }
     166           0 :         buf[i] = 0;
     167           0 :         *p = s;
     168           0 :         return i;
     169             : }
     170             : 
     171             : str
     172           2 : XMLxml2str(str *s, const xml *x)
     173             : {
     174           2 :         if (strNil(*x)) {
     175           1 :                 *s = GDKstrdup(str_nil);
     176           1 :                 return MAL_SUCCEED;
     177             :         }
     178           1 :         assert(**x == 'A' || **x == 'C' || **x == 'D');
     179           1 :         *s = GDKstrdup(*x + 1);
     180           1 :         return MAL_SUCCEED;
     181             : }
     182             : 
     183             : str
     184           2 : XMLstr2xml(xml *x, const char *const*val)
     185             : {
     186           2 :         const char *t = *val;
     187           2 :         str buf;
     188           2 :         size_t len;
     189             : 
     190           2 :         if (strNil(t)) {
     191           0 :                 *x = (xml) GDKstrdup(str_nil);
     192           0 :                 if (*x == NULL)
     193           0 :                         throw(MAL, "xml.xml", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     194             :                 return MAL_SUCCEED;
     195             :         }
     196           2 :         len = 6 * strlen(t) + 1;
     197           2 :         buf = GDKmalloc(len + 1);
     198           2 :         if (buf == NULL)
     199           0 :                 throw(MAL, "xml.xml", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     200           2 :         buf[0] = 'C';
     201           2 :         XMLquotestring(t, buf + 1, len);
     202           2 :         *x = buf;
     203           2 :         return MAL_SUCCEED;
     204             : }
     205             : 
     206             : str
     207           0 : XMLxmltext(str *s, const xml *x)
     208             : {
     209           0 :         xmlDocPtr doc;
     210           0 :         xmlNodePtr elem;
     211           0 :         str content = NULL;
     212             : 
     213           0 :         if (strNil(*x)) {
     214           0 :                 *s = GDKstrdup(str_nil);
     215           0 :                 if (*s == NULL)
     216           0 :                         throw(MAL, "xml.text", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     217             :                 return MAL_SUCCEED;
     218             :         }
     219           0 :         if (**x == 'D') {
     220           0 :                 doc = xmlParseMemory(*x + 1, (int) strlen(*x + 1));
     221           0 :                 elem = xmlDocGetRootElement(doc);
     222           0 :                 content = (str) xmlNodeGetContent(elem);
     223           0 :                 xmlFreeDoc(doc);
     224           0 :         } else if (**x == 'C') {
     225           0 :                 doc = xmlParseMemory("<doc/>", 6);
     226           0 :                 xmlParseInNodeContext(xmlDocGetRootElement(doc), *x + 1,
     227           0 :                                                           (int) strlen(*x + 1), 0, &elem);
     228           0 :                 content = (str) xmlNodeGetContent(elem);
     229           0 :                 xmlFreeNodeList(elem);
     230           0 :                 xmlFreeDoc(doc);
     231           0 :         } else if (**x == 'A') {
     232           0 :                 const char *t = *x + 1;
     233           0 :                 str p;
     234             : 
     235           0 :                 p = content = GDKmalloc(strlen(*x) + 1);
     236           0 :                 if (p == NULL)
     237           0 :                         throw(MAL, "xml.text", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     238           0 :                 while (*t) {
     239           0 :                         if (*t == '"' || *t == '\'') {
     240           0 :                                 char q = *t++;
     241             : 
     242           0 :                                 p += XMLunquotestring(&t, q, p);
     243             :                         }
     244           0 :                         t++;
     245             :                 }
     246           0 :                 *p = 0;
     247             :         }
     248           0 :         if (content == NULL) {
     249           0 :                 *s = GDKstrdup("");
     250           0 :                 if (*s == NULL)
     251           0 :                         throw(MAL, "xml.text", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     252             :         } else
     253           0 :                 *s = (str) content;
     254             :         return MAL_SUCCEED;
     255             : }
     256             : 
     257             : str
     258           0 : XMLxml2xml(xml *s, const xml *x)
     259             : {
     260           0 :         *s = GDKstrdup(*x);
     261           0 :         if (*s == NULL)
     262           0 :                 throw(MAL, "xml.xml", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     263             :         return MAL_SUCCEED;
     264             : }
     265             : 
     266             : str
     267           0 : XMLdocument(xml *x, const char * const *val)
     268             : {
     269           0 :         xmlDocPtr doc;
     270             : 
     271           0 :         if (strNil(*val)) {
     272           0 :                 *x = (xml) GDKstrdup(str_nil);
     273           0 :                 if (*x == NULL)
     274           0 :                         throw(MAL, "xml.document", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     275             :                 return MAL_SUCCEED;
     276             :         }
     277             :         /* call the libxml2 library to perform the test */
     278           0 :         doc = xmlParseMemory(*val, (int) strlen(*val));
     279           0 :         if (doc) {
     280           0 :                 int len;
     281           0 :                 xmlChar *buf;
     282             : 
     283           0 :                 xmlDocDumpMemory(doc, &buf, &len);
     284           0 :                 xmlFreeDoc(doc);
     285           0 :                 *x = GDKmalloc(len + 2);
     286           0 :                 if (*x == NULL)
     287           0 :                         throw(MAL, "xml.document", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     288           0 :                 snprintf(*x, len + 2, "D%s", (char *) buf);
     289           0 :                 GDKfree(buf);
     290           0 :                 return MAL_SUCCEED;
     291             :         }
     292           0 :         throw(MAL, "xml.document", "Document parse error");
     293             : }
     294             : 
     295             : str
     296           0 : XMLcontent(xml *x, const char * const *val)
     297             : {
     298           0 :         xmlDocPtr doc;
     299           0 :         xmlNodePtr elem;
     300           0 :         xmlParserErrors err;
     301           0 :         xmlBufferPtr buf;
     302           0 :         const xmlChar *s;
     303           0 :         size_t len;
     304             : 
     305           0 :         if (strNil(*val)) {
     306           0 :                 *x = (xml) GDKstrdup(str_nil);
     307           0 :                 if (*x == NULL)
     308           0 :                         throw(MAL, "xml.content", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     309             :                 return MAL_SUCCEED;
     310             :         }
     311             :         /* call the libxml2 library to perform the test */
     312           0 :         doc = xmlParseMemory("<doc/>", 6);
     313           0 :         err = xmlParseInNodeContext(xmlDocGetRootElement(doc), *val,
     314           0 :                                                                 (int) strlen(*val), 0, &elem);
     315           0 :         if (err !=XML_ERR_OK) {
     316           0 :                 xmlFreeDoc(doc);
     317           0 :                 throw(MAL, "xml.content", "Content parse error");
     318             :         }
     319           0 :         buf = xmlBufferCreate();
     320           0 :         xmlNodeDump(buf, doc, elem, 0, 0);
     321           0 :         s = xmlBufferContent(buf);
     322           0 :         len = strlen((const char *) s) + 2;
     323           0 :         *x = GDKmalloc(len);
     324           0 :         if (*x == NULL)
     325           0 :                 throw(MAL, "xml.content", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     326           0 :         snprintf(*x, len, "C%s", (const char *) s);
     327           0 :         xmlBufferFree(buf);
     328           0 :         xmlFreeNodeList(elem);
     329           0 :         xmlFreeDoc(doc);
     330           0 :         return MAL_SUCCEED;
     331             : }
     332             : 
     333             : str
     334           2 : XMLisdocument(bit *x, const char * const *s)
     335             : {
     336           2 :         xmlDocPtr doc;
     337             : 
     338             :         /* call the libxml2 library to perform the test */
     339           2 :         if (strNil(*s))
     340           0 :                 *x = bit_nil;
     341             :         else {
     342           2 :                 doc = xmlParseMemory(*s, (int) strlen(*s));
     343           2 :                 *x = doc != NULL;
     344           2 :                 if (doc)
     345           2 :                         xmlFreeDoc(doc);
     346             :         }
     347           2 :         return MAL_SUCCEED;
     348             : }
     349             : 
     350             : str
     351           1 : XMLcomment(xml *x, const char * const *s)
     352             : {
     353           1 :         size_t len;
     354           1 :         str buf;
     355             : 
     356           1 :         if (strNil(*s)) {
     357           0 :                 *x = (xml) GDKstrdup(str_nil);
     358           0 :                 if (*x == NULL)
     359           0 :                         throw(MAL, "xml.comment", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     360             :                 return MAL_SUCCEED;
     361             :         }
     362           1 :         if (strstr(*s, "--") != NULL)
     363           0 :                 throw(MAL, "xml.comment", "comment may not contain `--'");
     364           1 :         len = strlen(*s) + 9;
     365           1 :         buf = (str) GDKmalloc(len);
     366           1 :         if (buf == NULL)
     367           0 :                 throw(MAL, "xml.comment", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     368           1 :         snprintf(buf, len, "C<!--%s-->", *s);
     369           1 :         *x = buf;
     370           1 :         return MAL_SUCCEED;
     371             : }
     372             : 
     373             : str
     374           0 : XMLparse(xml *x, const char * const *doccont, const char * const *val, const char * const *option)
     375             : {
     376           0 :         (void) option;
     377           0 :         if (strcmp(*doccont, "content") == 0)
     378           0 :                 return XMLcontent(x, val);
     379           0 :         if (strcmp(*doccont, "document") == 0)
     380           0 :                 return XMLdocument(x, val);
     381           0 :         throw(MAL, "xml.parse", "invalid parameter");
     382             : }
     383             : 
     384             : str
     385           0 : XMLpi(xml *ret, const char * const *target, const char * const *value)
     386             : {
     387           0 :         size_t len;
     388           0 :         str buf;
     389           0 :         str val = NULL;
     390             : 
     391           0 :         if (strNil(*target)) {
     392           0 :                 *ret = GDKstrdup(str_nil);
     393           0 :                 if (*ret == NULL)
     394           0 :                         throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     395             :                 return MAL_SUCCEED;
     396             :         }
     397           0 :         if (xmlValidateName((xmlChar *) *target, 0) != 0
     398           0 :                 || strcasecmp(*target, "xml") == 0)
     399           0 :                 throw(MAL, "xml.attribute", "invalid processing instruction target");
     400           0 :         len = strlen(*target) + 6;
     401           0 :         if (strNil(*value) || **value == 0) {
     402           0 :                 size_t n = 6 * strlen(*value) + 1;
     403             : 
     404           0 :                 val = GDKmalloc(n);
     405           0 :                 if (val == NULL)
     406           0 :                         throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     407           0 :                 len += XMLquotestring(*value, val, n) + 1;
     408             :         }
     409           0 :         buf = GDKmalloc(len);
     410           0 :         if (buf == NULL) {
     411           0 :                 if (val)
     412           0 :                         GDKfree(val);
     413           0 :                 throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     414             :         }
     415           0 :         if (val == NULL) {
     416           0 :                 snprintf(buf, len, "C<?%s?>", *target);
     417             :         } else {
     418           0 :                 snprintf(buf, len, "C<?%s %s?>", *target, val);
     419           0 :                 GDKfree(val);
     420             :         }
     421           0 :         *ret = buf;
     422           0 :         return MAL_SUCCEED;
     423             : }
     424             : 
     425             : str
     426           0 : XMLroot(xml *ret, const xml *val, const char * const *version, const char * const *standalone)
     427             : {
     428           0 :         size_t len = 0, i = 0;
     429           0 :         str buf;
     430           0 :         bit isdoc = 0;
     431             : 
     432           0 :         if (strNil(*val)) {
     433           0 :                 *ret = GDKstrdup(str_nil);
     434           0 :                 if (*ret == NULL)
     435           0 :                         throw(MAL, "xml.root", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     436             :                 return MAL_SUCCEED;
     437             :         }
     438           0 :         if (**val != 'C')
     439           0 :                 throw(MAL, "xml.root", "value must be an XML node");
     440           0 :         len = 8;
     441           0 :         len = strlen(*val);
     442           0 :         if (!strNil(*version) && **version) {
     443           0 :                 if (strcmp(*version, "1.0") != 0 && strcmp(*version, "1.1") != 0)
     444           0 :                         throw(MAL, "xml.root", "illegal XML version");
     445           0 :                 len += 11 + strlen(*version);   /* strlen(" version=\"\"") */
     446             :         }
     447           0 :         if (!strNil(*standalone) && **standalone) {
     448           0 :                 if (strcmp(*standalone, "yes") != 0 && strcmp(*standalone, "no") != 0)
     449           0 :                         throw(MAL, "xml.root", "illegal XML standalone value");
     450           0 :                 len += 14 + strlen(*standalone);        /* strlen(" standalone=\"\"") */
     451             :         }
     452           0 :         buf = GDKmalloc(len);
     453           0 :         if (buf == NULL)
     454           0 :                 throw(MAL, "xml.root", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     455           0 :         strcpy(buf, "D<?xml");
     456           0 :         i = strlen(buf);
     457           0 :         if (!strNil(*version) && **version)
     458           0 :                 i += snprintf(buf + i, len - i, " version=\"%s\"", *version);
     459           0 :         if (!strNil(*standalone) && **standalone)
     460           0 :                 i += snprintf(buf + i, len - i, " standalone=\"%s\"", *standalone);
     461           0 :         snprintf(buf + i, len - i, "?>%s", *val + 1);
     462           0 :         buf++;
     463           0 :         XMLisdocument(&isdoc, &(const char *){buf});    /* check well-formedness */
     464           0 :         buf--;
     465           0 :         if (!isdoc) {
     466           0 :                 GDKfree(buf);
     467           0 :                 throw(MAL, "xml.root", "resulting document not well-formed");
     468             :         }
     469           0 :         *ret = buf;
     470           0 :         return MAL_SUCCEED;
     471             : }
     472             : 
     473             : str
     474           1 : XMLattribute(xml *x, const char * const *name, const char * const *val)
     475             : {
     476           1 :         const char *t = *val;
     477           1 :         str buf;
     478           1 :         size_t len;
     479             : 
     480           2 :         if (strNil(t) || strNil(*name)) {
     481           0 :                 *x = (xml) GDKstrdup(str_nil);
     482           0 :                 if (*x == NULL)
     483           0 :                         throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     484             :                 return MAL_SUCCEED;
     485             :         }
     486           1 :         if (xmlValidateName((xmlChar *) *name, 0) != 0)
     487           0 :                 throw(MAL, "xml.attribute", "invalid attribute name");
     488           1 :         len = 6 * strlen(t) + 1;
     489           1 :         buf = GDKmalloc(len);
     490           1 :         if (buf == NULL)
     491           0 :                 throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     492           1 :         len = XMLquotestring(t, buf, len);
     493           1 :         len += strlen(*name) + 5;
     494           1 :         *x = GDKmalloc(len);
     495           1 :         if (*x == NULL) {
     496           0 :                 GDKfree(buf);
     497           0 :                 throw(MAL, "xml.attribute", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     498             :         }
     499           1 :         snprintf(*x, len, "A%s=\"%s\"", *name, buf);
     500           1 :         GDKfree(buf);
     501           1 :         return MAL_SUCCEED;
     502             : }
     503             : 
     504             : str
     505          23 : XMLelement(xml *ret, const char * const *name, const xml *nspace, const xml *attr, const xml *val)
     506             : {
     507          23 :         size_t len, i, namelen;
     508          23 :         str buf;
     509             : 
     510          23 :         if (strNil(*name))
     511           0 :                 throw(MAL, "xml.element", "no element name specified");
     512          23 :         if (xmlValidateName((xmlChar *) *name, 0) != 0)
     513           0 :                 throw(MAL, "xml.element", "invalid element name");
     514             :         /* len is composed of several parts:
     515             :            "C" + "<" + name + (nspace ? " " + nspace : "") + (attr ? " " + attr : "") + (val ? ">" + val + "</" + name + ">" : "/>")
     516             :          */
     517          23 :         namelen = strlen(*name);
     518          23 :         len = namelen + 5;                      /* "C", "<", "/", ">", terminating NUL */
     519          44 :         if (nspace && !strNil(*nspace)) {
     520           0 :                 if (**nspace != 'A')
     521           0 :                         throw(MAL, "xml.element", "illegal namespace");
     522           0 :                 len += strlen(*nspace); /* " " + nspace (nspace contains initial 'A' which is replaced by space) */
     523             :         }
     524          44 :         if (attr && !strNil(*attr)) {
     525          19 :                 if (**attr != 'A')
     526           0 :                         throw(MAL, "xml.element", "illegal attribute");
     527          19 :                 len += strlen(*attr);   /* " " + attr (attr contains initial 'A' which is replaced by space) */
     528             :         }
     529          46 :         if (!strNil(*val) && **val != 0) {
     530          21 :                 if (**val != 'C')
     531           0 :                         throw(MAL, "xml.element", "illegal content");
     532          21 :                 len += strlen(*val + 1) + namelen + 2;  /* extra "<", ">", and name ("/" already counted) */
     533             :         }
     534          23 :         buf = GDKmalloc(len);
     535          23 :         if (buf == NULL)
     536           0 :                 throw(MAL, "xml.element", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     537          25 :         if (strNil(*val) && (!attr || strNil(*attr))) {
     538           1 :                 strcpy(buf, str_nil);
     539             :         } else {
     540          22 :                 i = snprintf(buf, len, "C<%s", *name);
     541          42 :                 if (nspace && !strNil(*nspace))
     542           0 :                         i += snprintf(buf + i, len - i, " %s", *nspace + 1);
     543          42 :                 if (attr && !strNil(*attr))
     544          19 :                         i += snprintf(buf + i, len - i, " %s", *attr + 1);
     545          44 :                 if (!strNil(*val))
     546          21 :                         i += snprintf(buf + i, len - i, ">%s</%s>", *val + 1, *name);
     547             :                 else
     548           1 :                         i += snprintf(buf + i, len - i, "/>");
     549             :         }
     550          23 :         *ret = buf;
     551          23 :         return MAL_SUCCEED;
     552             : }
     553             : 
     554             : str
     555           2 : XMLelementSmall(xml *ret, const char * const *name, const xml *val)
     556             : {
     557           2 :         return XMLelement(ret, name, NULL, NULL, val);
     558             : }
     559             : 
     560             : str
     561           0 : XMLconcat(xml *ret, const xml *left, const xml *right)
     562             : {
     563           0 :         size_t len;
     564           0 :         str buf;
     565             : 
     566             :         /* if either side is nil, return the other, otherwise concatenate */
     567           0 :         if (strNil(*left))
     568           0 :                 buf = GDKstrdup(*right);
     569           0 :         else if (strNil(*right))
     570           0 :                 buf = GDKstrdup(*left);
     571           0 :         else if (**left != **right)
     572           0 :                 throw(MAL, "xml.concat", "arguments not compatible");
     573           0 :         else if (**left == 'A') {
     574           0 :                 len = strlen(*left) + strlen(*right) + 1;
     575           0 :                 buf = GDKmalloc(len);
     576           0 :                 if (buf == NULL)
     577           0 :                         throw(MAL, "xml.concat", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     578           0 :                 snprintf(buf, len, "A%s %s", *left + 1, *right + 1);
     579           0 :         } else if (**left == 'C') {
     580           0 :                 len = strlen(*left) + strlen(*right) + 2;
     581           0 :                 buf = GDKmalloc(len);
     582           0 :                 if (buf == NULL)
     583           0 :                         throw(MAL, "xml.concat", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     584           0 :                 snprintf(buf, len, "C%s%s", *left + 1, *right + 1);
     585             :         } else
     586           0 :                 throw(MAL, "xml.concat",
     587             :                           "can only concatenate attributes and element content");
     588           0 :         if (buf == NULL)
     589           0 :                 throw(MAL, "xml.concat", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     590           0 :         *ret = buf;
     591           0 :         return MAL_SUCCEED;
     592             : }
     593             : 
     594             : str
     595           1 : XMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     596             : {
     597           1 :         xml *ret = getArgReference_TYPE(stk, p, 0, xml);
     598           1 :         int i;
     599           1 :         size_t len;
     600           1 :         str buf;
     601           1 :         xml x;
     602             : 
     603           1 :         (void) cntxt;
     604           1 :         (void) mb;
     605             : 
     606           1 :         len = 2;
     607           3 :         for (i = p->retc; i < p->argc; i++) {
     608           2 :                 x = *getArgReference_TYPE(stk, p, i, xml);
     609           4 :                 if (!strNil(x))
     610           2 :                         if (*x != 'C')
     611           0 :                                 throw(MAL, "xml.forest", "arguments must be element content");
     612           2 :                 len += strlen(x + 1);
     613             :         }
     614           1 :         buf = (str) GDKmalloc(len);
     615           1 :         if (buf == NULL)
     616           0 :                 throw(MAL, "xml.forest", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     617           1 :         *ret = buf;
     618           1 :         *buf++ = 'C';
     619           1 :         *buf = 0;
     620             : 
     621           3 :         for (i = p->retc; i < p->argc; i++) {
     622           2 :                 x = *getArgReference_TYPE(stk, p, i, xml);
     623           4 :                 if (!strNil(x)) {
     624           2 :                         len = strlen(x + 1);
     625           2 :                         strcpy(buf, x + 1);
     626           2 :                         buf += len;
     627             :                 }
     628             :         }
     629             :         return MAL_SUCCEED;
     630             : }
     631             : 
     632             : int TYPE_xml;
     633             : 
     634             : static str
     635         328 : XMLprelude(void)
     636             : {
     637         328 :         TYPE_xml = ATOMindex("xml");
     638         328 :         xmlMemSetup(GDKfree, GDKmalloc, GDKrealloc, GDKstrdup);
     639         328 :         xmlInitParser();
     640         328 :         return MAL_SUCCEED;
     641             : }
     642             : 
     643             : str
     644         326 : XMLepilogue(void *ret)
     645             : {
     646         326 :         (void) ret;
     647         326 :         xmlCleanupParser();
     648         326 :         return MAL_SUCCEED;
     649             : }
     650             : 
     651             : static ssize_t
     652           0 : XMLfromString(const char *src, size_t *len, void **X, bool external)
     653             : {
     654           0 :         xml *x = (xml *) X;
     655           0 :         if (*x) {
     656           0 :                 GDKfree(*x);
     657           0 :                 *x = NULL;
     658             :         }
     659           0 :         if (external && strcmp(src, "nil") == 0) {
     660           0 :                 *x = GDKstrdup(str_nil);
     661           0 :                 if (*x == NULL)
     662             :                         return -1;
     663             :                 return 3;
     664           0 :         } else if (strNil(src)) {
     665           0 :                 *x = GDKstrdup(str_nil);
     666           0 :                 if (*x == NULL)
     667             :                         return -1;
     668             :                 return 1;
     669             :         } else {
     670           0 :                 char *err = XMLstr2xml(x, &src);
     671           0 :                 if (err !=MAL_SUCCEED) {
     672           0 :                         GDKerror("%s", getExceptionMessageAndState(err));
     673           0 :                         freeException(err);
     674           0 :                         return -1;
     675             :                 }
     676             :         }
     677           0 :         *len = strlen(*x) + 1;
     678           0 :         return (ssize_t) *len - 1;
     679             : }
     680             : 
     681             : static ssize_t
     682          48 : XMLtoString(str *s, size_t *len, const void *SRC, bool external)
     683             : {
     684          48 :         const char *src = SRC;
     685          48 :         size_t l;
     686             : 
     687          48 :         if (strNil(src))
     688           1 :                 src = external ? "nil" : str_nil;
     689             :         else
     690          47 :                 src++;
     691          48 :         l = strlen(src) + 1;
     692          48 :         if (l >= *len || *s == NULL) {
     693           5 :                 GDKfree(*s);
     694           5 :                 *s = GDKmalloc(l);
     695           5 :                 if (*s == NULL)
     696             :                         return -1;
     697           5 :                 *len = l;
     698             :         }
     699          48 :         strcpy(*s, src);
     700          48 :         return (ssize_t) l - 1;
     701             : }
     702             : 
     703             : #else
     704             : 
     705             : #define NO_LIBXML_FATAL "xml: MonetDB was built without libxml, but what you are trying to do requires it."
     706             : 
     707             : static ssize_t
     708             : XMLfromString(const char *src, size_t *len, void **x, bool external)
     709             : {
     710             :         (void) src;
     711             :         (void) len;
     712             :         (void) x;
     713             :         (void) external;
     714             :         GDKerror("not implemented\n");
     715             :         return -1;
     716             : }
     717             : 
     718             : static ssize_t
     719             : XMLtoString(str *s, size_t *len, const void *src, bool external)
     720             : {
     721             :         (void) s;
     722             :         (void) len;
     723             :         (void) src;
     724             :         (void) external;
     725             :         GDKerror("not implemented\n");
     726             :         return -1;
     727             : }
     728             : 
     729             : str
     730             : XMLxml2str(str *s, const xml *x)
     731             : {
     732             :         (void) s;
     733             :         (void) x;
     734             :         return createException(MAL, "xml.xml2str", SQLSTATE(HY005) NO_LIBXML_FATAL);
     735             : }
     736             : 
     737             : str
     738             : XMLstr2xml(xml *x, const char *const*val)
     739             : {
     740             :         (void) val;
     741             :         (void) x;
     742             :         return createException(MAL, "xml.xml2str", SQLSTATE(HY005) NO_LIBXML_FATAL);
     743             : }
     744             : 
     745             : str
     746             : XMLxmltext(str *s, const xml *x)
     747             : {
     748             :         (void) s;
     749             :         (void) x;
     750             :         return createException(MAL, "xml.xmltext", SQLSTATE(HY005) NO_LIBXML_FATAL);
     751             : }
     752             : 
     753             : str
     754             : XMLxml2xml(xml *x, const xml *s)
     755             : {
     756             :         (void) s;
     757             :         (void) x;
     758             :         return createException(MAL, "xml.xml2xml", SQLSTATE(HY005) NO_LIBXML_FATAL);
     759             : }
     760             : 
     761             : str
     762             : XMLdocument(xml *x, const char * const *s)
     763             : {
     764             :         (void) s;
     765             :         (void) x;
     766             :         return createException(MAL, "xml.document",
     767             :                                                    SQLSTATE(HY005) NO_LIBXML_FATAL);
     768             : }
     769             : 
     770             : str
     771             : XMLcontent(xml *x, const char * const *s)
     772             : {
     773             :         (void) s;
     774             :         (void) x;
     775             :         return createException(MAL, "xml.content", SQLSTATE(HY005) NO_LIBXML_FATAL);
     776             : }
     777             : 
     778             : str
     779             : XMLisdocument(bit *x, const char * const *s)
     780             : {
     781             :         (void) s;
     782             :         (void) x;
     783             :         return createException(MAL, "xml.isdocument",
     784             :                                                    SQLSTATE(HY005) NO_LIBXML_FATAL);
     785             : }
     786             : 
     787             : str
     788             : XMLcomment(xml *x, const char * const *s)
     789             : {
     790             :         (void) s;
     791             :         (void) x;
     792             :         return createException(MAL, "xml.comment", SQLSTATE(HY005) NO_LIBXML_FATAL);
     793             : }
     794             : 
     795             : str
     796             : XMLpi(xml *x, const char * const *target, const char * const *s)
     797             : {
     798             :         (void) s;
     799             :         (void) target;
     800             :         (void) x;
     801             :         return createException(MAL, "xml.pi", SQLSTATE(HY005) NO_LIBXML_FATAL);
     802             : }
     803             : 
     804             : str
     805             : XMLroot(xml *x, const xml *v, const char * const *version, const char * const *standalone)
     806             : {
     807             :         (void) x;
     808             :         (void) v;
     809             :         (void) version;
     810             :         (void) standalone;
     811             :         return createException(MAL, "xml.root", SQLSTATE(HY005) NO_LIBXML_FATAL);
     812             : }
     813             : 
     814             : str
     815             : XMLparse(xml *x, const char * const *doccont, const char * const *s, const char * const *option)
     816             : {
     817             :         (void) x;
     818             :         (void) doccont;
     819             :         (void) s;
     820             :         (void) option;
     821             :         return createException(MAL, "xml.parse", SQLSTATE(HY005) NO_LIBXML_FATAL);
     822             : }
     823             : 
     824             : str
     825             : XMLattribute(xml *ret, const char * const *name, const char * const *val)
     826             : {
     827             :         (void) ret;
     828             :         (void) name;
     829             :         (void) val;
     830             :         return createException(MAL, "xml.attribute",
     831             :                                                    SQLSTATE(HY005) NO_LIBXML_FATAL);
     832             : }
     833             : 
     834             : str
     835             : XMLelement(xml *ret, const char * const *name, const xml *nspace, const xml *attr, const xml *val)
     836             : {
     837             :         (void) ret;
     838             :         (void) name;
     839             :         (void) nspace;
     840             :         (void) attr;
     841             :         (void) val;
     842             :         return createException(MAL, "xml.element", SQLSTATE(HY005) NO_LIBXML_FATAL);
     843             : }
     844             : 
     845             : str
     846             : XMLelementSmall(xml *ret, const char * const *name, const xml *val)
     847             : {
     848             :         (void) ret;
     849             :         (void) name;
     850             :         (void) val;
     851             :         return createException(MAL, "xml.elementSmall",
     852             :                                                    SQLSTATE(HY005) NO_LIBXML_FATAL);
     853             : }
     854             : 
     855             : str
     856             : XMLconcat(xml *ret, const xml *left, const xml *right)
     857             : {
     858             :         (void) ret;
     859             :         (void) left;
     860             :         (void) right;
     861             :         return createException(MAL, "xml.concat", SQLSTATE(HY005) NO_LIBXML_FATAL);
     862             : }
     863             : 
     864             : str
     865             : XMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     866             : {
     867             :         (void) cntxt;
     868             :         (void) mb;
     869             :         (void) stk;
     870             :         (void) p;
     871             :         return createException(MAL, "xml.forest", SQLSTATE(HY005) NO_LIBXML_FATAL);
     872             : }
     873             : 
     874             : size_t
     875             : XMLquotestring(const char *s, char *buf, size_t len)
     876             : {
     877             :         (void) s;
     878             :         (void) buf;
     879             :         (void) len;
     880             :         return 0;
     881             : }
     882             : 
     883             : size_t
     884             : XMLunquotestring(const char **p, char q, char *buf)
     885             : {
     886             :         (void) p;
     887             :         (void) q;
     888             :         (void) buf;
     889             :         return 0;
     890             : }
     891             : 
     892             : static str
     893             : XMLprelude(void)
     894             : {
     895             :         return MAL_SUCCEED;                     /* to not break init */
     896             : }
     897             : 
     898             : str
     899             : XMLepilogue(void *ret)
     900             : {
     901             :         (void) ret;
     902             :         return MAL_SUCCEED;
     903             : }
     904             : 
     905             : #endif /* HAVE_LIBXML */
     906             : 
     907             : #include "mel.h"
     908             : mel_atom xml_init_atoms[] = {
     909             :  { .name="xml", .basetype="str", .fromstr=XMLfromString, .tostr=XMLtoString, },  { .cmp=NULL }
     910             : };
     911             : mel_func xml_init_funcs[] = {
     912             :  command("xml", "xml", XMLstr2xml, false, "Cast the string to an xml compliant string", args(1,2, arg("",xml),arg("src",str))),
     913             :  command("xml", "str", XMLxml2str, false, "Cast the string to an xml compliant string", args(1,2, arg("",str),arg("src",xml))),
     914             :  command("xml", "text", XMLxmltext, false, "Extract text from an xml atom", args(1,2, arg("",str),arg("src",xml))),
     915             :  command("xml", "comment", XMLcomment, false, "Construct an comment struction ", args(1,2, arg("",xml),arg("val",str))),
     916             :  command("xml", "parse", XMLparse, false, "Parse the XML document or element string values ", args(1,4, arg("",xml),arg("doccont",str),arg("val",str),arg("option",str))),
     917             :  command("xml", "pi", XMLpi, false, "Construct a processing instruction", args(1,3, arg("",xml),arg("target",str),arg("val",str))),
     918             :  command("xml", "document", XMLdocument, false, "Check the value for compliance as XML document", args(1,2, arg("",xml),arg("val",str))),
     919             :  command("xml", "content", XMLcontent, false, "Check the value for compliance as content, i.e.  it may contain multiple roots and character data.", args(1,2, arg("",xml),arg("val",str))),
     920             :  command("xml", "root", XMLroot, false, "Construct the root nodes", args(1,4, arg("",xml),arg("val",xml),arg("version",str),arg("standalone",str))),
     921             :  command("xml", "attribute", XMLattribute, false, "Construct an attribute value pair", args(1,3, arg("",xml),arg("name",str),arg("val",str))),
     922             :  command("xml", "element", XMLelement, false, "The basic building block for XML elements are namespaces, attributes and a sequence of xml elements. The name space and the attributes may be left unspecified(=nil:bat).", args(1,5, arg("",xml),arg("name",str),arg("ns",xml),arg("attr",xml),arg("s",xml))),
     923             :  command("xml", "element", XMLelementSmall, false, "The basic building block for XML elements are namespaces, attributes and a sequence of xml elements. The name space and the attributes may be left unspecified(=nil:bat).", args(1,3, arg("",xml),arg("name",str),arg("s",xml))),
     924             :  command("xml", "concat", XMLconcat, false, "Concatenate the xml values", args(1,3, arg("",xml),arg("val1",xml),arg("val2",xml))),
     925             :  pattern("xml", "forest", XMLforest, false, "Construct an element list", args(1,2, arg("",xml),vararg("val",xml))),
     926             :  command("xml", "isdocument", XMLisdocument, false, "Validate the string as a document", args(1,2, arg("",bit),arg("val",str))),
     927             :  command("xml", "epilogue", XMLepilogue, false, "", args(1,1, arg("",void))),
     928             :  command("calc", "xml", XMLstr2xml, false, "", args(1,2, arg("",xml),arg("src",str))),
     929             :  command("calc", "xml", XMLxml2xml, false, "", args(1,2, arg("",xml),arg("src",xml))),
     930             :  { .imp=NULL }
     931             : };
     932             : #include "mal_import.h"
     933             : #ifdef _MSC_VER
     934             : #undef read
     935             : #pragma section(".CRT$XCU",read)
     936             : #endif
     937         321 : LIB_STARTUP_FUNC(init_xml_mal)
     938         321 : { mal_module2("xml", xml_init_atoms, xml_init_funcs, XMLprelude, NULL); }

Generated by: LCOV version 1.14