str BATXMLxml2str(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "xml.str", INTERNAL_BAT_ACCESS); prepareResult(bn, b, TYPE_str, "str", (void) 0); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); if (strNil(t)) { bunfastapp(bn, t); bn->T->nonil = 0; } else { assert(*t == 'A' || *t == 'C' || *t == 'D'); bunfastapp(bn, t + 1); } } finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.str", OPERATION_FAILED " during bulk coercion"); }
str BATXMLdocument(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; size_t size = BUFSIZ; str buf = GDKmalloc(size); const char *err = OPERATION_FAILED; if (buf == NULL) throw(MAL,"xml.document",MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.document", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "document", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); xmlDocPtr doc; int len; xmlChar *s; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } len = (int) strlen(t); doc = xmlParseMemory(t, len); if (doc == NULL) { err = OPERATION_FAILED XML_PARSE_ERROR; goto bunins_failed; } xmlDocDumpMemory(doc, &s, &len); xmlFreeDoc(doc); if ((size_t) len + 2 >= size) { GDKfree(buf); size = (size_t) len + 128; buf = GDKmalloc(size); if (buf == NULL) { err= MAL_MALLOC_FAIL; goto bunins_failed; } } buf[0] = 'D'; strcpy(buf + 1, (char *) s); bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: GDKfree(buf); BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.document", "%s", err); }
str BATXMLcomment(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf = GDKmalloc(size); BATiter bi; const char *err= OPERATION_FAILED; if (buf == NULL) throw(MAL, "xml.comment", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.comment", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "comment", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } if (strstr(t, "--") != NULL) { err = XML_COMMENT_ERROR; goto bunins_failed; } len = strlen(t); if (len + 9 >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } snprintf(buf, size, "C<!--%s-->", t); bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.comment", "%s", err); }
/* * The core of the activity is str2xml, where the actual strings * are constructed. * To avoid repetitive copying we make sure that the garbage * collector does not remove the xml intermediates. * This way, we know that as long as the xml-variables are not * reused, the complete structure of the xml document(s) are available. * We merely have to collect the pieces. * [FOR LATER, FIRST GO FOR THE EASY IMPLEMENTATION] * XML values are represented by strings already. */ str BATXMLstr2xml(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; const char *err= OPERATION_FAILED; BATiter bi; buf = GDKmalloc(size); if (buf == NULL) throw(MAL,"xml.str2xml",MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.xml", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "xml", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } len = strlen(t) * 6 + 1; if (size < len) { size = len + 128; GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } buf[0] = 'C'; XMLquotestring(t, buf + 1, size - 1); bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.xml", "%s", err); }
static str do_batstr_int(bat *ret, const bat *l, const char *name, str (*func)(int *, const str *)) { BATiter bi; BAT *bn, *b; BUN p, q; str x; int y; str msg = MAL_SUCCEED; prepareOperand(b, l, name); prepareResult(bn, b, TYPE_int, name); bi = bat_iterator(b); BATloop(b, p, q) { x = (str) BUNtail(bi, p); if (x == 0 || strcmp(x, str_nil) == 0) { y = int_nil; bn->tnonil = 0; bn->tnil = 1; } else if ((msg = (*func)(&y, &x)) != MAL_SUCCEED) { goto bunins_failed; } bunfastapp(bn, &y); }
str BATXMLisdocument(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "xml.isdocument", INTERNAL_BAT_ACCESS); prepareResult(bn, b, TYPE_bit, "isdocument", (void) 0); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); xmlDocPtr doc; bit val; if (strNil(t)) { val = bit_nil; bn->T->nonil = 0; } else { doc = xmlParseMemory(t, (int) strlen(t)); if (doc == NULL) { val = 0; } else { xmlFreeDoc(doc); val = 1; } } bunfastapp(bn, &val); } finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.isdocument", OPERATION_FAILED " During bulk processing"); }
str BATXMLforest(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { bat *ret = getArgReference_bat(stk, pci, 0); BAT *bn; BATiter *bi; BUN *p, *q; str buf; int i; size_t offset, len, size = BUFSIZ; const char *err = OPERATION_FAILED; (void) mb; (void) cntxt; buf = GDKmalloc(size); bi = GDKmalloc(sizeof(BATiter) * pci->argc); p = GDKmalloc(sizeof(BUN) * pci->argc); q = GDKmalloc(sizeof(BUN) * pci->argc); if (buf == NULL || bi == NULL || p == NULL || q == NULL) { if (buf) GDKfree(buf); if (bi) GDKfree(bi); if (p) GDKfree(p); if (q) GDKfree(q); throw(MAL, "xml.forest", MAL_MALLOC_FAIL); } /* collect the admin for the xml elements */ for (i = pci->retc; i < pci->argc; i++) { if ((bi[i].b = BATdescriptor(*getArgReference_bat(stk, pci, i))) == NULL) break; p[i] = BUNfirst(bi[i].b); q[i] = BUNlast(bi[i].b); } /* check for errors */ if (i != pci->argc) { for (i--; i >= pci->retc; i--) if (bi[i].b) BBPunfix(bi[i].b->batCacheid); GDKfree(bi); GDKfree(p); GDKfree(q); GDKfree(buf); throw(MAL, "xml.forest", INTERNAL_BAT_ACCESS); } prepareResult(bn, bi[pci->retc].b, TYPE_xml, "forest", for (i = pci->retc; i < pci->argc; i++) BBPunfix(bi[i].b->batCacheid); GDKfree(bi); GDKfree(p); GDKfree(q); GDKfree(buf)); while (p[pci->retc] < q[pci->retc]) { const char *t; /* fetch the elements */ offset = 0; strcpy(buf, str_nil); for (i = pci->retc; i < pci->argc; i++) { int n; t = (const char *) BUNtail(bi[i], p[i]); if (strNil(t)) continue; if ((len = strlen(t)) >= size - offset) { size += len + 128; buf = GDKrealloc(buf, size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (offset == 0) n = snprintf(buf, size, "%s", t); else if (buf[0] != *t) { err = "incompatible values in forest"; goto bunins_failed; } else if (buf[0] == 'A') n = snprintf(buf + offset, size - offset, " %s", t + 1); else if (buf[0] == 'C') n = snprintf(buf + offset, size - offset, "%s", t + 1); else { err = "can only combine attributes and element content"; goto bunins_failed; } offset += n; } bunfastapp(bn, buf); if (offset == 0) bn->T->nonil = 0; for (i = pci->retc; i < pci->argc; i++) if (bi[i].b) p[i]++; } GDKfree(buf); finalizeResult(ret, bn, bi[pci->retc].b); GDKfree(bi); GDKfree(p); GDKfree(q); return MAL_SUCCEED; bunins_failed: for (i = pci->retc; i < pci->argc; i++) if (bi[i].b) BBPunfix(bi[i].b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); GDKfree(bi); GDKfree(p); GDKfree(q); throw(MAL, "xml.forest", "%s", err); }
str BATXMLelement(bat *ret, const char * const *name, xml *nspace, xml *attr, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; BATiter bi; size_t elemlen, namelen; const char *err = OPERATION_FAILED; if (strNil(*name)) throw(MAL, "xml.element", XML_NO_ELEMENT); if (xmlValidateName((xmlChar *) *name, 0) != 0) throw(MAL, "xml.element", XML_ATTRIBUTE_INVALID); if (nspace && !strNil(*nspace) && **nspace) throw(MAL, "xml.element", XML_NO_NAMESPACE); namelen = strlen(*name); elemlen = namelen + 5; if (nspace && !strNil(*nspace)) { if (**nspace != 'A') throw(MAL, "xml.element", XML_ILLEGAL_NAMESPACE); elemlen += strlen(*nspace); /* " " + nspace (nspace contains initial 'A' which is replaced by space) */ } if (attr && !strNil(*attr)) { if (**attr != 'A') throw(MAL, "xml.element", XML_ILLEGAL_ATTRIBUTE); elemlen += strlen(*attr); /* " " + attr (attr contains initial 'A' which is replaced by space) */ } buf = GDKmalloc(size); if (buf == NULL) throw(MAL, "xml.attribute", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.element", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "element", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; len = elemlen; if (!strNil(t)) { if (*t != 'C') { err = XML_ILLEGAL_CONTENT; goto bunins_failed; } len += strlen(t + 1) + namelen + 2; /* extra "<", ">", and name ("/" already counted) */ } if (len >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t) && (!attr || strNil(*attr))) { strcpy(buf, str_nil); bn->T->nonil = 0; } else { int i = snprintf(buf, size, "C<%s", *name); if (nspace && !strNil(*nspace)) i += snprintf(buf + i, size - i, " %s", *nspace + 1); if (attr && !strNil(*attr)) i += snprintf(buf + i, size - i, " %s", *attr + 1); if (!strNil(t)) i += snprintf(buf + i, size - i, ">%s</%s>", t + 1, *name); else i += snprintf(buf + i, size - i, "/>"); } bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.element", "%s", err); }
str BATXMLattribute(bat *ret, const char * const *name, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; BATiter bi; size_t attrlen; const char *err = OPERATION_FAILED; if (strNil(*name)) throw(MAL, "xml.attribute", XML_ATTRIBUTE_ERROR); if (xmlValidateName((xmlChar *) *name, 0) != 0) throw(MAL, "xml.attribute", XML_ATTRIBUTE_INVALID); attrlen = strlen(*name) + 5; buf = GDKmalloc(size); if (buf == NULL) throw(MAL, "xml.attribute", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.attribute", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "attribute", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; len = attrlen; if (!strNil(t)) len += strlen(t) * 6 + 1; if (len >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t)) { strcpy(buf, str_nil); bn->T->nonil = 0; } else { int n = snprintf(buf, size, "A%s = \"", *name); size_t m = XMLquotestring(t, buf + n, size - n); strcpy(buf + n + m, "\""); } bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.attribute", "%s", err); }
str BATXMLroot(bat *ret, const bat *bid, const char * const *version, const char * const *standalone) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; BATiter bi; size_t hdrlen; const char *err = OPERATION_FAILED; hdrlen = 8; if (!strNil(*version) && **version) { if (strcmp(*version, "1.0") != 0 && strcmp(*version, "1.1") != 0) throw(MAL, "xml.root", XML_VERSION_ERROR); hdrlen += 11 + strlen(*version); /* strlen(" version=\"\"") */ } if (!strNil(*standalone) && **standalone) { if (strcmp(*standalone, "yes") != 0 && strcmp(*standalone, "no") != 0) throw(MAL, "xml.root", XML_STANDALONE_ERROR "illegal XML standalone value"); hdrlen += 14 + strlen(*standalone); /* strlen(" standalone=\"\"") */ } buf = GDKmalloc(size); if (buf == NULL) throw(MAL, "xml.root", MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.pi", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "pi", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len, i; bit isdoc; len = hdrlen; if (!strNil(t)) len += strlen(t); if (len >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t)) { strcpy(buf, str_nil); bn->T->nonil = 0; } else { strcpy(buf, "D<?xml"); i = strlen(buf); if (!strNil(*version) && **version) i += snprintf(buf + i, len - i, " version=\"%s\"", *version); if (!strNil(*standalone) && **standalone) i += snprintf(buf + i, len - i, " standalone=\"%s\"", *standalone); snprintf(buf + i, len - i, "?>%s", t + 1); buf++; XMLisdocument(&isdoc, &buf); /* check well-formedness */ buf--; if (!isdoc) { err = XML_NOT_WELL_FORMED; goto bunins_failed; } } bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.root", "%s", err); }
str BATXMLpi(bat *ret, const char * const *target, const bat *bid) { BAT *b, *bn; BUN p, q; size_t size = BUFSIZ; str buf; BATiter bi; size_t tgtlen; const char *err = OPERATION_FAILED; if (strNil(*target)) throw(MAL, "xml.pi", XML_PI_ERROR); buf = GDKmalloc(size); if (buf == NULL) throw(MAL, "xml.pi", MAL_MALLOC_FAIL); tgtlen = strlen(*target) + 6; if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.pi", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "pi", GDKfree(buf)); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; len = tgtlen; if (!strNil(t)) len += strlen(t) * 6 + 1; if (len >= size) { /* make sure there is enough space */ size = len + 128; /* free/malloc so we don't copy */ GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t)) snprintf(buf, size, "C<?%s?>", *target); else { int n = snprintf(buf, size, "C<?%s ", *target); size_t m = XMLquotestring(t, buf + n, size - n); strcpy(buf + n + m, "?>"); } bunfastapp(bn, buf); } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.pi", "%s", err); }
/* * The standard supports specific mappings for * NULL values,i.e. {null,absent,empty,nil,niloncontent) * in the context of an element and forest construction. * The standard should be studied in more detail, because * the syntax(rules) seem ambiguous. * It applies to all components of an element or their * concatenation. * * For the time being, the variaton on XMLtag seems the * most reasonable interpretation. */ str BATXMLoptions(bat *ret, const char * const *name, const char * const *options, const bat *bid) { BAT *b, *bn; BUN p, q; str buf = GDKmalloc(BUFSIZ); str val = GDKmalloc(BUFSIZ); size_t size = BUFSIZ, len = strlen(*name); BATiter bi; const char *err = OPERATION_FAILED " During bulk options analysis"; if (val == NULL || buf == NULL) { if (val != NULL) GDKfree(val); if (buf != NULL) GDKfree(buf); throw(MAL, "batxml.options", MAL_MALLOC_FAIL); } if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(val); GDKfree(buf); throw(MAL, "xml.options", INTERNAL_BAT_ACCESS); } prepareResult(bn, b, TYPE_xml, "options", GDKfree(val); GDKfree(buf)); if (strcmp(*options, "absent") == 0) buf[0] = 0; else if (strcmp(*options, "empty") == 0) snprintf(buf, size, "<%s></%s>", *name, *name); else if (strcmp(*options, "null") == 0) snprintf(buf, size, "null"); else if (strcmp(*options, "nil") == 0) snprintf(buf, size, "nil"); else { /*if(strcmp(*options,"niloncontent")==0) */ err = PROGRAM_NYI; goto bunins_failed; } snprintf(val, size, "<%s>", *name); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); if (strNil(t)) { bunfastapp(bn, buf); } else { if (strlen(t) > size - 2 * len - 6) { size += strlen(t); val = (char *) GDKrealloc(val, size + strlen(t)); if (val == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } snprintf(val + len + 2, size - len, "%s</%s>", t, *name); bunfastapp(bn, val); } } GDKfree(val); GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); if (val != NULL) GDKfree(val); throw(MAL, "batxml.options", "%s", err); }
str BATXMLcontent(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; xmlDocPtr doc; xmlNodePtr root; size_t size = BUFSIZ; str buf = GDKmalloc(size); const char *err = OPERATION_FAILED; xmlBufferPtr xbuf; if (buf == NULL) throw(MAL,"xml.content",MAL_MALLOC_FAIL); if ((b = BATdescriptor(*bid)) == NULL) { GDKfree(buf); throw(MAL, "xml.content", INTERNAL_BAT_ACCESS); } doc = xmlParseMemory("<doc/>", 6); root = xmlDocGetRootElement(doc); prepareResult(bn, b, TYPE_xml, "content", GDKfree(buf)); bi = bat_iterator(b); xbuf = xmlBufferCreate(); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; xmlNodePtr elem; xmlParserErrors xerr; const xmlChar *s; if (strNil(t)) { bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } len = strlen(t); xerr = xmlParseInNodeContext(root, t, (int) len, 0, &elem); if (xerr != XML_ERR_OK) { err = XML_PARSE_ERROR; goto bunins_failed; } xmlNodeDump(xbuf, doc, elem, 0, 0); s = xmlBufferContent(xbuf); len = strlen((const char *) s); if (len + 2 >= size) { GDKfree(buf); size = len + 128; buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } buf[0] = 'C'; strcpy(buf + 1, (const char *) s); bunfastapp(bn, buf); xmlBufferEmpty(xbuf); xmlFreeNodeList(elem); } xmlBufferFree(xbuf); xmlFreeDoc(doc); GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: xmlBufferFree(xbuf); xmlFreeDoc(doc); if (buf != NULL) GDKfree(buf); BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); throw(MAL, "xml.document", "%s", err); }
str BATXMLxmltext(bat *ret, const bat *bid) { BAT *b, *bn; BUN p, q; BATiter bi; size_t size = 0; str buf = NULL; xmlDocPtr doc = NULL; xmlNodePtr elem; str content = NULL; const char *err = OPERATION_FAILED; if ((b = BATdescriptor(*bid)) == NULL) throw(MAL, "xml.text", INTERNAL_BAT_ACCESS); prepareResult(bn, b, TYPE_str, "text", (void) 0); bi = bat_iterator(b); BATloop(b, p, q) { const char *t = (const char *) BUNtail(bi, p); size_t len; if (strNil(t)) { bunfastapp(bn, t); bn->T->nonil = 0; continue; } len = strlen(t); switch (*t) { case 'D': { xmlDocPtr d = xmlParseMemory(t + 1, (int) (len - 1)); elem = xmlDocGetRootElement(d); content = (str) xmlNodeGetContent(elem); xmlFreeDoc(d); if (content == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } break; } case 'C': if (doc == NULL) doc = xmlParseMemory("<doc/>", 6); xmlParseInNodeContext(xmlDocGetRootElement(doc), t + 1, (int) (len - 1), 0, &elem); content = (str) xmlNodeGetContent(elem); xmlFreeNodeList(elem); if (content == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } break; case 'A': { str s; if (buf == NULL || size < len) { size = len + 128; if (buf != NULL) GDKfree(buf); buf = GDKmalloc(size); if (buf == NULL) { err = MAL_MALLOC_FAIL; goto bunins_failed; } } s = buf; t++; while (*t) { if (*t == '"' || *t == '\'') { char q = *t++; s += XMLunquotestring(&t, q, s); } t++; } *s = 0; break; } default: assert(*t == 'A' || *t == 'C' || *t == 'D'); bunfastapp(bn, str_nil); bn->T->nonil = 0; continue; } assert(content != NULL || buf != NULL); bunfastapp(bn, content != NULL ? content : buf); if (content != NULL) GDKfree(content); content = NULL; } finalizeResult(ret, bn, b); if (buf != NULL) GDKfree(buf); if (doc != NULL) xmlFreeDoc(doc); return MAL_SUCCEED; bunins_failed: BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); if (doc != NULL) xmlFreeDoc(doc); if (content != NULL) GDKfree(content); throw(MAL, "xml.text", "%s", err); }
str BATXMLconcat(bat *ret, const bat *bid, const bat *rid) { BAT *b, *r = 0, *bn; BUN p, q, rp = 0; size_t len, size = BUFSIZ; str buf = GDKmalloc(size); BATiter bi, ri; const char *err = OPERATION_FAILED; if (buf == NULL) throw(MAL, "xml.concat", MAL_MALLOC_FAIL); b = BATdescriptor(*bid); r = BATdescriptor(*rid); if (b == NULL || r == NULL) { GDKfree(buf); if (b) BBPunfix(b->batCacheid); if (r) BBPunfix(r->batCacheid); throw(MAL, "xml.concat", INTERNAL_BAT_ACCESS); } p = BUNfirst(b); q = BUNlast(b); rp = BUNfirst(r); prepareResult(bn, b, TYPE_xml, "concat", GDKfree(buf); BBPunfix(r->batCacheid)); bi = bat_iterator(b); ri = bat_iterator(r); while (p < q) { const char *t = (const char *) BUNtail(bi, p); const char *v = (const char *) BUNtail(ri, rp); len = strlen(t) + strlen(v) + 1; if (len >= size) { GDKfree(buf); size = len + 128; buf = GDKmalloc(size); if (buf == NULL) { err= MAL_MALLOC_FAIL; goto bunins_failed; } } if (strNil(t)) { if (strNil(v)) { strcpy(buf, str_nil); bn->T->nonil = 0; } else strcpy(buf, v); } else { if (strNil(v)) strcpy(buf, t); else if (*t != *v) { err = "arguments not compatible"; goto bunins_failed; } else if (*t == 'A') snprintf(buf, size, "A%s %s", t + 1, v + 1); else if (*t == 'C') snprintf(buf, size, "C%s%s", t + 1, v + 1); else { err = "can only concatenate attributes and element content"; goto bunins_failed; } } bunfastapp(bn, buf); rp++; p++; } GDKfree(buf); finalizeResult(ret, bn, b); return MAL_SUCCEED; bunins_failed: BBPunfix(r->batCacheid); BBPunfix(b->batCacheid); BBPunfix(bn->batCacheid); if (buf != NULL) GDKfree(buf); throw(MAL, "xml.concat", "%s", err); }