From 30c4b0ebc24fe0106e146b1f6577a4150e71e258 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 7 Feb 2013 13:34:27 +0400 Subject: - Fixing TAB to 2 spaces - Fixing line endings from "\r\n" to "\n" --- storage/connect/libdoc.cpp | 1502 ++++++++++++++++++++++---------------------- 1 file changed, 751 insertions(+), 751 deletions(-) (limited to 'storage/connect/libdoc.cpp') diff --git a/storage/connect/libdoc.cpp b/storage/connect/libdoc.cpp index dedee068ca0..36e920540aa 100644 --- a/storage/connect/libdoc.cpp +++ b/storage/connect/libdoc.cpp @@ -1,751 +1,751 @@ -/******************************************************************/ -/* Implementation of XML document processing using libxml2 */ -/* Author: Olivier Bertrand 2007-2013 */ -/******************************************************************/ -#include -#include -#include -#include -#include -#include -//#if defined(WIN32) -//#include -//#else // !WIN32 -#include "my_global.h" -//#endif // !WIN32 - -#if !defined(LIBXML_XPATH_ENABLED) || !defined(LIBXML_SAX1_ENABLED) -#error "XPath not supported" -#endif - -#include "global.h" -#include "plgdbsem.h" -#include "xobject.h" -#include "libdoc.h" - -#include "sql_string.h" - -extern "C" { -extern char version[]; -extern int trace; -} // "C" - -/******************************************************************/ -/* Return a LIBXMLDOC as a XMLDOC. */ -/******************************************************************/ -PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf, - char *enc, PFBLOCK fp) - { - return (PXDOC) new(g) LIBXMLDOC(nsl, nsdf, enc, fp); - } // end of GetLibxmlDoc - -/******************************************************************/ -/* XML library initialization function. */ -/******************************************************************/ -void XmlInitParserLib(void) - { - xmlInitParser(); - } // end of XmlInitParserLib - -/******************************************************************/ -/* XML library cleanup function. */ -/******************************************************************/ -void XmlCleanupParserLib(void) - { - xmlCleanupParser(); - xmlMemoryDump(); - } // end of XmlCleanupParserLib - -/******************************************************************/ -/* Close a loaded libxml2 XML file. */ -/******************************************************************/ -void CloseXML2File(PGLOBAL g, PFBLOCK fp, bool all) - { - PX2BLOCK xp = (PX2BLOCK)fp; - - if (xp && xp->Count > 1 && !all) { - xp->Count--; - } else if (xp && xp->Count > 0) { - xmlFreeDoc(xp->Docp); - xp->Count = 0; - } // endif - - } // end of CloseXML2File - -/* ---------------------- class LIBXMLDOC ----------------------- */ - -/******************************************************************/ -/* LIBXMLDOC constructor. */ -/******************************************************************/ -LIBXMLDOC::LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp) - : XMLDOCUMENT(nsl, nsdf, enc) - { - assert (!fp || fp->Type == TYPE_FB_XML2); - Docp = (fp) ? ((PX2BLOCK)fp)->Docp : NULL; - Nlist = NULL; - Ctxp = NULL; - Xop = NULL; - } // end of LIBXMLDOC constructor - -/******************************************************************/ -/* Initialize XML parser and check library compatibility. */ -/******************************************************************/ -bool LIBXMLDOC::Initialize(PGLOBAL g) - { -//int n = xmlKeepBlanksDefault(0); - return MakeNSlist(g); - } // end of Initialize - -/******************************************************************/ -/* Parse the XML file and construct node tree in memory. */ -/******************************************************************/ -bool LIBXMLDOC::ParseFile(char *fn) - { - if ((Docp = xmlParseFile(fn))) { - if (Docp->encoding) - Encoding = (char*)Docp->encoding; - - return false; - } else - return true; - - } // end of ParseFile - -/******************************************************************/ -/* Create or reuse an Xblock for this document. */ -/******************************************************************/ -PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn) - { - PDBUSER dup = (PDBUSER)g->Activityp->Aptr; - PX2BLOCK xp = (PX2BLOCK)PlugSubAlloc(g, NULL, sizeof(X2BLOCK)); - - memset(xp, 0, sizeof(X2BLOCK)); - xp->Next = (PX2BLOCK)dup->Openlist; - dup->Openlist = (PFBLOCK)xp; - xp->Type = TYPE_FB_XML2; - xp->Fname = (LPCSTR)PlugSubAlloc(g, NULL, strlen(fn) + 1); - strcpy((char*)xp->Fname, fn); - xp->Count = 1; - xp->Length = (m == MODE_READ) ? 1 : 0; - xp->Retcode = rc; - xp->Docp = Docp; -// xp->Ctxp = Ctxp; -// xp->Xop = Xop; - - // Return xp as a fp - return (PFBLOCK)xp; - } // end of LinkXblock - -/******************************************************************/ -/* Construct and add the XML processing instruction node. */ -/******************************************************************/ -bool LIBXMLDOC::NewDoc(PGLOBAL g, char *ver) - { - return ((Docp = xmlNewDoc(BAD_CAST ver)) == NULL); - } // end of NewDoc - -/******************************************************************/ -/* Add a new comment node to the document. */ -/******************************************************************/ -void LIBXMLDOC::AddComment(PGLOBAL g, char *txtp) - { - xmlNodePtr cp = xmlNewDocComment(Docp, BAD_CAST txtp); - xmlAddChild((xmlNodePtr)Docp, cp); - } // end of AddText - -/******************************************************************/ -/* Return the node class of the root of the document. */ -/******************************************************************/ -PXNODE LIBXMLDOC::GetRoot(PGLOBAL g) - { - xmlNodePtr root = xmlDocGetRootElement(Docp); - - if (!root) - return NULL; - - return new(g) XML2NODE(this, root); - } // end of GetRoot - -/******************************************************************/ -/* Create a new root element and return its class node. */ -/******************************************************************/ -PXNODE LIBXMLDOC::NewRoot(PGLOBAL g, char *name) - { - xmlNodePtr root = xmlNewDocNode(Docp, NULL, BAD_CAST name, NULL); - - if (root) { - xmlDocSetRootElement(Docp, root); - return new(g) XML2NODE(this, root); - } else - return NULL; - - } // end of NewRoot - -/******************************************************************/ -/* Return a void XML2NODE node class. */ -/******************************************************************/ -PXNODE LIBXMLDOC::NewPnode(PGLOBAL g, char *name) - { - xmlNodePtr nop; - - if (name) { - nop = xmlNewDocNode(Docp, NULL, BAD_CAST name, NULL); - - if (nop == NULL) - return NULL; - - } else - nop = NULL; - - return new(g) XML2NODE(this, nop); - } // end of NewPnode - -/******************************************************************/ -/* Return a void XML2ATTR node class. */ -/******************************************************************/ -PXATTR LIBXMLDOC::NewPattr(PGLOBAL g) - { - return new(g) XML2ATTR(this, NULL, NULL); - } // end of NewPattr - -/******************************************************************/ -/* Return a void XML2ATTR node class. */ -/******************************************************************/ -PXLIST LIBXMLDOC::NewPlist(PGLOBAL g) - { - return new(g) XML2NODELIST(this, NULL); - } // end of NewPlist - -/******************************************************************/ -/* Dump the node tree to a new XML file. */ -/******************************************************************/ -int LIBXMLDOC::DumpDoc(PGLOBAL g, char *ofn) - { - int rc; - FILE *of; - - if (!(of= global_fopen(g, MSGID_CANNOT_OPEN, ofn, "w"))) - return -1; - -#if 1 - // This function does not crash ( - rc = xmlSaveFormatFileEnc((const char *)ofn, Docp, Encoding, 0); -// rc = xmlDocDump(of, Docp); -#else // 0 - // Until this function is fixed, do the job ourself - xmlNodePtr Rootp; - - // Save the modified document - fprintf(of, "\n", Encoding); - fprintf(of, "\n", version); - - if (!(Rootp = xmlDocGetRootElement(Docp))) - return 1; - - Buf = (char*)PlugSubAlloc(g, NULL, 1024); - rc = iconv_close(Cd2); - Cd2 = iconv_open(Encoding, "UTF-8"); - rc = CheckDocument(of, Rootp); -#endif // 0 - - fclose(of); - return rc; - } // end of Dump - -/******************************************************************/ -/* Free the document, cleanup the XML library, and */ -/* debug memory for regression tests. */ -/******************************************************************/ -void LIBXMLDOC::CloseDoc(PGLOBAL g, PFBLOCK xp) - { - if (xp && xp->Count == 1) { - if (Xop) - xmlXPathFreeObject(Xop); - - if (Ctxp) - xmlXPathFreeContext(Ctxp); - - } // endif Count - - CloseXML2File(g, xp, false); - } // end of Close - -/******************************************************************/ -/* Evaluate the passed Xpath from the passed context node. */ -/******************************************************************/ -xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp) - { - xmlNodeSetPtr nl; - - if (trace) - htrc("GetNodeList %s np=%p\n", xp, np); - - if (!Ctxp) { - // Init Xpath - xmlXPathInit(); - - // Create xpath evaluation context - if (!(Ctxp = xmlXPathNewContext(Docp))) { - strcpy(g->Message, MSG(XPATH_CNTX_ERR)); - - if (trace) - htrc("Context error: %s\n", g->Message); - - return NULL; - } // endif xpathCtx - - // Register namespaces from list (if any) - for (PNS nsp = Namespaces; nsp; nsp = nsp->Next) - if (xmlXPathRegisterNs(Ctxp, BAD_CAST nsp->Prefix, - BAD_CAST nsp->Uri)) { - sprintf(g->Message, MSG(REGISTER_ERR), nsp->Prefix, nsp->Uri); - - if (trace) - htrc("Ns error: %s\n", g->Message); - - return NULL; - } // endif Registering - - } else - xmlXPathFreeNodeSetList(Xop); // To be checked - - // Set the context to the calling node - Ctxp->node = np; - - // Evaluate table xpath - if (!(Xop = xmlXPathEval(BAD_CAST xp, Ctxp))) { - sprintf(g->Message, MSG(XPATH_EVAL_ERR), xp); - - if (trace) - htrc("Path error: %s\n", g->Message); - - return NULL; - } else - nl = Xop->nodesetval; - - if (trace) - htrc("GetNodeList nl=%p n=%p\n", nl, (nl) ? nl->nodeNr : 0); - - return nl; - } // end of GetNodeList - -/******************************************************************/ -/* CheckDocument: check if the document is ok to dump. */ -/* Currently this does the dumping of the document. */ -/******************************************************************/ -bool LIBXMLDOC::CheckDocument(FILE *of, xmlNodePtr np) - { - int n; - bool b; - - if (!np) - return true; - - if (np->type == XML_ELEMENT_NODE) { - n = fprintf(of, "<%s", np->name); - b = CheckDocument(of, (xmlNodePtr)np->properties); - - if (np->children) - n = fprintf(of, ">"); - else - n = fprintf(of, "/>"); - - } else if (np->type == XML_ATTRIBUTE_NODE) - n = fprintf(of, " %s=\"", np->name); - else if (np->type == XML_TEXT_NODE) - n = fprintf(of, "%s", Encode(NULL, (char*)np->content)); - else if (np->type == XML_COMMENT_NODE) - n = fprintf(of, "%s", Encode(NULL, (char*)np->content)); - - b = CheckDocument(of, np->children); - - if (np->type == XML_ATTRIBUTE_NODE) - n = fprintf(of, "\""); - else if (!b && np->type == XML_ELEMENT_NODE) - n = fprintf(of, "", np->name); - - b = CheckDocument(of, np->next); - return false; - } // end of CheckDocument - -/******************************************************************/ -/* Convert node or attribute content to latin characters. */ -/******************************************************************/ -int LIBXMLDOC::Decode(xmlChar *cnt, char *buf, int n) - { - const char *txt = (const char *)cnt; - uint dummy_errors; - uint32 len= copy_and_convert(buf, n, &my_charset_latin1, txt, - strlen(txt), &my_charset_utf8_general_ci, - &dummy_errors); - buf[len]= '\0'; - return 0; - } // end of Decode - -/******************************************************************/ -/* Convert node or attribute content to latin characters. */ -/******************************************************************/ -xmlChar *LIBXMLDOC::Encode(PGLOBAL g, char *txt) - { - const CHARSET_INFO *ics= &my_charset_latin1; // TODO: Field->charset() - const CHARSET_INFO *ocs= &my_charset_utf8_general_ci; - size_t i = strlen(txt); - size_t o = i * ocs->mbmaxlen / ics->mbmaxlen + 1; - char *buf; - if (g) { - buf = (char*)PlugSubAlloc(g, NULL, o); - } else { - o = 1024; - buf = Buf; - } // endif g - uint dummy_errors; - uint32 len= copy_and_convert(buf, o, ocs, - txt, i, ics, - &dummy_errors); - buf[len]= '\0'; - return BAD_CAST buf; - } // end of Encode - -/* ---------------------- class XML2NODE ------------------------ */ - -/******************************************************************/ -/* XML2NODE constructor. */ -/******************************************************************/ -XML2NODE::XML2NODE(PXDOC dp, xmlNodePtr np) : XMLNODE(dp) - { - Docp = ((PXDOC2)dp)->Docp; - Content = NULL; - Nodep = np; - } // end of XML2NODE constructor - -int XML2NODE::GetType(void) - { - if (trace) - htrc("GetType type=%d\n", Nodep->type); - - return Nodep->type; - } // end of GetType - -/******************************************************************/ -/* Return the node class of next sibling of the node. */ -/******************************************************************/ -PXNODE XML2NODE::GetNext(PGLOBAL g) - { - if (!Nodep->next) - Next = NULL; - else if (!Next) - Next = new(g) XML2NODE(Doc, Nodep->next); - - return Next; - } // end of GetNext - -/******************************************************************/ -/* Return the node class of first children of the node. */ -/******************************************************************/ -PXNODE XML2NODE::GetChild(PGLOBAL g) - { - if (!Nodep->children) - Children = NULL; - else if (!Children) - Children = new(g) XML2NODE(Doc, Nodep->children); - - return Children; - } // end of GetChild - -/******************************************************************/ -/* Return the content of a node and subnodes. */ -/******************************************************************/ -char *XML2NODE::GetText(char *buf, int len) - { - if (Content) - xmlFree(Content); - - if ((Content = xmlNodeGetContent(Nodep))) { - int rc = ((PXDOC2)Doc)->Decode(Content, buf, len); - - if (trace) - htrc("GetText buf='%s' len=%d rc=%d\n", buf, len, rc); - - xmlFree(Content); - Content = NULL; - } else - *buf = '\0'; - - return buf; - } // end of GetText - -/******************************************************************/ -/* Set the content of a node. */ -/******************************************************************/ -bool XML2NODE::SetContent(PGLOBAL g, char *txtp, int len) - { - if (trace) - htrc("SetContent %s\n", txtp); - - xmlNodeSetContent(Nodep, ((PXDOC2)Doc)->Encode(g, txtp)); - return false; - } // end of SetContent - -/******************************************************************/ -/* Return a clone of this node. */ -/******************************************************************/ -PXNODE XML2NODE::Clone(PGLOBAL g, PXNODE np) - { - if (np) { - ((PNODE2)np)->Nodep = Nodep; - return np; - } else - return new(g) XML2NODE(Doc, Nodep); - - } // end of Clone - -/******************************************************************/ -/* Return the list of all or matching children that are elements.*/ -/******************************************************************/ -PXLIST XML2NODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp) - { - if (trace) - htrc("GetChildElements %s\n", xp); - - return SelectNodes(g, (xp) ? xp : (char*)"*", lp); - } // end of GetChildElements - -/******************************************************************/ -/* Return the list of nodes verifying the passed Xpath. */ -/******************************************************************/ -PXLIST XML2NODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp) - { - if (trace) - htrc("SelectNodes %s\n", xp); - - xmlNodeSetPtr nl = ((PXDOC2)Doc)->GetNodeList(g, Nodep, xp); - - if (lp) { - ((PLIST2)lp)->Listp = nl; - return lp; - } else - return new(g) XML2NODELIST(Doc, nl); - - } // end of SelectNodes - -/******************************************************************/ -/* Return the first node verifying the passed Xapth. */ -/******************************************************************/ -PXNODE XML2NODE::SelectSingleNode(PGLOBAL g, char *xp, PXNODE np) - { - if (trace) - htrc("SelectSingleNode %s\n", xp); - - xmlNodeSetPtr nl = ((PXDOC2)Doc)->GetNodeList(g, Nodep, xp); - - if (nl && nl->nodeNr) { - if (np) { - ((PNODE2)np)->Nodep = nl->nodeTab[0]; - return np; - } else - return new(g) XML2NODE(Doc, nl->nodeTab[0]); - - } else - return NULL; - - } // end of SelectSingleNode - -/******************************************************************/ -/* Return the node attribute with the specified name. */ -/******************************************************************/ -PXATTR XML2NODE::GetAttribute(PGLOBAL g, char *name, PXATTR ap) - { - if (trace) - htrc("GetAttribute %s\n", name); - - xmlAttrPtr atp = xmlHasProp(Nodep, BAD_CAST name); - - if (atp) { - if (ap) { - ((PATTR2)ap)->Atrp = atp; - ((PATTR2)ap)->Parent = Nodep; - return ap; - } else - return new(g) XML2ATTR(Doc, atp, Nodep); - - } else - return NULL; - - } // end of GetAttribute - -/******************************************************************/ -/* Add a new child node to this node and return it. */ -/******************************************************************/ -PXNODE XML2NODE::AddChildNode(PGLOBAL g, char *name, PXNODE np) - { - char *p, *pn, *pf = NULL; - - if (trace) - htrc("AddChildNode %s\n", name); - - // Is a prefix specified - if ((pn = strchr(name, ':'))) { - pf = name; - *pn++ = '\0'; // Separate name from prefix - } else - pn = name; - - // If name has the format m[n] only m is taken as node name - if ((p = strchr(pn, '['))) - p = BufAlloc(g, pn, p - pn); - else - p = pn; - - xmlNodePtr nop = xmlNewChild(Nodep, NULL, BAD_CAST p, NULL); - - if (!nop) - return NULL; - - if (pf) { - // Prefixed name, is it the default NS prefix? - if (Doc->DefNs && !strcmp(pf, Doc->DefNs)) - pf = NULL; // Default namespace - - xmlNsPtr nsp = xmlSearchNs(Docp, nop, BAD_CAST pf); - - if (!nsp) - nsp = xmlNewNs(nop, NULL, BAD_CAST pf); - - // Set node namespace - nop->ns = nsp; - *(--p) = ':'; // Restore Xname - } else if (Doc->DefNs && xmlSearchNs(Docp, nop, NULL)) - // Not in default namespace - nop->ns = xmlNewNs(nop, BAD_CAST "", NULL); - - if (np) - ((PNODE2)np)->Nodep = nop; - else - np = new(g) XML2NODE(Doc, nop); - - return NewChild(np); - } // end of AddChildNode - -/******************************************************************/ -/* Add a new property to this node and return it. */ -/******************************************************************/ -PXATTR XML2NODE::AddProperty(PGLOBAL g, char *name, PXATTR ap) - { - if (trace) - htrc("AddProperty %s\n", name); - - xmlAttrPtr atp = xmlNewProp(Nodep, BAD_CAST name, NULL); - - if (atp) { - if (ap) { - ((PATTR2)ap)->Atrp = atp; - ((PATTR2)ap)->Parent = Nodep; - return ap; - } else - return new(g) XML2ATTR(Doc, atp, Nodep); - - } else - return NULL; - - } // end of AddProperty - -/******************************************************************/ -/* Add a new text node to this node. */ -/******************************************************************/ -void XML2NODE::AddText(PGLOBAL g, char *txtp) - { - if (trace) - htrc("AddText %s\n", txtp); - - // This is to avoid a blank line when inserting a new line - xmlNodePtr np = xmlGetLastChild(Nodep); - - if (np && np->type == XML_TEXT_NODE) { - xmlUnlinkNode(np); - xmlFreeNode(np); - } // endif type - - // Add the new text - xmlAddChild(Nodep, xmlNewText(BAD_CAST txtp)); - } // end of AddText - -/******************************************************************/ -/* Remove a child node from this node. */ -/******************************************************************/ -void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp) - { - xmlNodePtr np = ((PNODE2)dnp)->Nodep; - xmlNodePtr text = np->next; - - // This is specific to row nodes - if (text && text->type == XML_TEXT_NODE) { - xmlUnlinkNode(text); - xmlFreeNode(text); - } // endif type - - xmlUnlinkNode(np); - xmlFreeNode(np); - Delete(dnp); - } // end of DeleteChild - -/* -------------------- class XML2NODELIST ---------------------- */ - -/******************************************************************/ -/* XML2NODELIST constructor. */ -/******************************************************************/ -XML2NODELIST::XML2NODELIST(PXDOC dp, xmlNodeSetPtr lp) - : XMLNODELIST(dp) - { - Listp = lp; - } // end of XML2NODELIST constructor - -/******************************************************************/ -/* Return the length of the list. */ -/******************************************************************/ -int XML2NODELIST::GetLength(void) - { - return (Listp) ? Listp->nodeNr : 0; - } // end of GetLength - -/******************************************************************/ -/* Return the nth element of the list. */ -/******************************************************************/ -PXNODE XML2NODELIST::GetItem(PGLOBAL g, int n, PXNODE np) - { - if (trace) - htrc("GetItem %d\n", n); - - if (!Listp || Listp->nodeNr <= n) - return NULL; - - if (np) { - ((PNODE2)np)->Nodep = Listp->nodeTab[n]; - return np; - } else - return new(g) XML2NODE(Doc, Listp->nodeTab[n]); - - } // end of GetItem - -/* ---------------------- class XML2ATTR ------------------------ */ - -/******************************************************************/ -/* XML2ATTR constructor. */ -/******************************************************************/ -XML2ATTR::XML2ATTR(PXDOC dp, xmlAttrPtr ap, xmlNodePtr np) - : XMLATTRIBUTE(dp) - { - Atrp = ap; - Parent = np; - } // end of XML2ATTR constructor - -/******************************************************************/ -/* Set the content of an attribute. */ -/******************************************************************/ -bool XML2ATTR::SetText(PGLOBAL g, char *txtp, int len) - { - if (trace) - htrc("SetText %s\n", txtp); - - xmlSetProp(Parent, Atrp->name, ((PXDOC2)Doc)->Encode(g, txtp)); - return false; - } // end of SetText +/******************************************************************/ +/* Implementation of XML document processing using libxml2 */ +/* Author: Olivier Bertrand 2007-2013 */ +/******************************************************************/ +#include +#include +#include +#include +#include +#include +//#if defined(WIN32) +//#include +//#else // !WIN32 +#include "my_global.h" +//#endif // !WIN32 + +#if !defined(LIBXML_XPATH_ENABLED) || !defined(LIBXML_SAX1_ENABLED) +#error "XPath not supported" +#endif + +#include "global.h" +#include "plgdbsem.h" +#include "xobject.h" +#include "libdoc.h" + +#include "sql_string.h" + +extern "C" { +extern char version[]; +extern int trace; +} // "C" + +/******************************************************************/ +/* Return a LIBXMLDOC as a XMLDOC. */ +/******************************************************************/ +PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf, + char *enc, PFBLOCK fp) + { + return (PXDOC) new(g) LIBXMLDOC(nsl, nsdf, enc, fp); + } // end of GetLibxmlDoc + +/******************************************************************/ +/* XML library initialization function. */ +/******************************************************************/ +void XmlInitParserLib(void) + { + xmlInitParser(); + } // end of XmlInitParserLib + +/******************************************************************/ +/* XML library cleanup function. */ +/******************************************************************/ +void XmlCleanupParserLib(void) + { + xmlCleanupParser(); + xmlMemoryDump(); + } // end of XmlCleanupParserLib + +/******************************************************************/ +/* Close a loaded libxml2 XML file. */ +/******************************************************************/ +void CloseXML2File(PGLOBAL g, PFBLOCK fp, bool all) + { + PX2BLOCK xp = (PX2BLOCK)fp; + + if (xp && xp->Count > 1 && !all) { + xp->Count--; + } else if (xp && xp->Count > 0) { + xmlFreeDoc(xp->Docp); + xp->Count = 0; + } // endif + + } // end of CloseXML2File + +/* ---------------------- class LIBXMLDOC ----------------------- */ + +/******************************************************************/ +/* LIBXMLDOC constructor. */ +/******************************************************************/ +LIBXMLDOC::LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp) + : XMLDOCUMENT(nsl, nsdf, enc) + { + assert (!fp || fp->Type == TYPE_FB_XML2); + Docp = (fp) ? ((PX2BLOCK)fp)->Docp : NULL; + Nlist = NULL; + Ctxp = NULL; + Xop = NULL; + } // end of LIBXMLDOC constructor + +/******************************************************************/ +/* Initialize XML parser and check library compatibility. */ +/******************************************************************/ +bool LIBXMLDOC::Initialize(PGLOBAL g) + { +//int n = xmlKeepBlanksDefault(0); + return MakeNSlist(g); + } // end of Initialize + +/******************************************************************/ +/* Parse the XML file and construct node tree in memory. */ +/******************************************************************/ +bool LIBXMLDOC::ParseFile(char *fn) + { + if ((Docp = xmlParseFile(fn))) { + if (Docp->encoding) + Encoding = (char*)Docp->encoding; + + return false; + } else + return true; + + } // end of ParseFile + +/******************************************************************/ +/* Create or reuse an Xblock for this document. */ +/******************************************************************/ +PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn) + { + PDBUSER dup = (PDBUSER)g->Activityp->Aptr; + PX2BLOCK xp = (PX2BLOCK)PlugSubAlloc(g, NULL, sizeof(X2BLOCK)); + + memset(xp, 0, sizeof(X2BLOCK)); + xp->Next = (PX2BLOCK)dup->Openlist; + dup->Openlist = (PFBLOCK)xp; + xp->Type = TYPE_FB_XML2; + xp->Fname = (LPCSTR)PlugSubAlloc(g, NULL, strlen(fn) + 1); + strcpy((char*)xp->Fname, fn); + xp->Count = 1; + xp->Length = (m == MODE_READ) ? 1 : 0; + xp->Retcode = rc; + xp->Docp = Docp; +// xp->Ctxp = Ctxp; +// xp->Xop = Xop; + + // Return xp as a fp + return (PFBLOCK)xp; + } // end of LinkXblock + +/******************************************************************/ +/* Construct and add the XML processing instruction node. */ +/******************************************************************/ +bool LIBXMLDOC::NewDoc(PGLOBAL g, char *ver) + { + return ((Docp = xmlNewDoc(BAD_CAST ver)) == NULL); + } // end of NewDoc + +/******************************************************************/ +/* Add a new comment node to the document. */ +/******************************************************************/ +void LIBXMLDOC::AddComment(PGLOBAL g, char *txtp) + { + xmlNodePtr cp = xmlNewDocComment(Docp, BAD_CAST txtp); + xmlAddChild((xmlNodePtr)Docp, cp); + } // end of AddText + +/******************************************************************/ +/* Return the node class of the root of the document. */ +/******************************************************************/ +PXNODE LIBXMLDOC::GetRoot(PGLOBAL g) + { + xmlNodePtr root = xmlDocGetRootElement(Docp); + + if (!root) + return NULL; + + return new(g) XML2NODE(this, root); + } // end of GetRoot + +/******************************************************************/ +/* Create a new root element and return its class node. */ +/******************************************************************/ +PXNODE LIBXMLDOC::NewRoot(PGLOBAL g, char *name) + { + xmlNodePtr root = xmlNewDocNode(Docp, NULL, BAD_CAST name, NULL); + + if (root) { + xmlDocSetRootElement(Docp, root); + return new(g) XML2NODE(this, root); + } else + return NULL; + + } // end of NewRoot + +/******************************************************************/ +/* Return a void XML2NODE node class. */ +/******************************************************************/ +PXNODE LIBXMLDOC::NewPnode(PGLOBAL g, char *name) + { + xmlNodePtr nop; + + if (name) { + nop = xmlNewDocNode(Docp, NULL, BAD_CAST name, NULL); + + if (nop == NULL) + return NULL; + + } else + nop = NULL; + + return new(g) XML2NODE(this, nop); + } // end of NewPnode + +/******************************************************************/ +/* Return a void XML2ATTR node class. */ +/******************************************************************/ +PXATTR LIBXMLDOC::NewPattr(PGLOBAL g) + { + return new(g) XML2ATTR(this, NULL, NULL); + } // end of NewPattr + +/******************************************************************/ +/* Return a void XML2ATTR node class. */ +/******************************************************************/ +PXLIST LIBXMLDOC::NewPlist(PGLOBAL g) + { + return new(g) XML2NODELIST(this, NULL); + } // end of NewPlist + +/******************************************************************/ +/* Dump the node tree to a new XML file. */ +/******************************************************************/ +int LIBXMLDOC::DumpDoc(PGLOBAL g, char *ofn) + { + int rc; + FILE *of; + + if (!(of= global_fopen(g, MSGID_CANNOT_OPEN, ofn, "w"))) + return -1; + +#if 1 + // This function does not crash ( + rc = xmlSaveFormatFileEnc((const char *)ofn, Docp, Encoding, 0); +// rc = xmlDocDump(of, Docp); +#else // 0 + // Until this function is fixed, do the job ourself + xmlNodePtr Rootp; + + // Save the modified document + fprintf(of, "\n", Encoding); + fprintf(of, "\n", version); + + if (!(Rootp = xmlDocGetRootElement(Docp))) + return 1; + + Buf = (char*)PlugSubAlloc(g, NULL, 1024); + rc = iconv_close(Cd2); + Cd2 = iconv_open(Encoding, "UTF-8"); + rc = CheckDocument(of, Rootp); +#endif // 0 + + fclose(of); + return rc; + } // end of Dump + +/******************************************************************/ +/* Free the document, cleanup the XML library, and */ +/* debug memory for regression tests. */ +/******************************************************************/ +void LIBXMLDOC::CloseDoc(PGLOBAL g, PFBLOCK xp) + { + if (xp && xp->Count == 1) { + if (Xop) + xmlXPathFreeObject(Xop); + + if (Ctxp) + xmlXPathFreeContext(Ctxp); + + } // endif Count + + CloseXML2File(g, xp, false); + } // end of Close + +/******************************************************************/ +/* Evaluate the passed Xpath from the passed context node. */ +/******************************************************************/ +xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp) + { + xmlNodeSetPtr nl; + + if (trace) + htrc("GetNodeList %s np=%p\n", xp, np); + + if (!Ctxp) { + // Init Xpath + xmlXPathInit(); + + // Create xpath evaluation context + if (!(Ctxp = xmlXPathNewContext(Docp))) { + strcpy(g->Message, MSG(XPATH_CNTX_ERR)); + + if (trace) + htrc("Context error: %s\n", g->Message); + + return NULL; + } // endif xpathCtx + + // Register namespaces from list (if any) + for (PNS nsp = Namespaces; nsp; nsp = nsp->Next) + if (xmlXPathRegisterNs(Ctxp, BAD_CAST nsp->Prefix, + BAD_CAST nsp->Uri)) { + sprintf(g->Message, MSG(REGISTER_ERR), nsp->Prefix, nsp->Uri); + + if (trace) + htrc("Ns error: %s\n", g->Message); + + return NULL; + } // endif Registering + + } else + xmlXPathFreeNodeSetList(Xop); // To be checked + + // Set the context to the calling node + Ctxp->node = np; + + // Evaluate table xpath + if (!(Xop = xmlXPathEval(BAD_CAST xp, Ctxp))) { + sprintf(g->Message, MSG(XPATH_EVAL_ERR), xp); + + if (trace) + htrc("Path error: %s\n", g->Message); + + return NULL; + } else + nl = Xop->nodesetval; + + if (trace) + htrc("GetNodeList nl=%p n=%p\n", nl, (nl) ? nl->nodeNr : 0); + + return nl; + } // end of GetNodeList + +/******************************************************************/ +/* CheckDocument: check if the document is ok to dump. */ +/* Currently this does the dumping of the document. */ +/******************************************************************/ +bool LIBXMLDOC::CheckDocument(FILE *of, xmlNodePtr np) + { + int n; + bool b; + + if (!np) + return true; + + if (np->type == XML_ELEMENT_NODE) { + n = fprintf(of, "<%s", np->name); + b = CheckDocument(of, (xmlNodePtr)np->properties); + + if (np->children) + n = fprintf(of, ">"); + else + n = fprintf(of, "/>"); + + } else if (np->type == XML_ATTRIBUTE_NODE) + n = fprintf(of, " %s=\"", np->name); + else if (np->type == XML_TEXT_NODE) + n = fprintf(of, "%s", Encode(NULL, (char*)np->content)); + else if (np->type == XML_COMMENT_NODE) + n = fprintf(of, "%s", Encode(NULL, (char*)np->content)); + + b = CheckDocument(of, np->children); + + if (np->type == XML_ATTRIBUTE_NODE) + n = fprintf(of, "\""); + else if (!b && np->type == XML_ELEMENT_NODE) + n = fprintf(of, "", np->name); + + b = CheckDocument(of, np->next); + return false; + } // end of CheckDocument + +/******************************************************************/ +/* Convert node or attribute content to latin characters. */ +/******************************************************************/ +int LIBXMLDOC::Decode(xmlChar *cnt, char *buf, int n) + { + const char *txt = (const char *)cnt; + uint dummy_errors; + uint32 len= copy_and_convert(buf, n, &my_charset_latin1, txt, + strlen(txt), &my_charset_utf8_general_ci, + &dummy_errors); + buf[len]= '\0'; + return 0; + } // end of Decode + +/******************************************************************/ +/* Convert node or attribute content to latin characters. */ +/******************************************************************/ +xmlChar *LIBXMLDOC::Encode(PGLOBAL g, char *txt) + { + const CHARSET_INFO *ics= &my_charset_latin1; // TODO: Field->charset() + const CHARSET_INFO *ocs= &my_charset_utf8_general_ci; + size_t i = strlen(txt); + size_t o = i * ocs->mbmaxlen / ics->mbmaxlen + 1; + char *buf; + if (g) { + buf = (char*)PlugSubAlloc(g, NULL, o); + } else { + o = 1024; + buf = Buf; + } // endif g + uint dummy_errors; + uint32 len= copy_and_convert(buf, o, ocs, + txt, i, ics, + &dummy_errors); + buf[len]= '\0'; + return BAD_CAST buf; + } // end of Encode + +/* ---------------------- class XML2NODE ------------------------ */ + +/******************************************************************/ +/* XML2NODE constructor. */ +/******************************************************************/ +XML2NODE::XML2NODE(PXDOC dp, xmlNodePtr np) : XMLNODE(dp) + { + Docp = ((PXDOC2)dp)->Docp; + Content = NULL; + Nodep = np; + } // end of XML2NODE constructor + +int XML2NODE::GetType(void) + { + if (trace) + htrc("GetType type=%d\n", Nodep->type); + + return Nodep->type; + } // end of GetType + +/******************************************************************/ +/* Return the node class of next sibling of the node. */ +/******************************************************************/ +PXNODE XML2NODE::GetNext(PGLOBAL g) + { + if (!Nodep->next) + Next = NULL; + else if (!Next) + Next = new(g) XML2NODE(Doc, Nodep->next); + + return Next; + } // end of GetNext + +/******************************************************************/ +/* Return the node class of first children of the node. */ +/******************************************************************/ +PXNODE XML2NODE::GetChild(PGLOBAL g) + { + if (!Nodep->children) + Children = NULL; + else if (!Children) + Children = new(g) XML2NODE(Doc, Nodep->children); + + return Children; + } // end of GetChild + +/******************************************************************/ +/* Return the content of a node and subnodes. */ +/******************************************************************/ +char *XML2NODE::GetText(char *buf, int len) + { + if (Content) + xmlFree(Content); + + if ((Content = xmlNodeGetContent(Nodep))) { + int rc = ((PXDOC2)Doc)->Decode(Content, buf, len); + + if (trace) + htrc("GetText buf='%s' len=%d rc=%d\n", buf, len, rc); + + xmlFree(Content); + Content = NULL; + } else + *buf = '\0'; + + return buf; + } // end of GetText + +/******************************************************************/ +/* Set the content of a node. */ +/******************************************************************/ +bool XML2NODE::SetContent(PGLOBAL g, char *txtp, int len) + { + if (trace) + htrc("SetContent %s\n", txtp); + + xmlNodeSetContent(Nodep, ((PXDOC2)Doc)->Encode(g, txtp)); + return false; + } // end of SetContent + +/******************************************************************/ +/* Return a clone of this node. */ +/******************************************************************/ +PXNODE XML2NODE::Clone(PGLOBAL g, PXNODE np) + { + if (np) { + ((PNODE2)np)->Nodep = Nodep; + return np; + } else + return new(g) XML2NODE(Doc, Nodep); + + } // end of Clone + +/******************************************************************/ +/* Return the list of all or matching children that are elements.*/ +/******************************************************************/ +PXLIST XML2NODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp) + { + if (trace) + htrc("GetChildElements %s\n", xp); + + return SelectNodes(g, (xp) ? xp : (char*)"*", lp); + } // end of GetChildElements + +/******************************************************************/ +/* Return the list of nodes verifying the passed Xpath. */ +/******************************************************************/ +PXLIST XML2NODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp) + { + if (trace) + htrc("SelectNodes %s\n", xp); + + xmlNodeSetPtr nl = ((PXDOC2)Doc)->GetNodeList(g, Nodep, xp); + + if (lp) { + ((PLIST2)lp)->Listp = nl; + return lp; + } else + return new(g) XML2NODELIST(Doc, nl); + + } // end of SelectNodes + +/******************************************************************/ +/* Return the first node verifying the passed Xapth. */ +/******************************************************************/ +PXNODE XML2NODE::SelectSingleNode(PGLOBAL g, char *xp, PXNODE np) + { + if (trace) + htrc("SelectSingleNode %s\n", xp); + + xmlNodeSetPtr nl = ((PXDOC2)Doc)->GetNodeList(g, Nodep, xp); + + if (nl && nl->nodeNr) { + if (np) { + ((PNODE2)np)->Nodep = nl->nodeTab[0]; + return np; + } else + return new(g) XML2NODE(Doc, nl->nodeTab[0]); + + } else + return NULL; + + } // end of SelectSingleNode + +/******************************************************************/ +/* Return the node attribute with the specified name. */ +/******************************************************************/ +PXATTR XML2NODE::GetAttribute(PGLOBAL g, char *name, PXATTR ap) + { + if (trace) + htrc("GetAttribute %s\n", name); + + xmlAttrPtr atp = xmlHasProp(Nodep, BAD_CAST name); + + if (atp) { + if (ap) { + ((PATTR2)ap)->Atrp = atp; + ((PATTR2)ap)->Parent = Nodep; + return ap; + } else + return new(g) XML2ATTR(Doc, atp, Nodep); + + } else + return NULL; + + } // end of GetAttribute + +/******************************************************************/ +/* Add a new child node to this node and return it. */ +/******************************************************************/ +PXNODE XML2NODE::AddChildNode(PGLOBAL g, char *name, PXNODE np) + { + char *p, *pn, *pf = NULL; + + if (trace) + htrc("AddChildNode %s\n", name); + + // Is a prefix specified + if ((pn = strchr(name, ':'))) { + pf = name; + *pn++ = '\0'; // Separate name from prefix + } else + pn = name; + + // If name has the format m[n] only m is taken as node name + if ((p = strchr(pn, '['))) + p = BufAlloc(g, pn, p - pn); + else + p = pn; + + xmlNodePtr nop = xmlNewChild(Nodep, NULL, BAD_CAST p, NULL); + + if (!nop) + return NULL; + + if (pf) { + // Prefixed name, is it the default NS prefix? + if (Doc->DefNs && !strcmp(pf, Doc->DefNs)) + pf = NULL; // Default namespace + + xmlNsPtr nsp = xmlSearchNs(Docp, nop, BAD_CAST pf); + + if (!nsp) + nsp = xmlNewNs(nop, NULL, BAD_CAST pf); + + // Set node namespace + nop->ns = nsp; + *(--p) = ':'; // Restore Xname + } else if (Doc->DefNs && xmlSearchNs(Docp, nop, NULL)) + // Not in default namespace + nop->ns = xmlNewNs(nop, BAD_CAST "", NULL); + + if (np) + ((PNODE2)np)->Nodep = nop; + else + np = new(g) XML2NODE(Doc, nop); + + return NewChild(np); + } // end of AddChildNode + +/******************************************************************/ +/* Add a new property to this node and return it. */ +/******************************************************************/ +PXATTR XML2NODE::AddProperty(PGLOBAL g, char *name, PXATTR ap) + { + if (trace) + htrc("AddProperty %s\n", name); + + xmlAttrPtr atp = xmlNewProp(Nodep, BAD_CAST name, NULL); + + if (atp) { + if (ap) { + ((PATTR2)ap)->Atrp = atp; + ((PATTR2)ap)->Parent = Nodep; + return ap; + } else + return new(g) XML2ATTR(Doc, atp, Nodep); + + } else + return NULL; + + } // end of AddProperty + +/******************************************************************/ +/* Add a new text node to this node. */ +/******************************************************************/ +void XML2NODE::AddText(PGLOBAL g, char *txtp) + { + if (trace) + htrc("AddText %s\n", txtp); + + // This is to avoid a blank line when inserting a new line + xmlNodePtr np = xmlGetLastChild(Nodep); + + if (np && np->type == XML_TEXT_NODE) { + xmlUnlinkNode(np); + xmlFreeNode(np); + } // endif type + + // Add the new text + xmlAddChild(Nodep, xmlNewText(BAD_CAST txtp)); + } // end of AddText + +/******************************************************************/ +/* Remove a child node from this node. */ +/******************************************************************/ +void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp) + { + xmlNodePtr np = ((PNODE2)dnp)->Nodep; + xmlNodePtr text = np->next; + + // This is specific to row nodes + if (text && text->type == XML_TEXT_NODE) { + xmlUnlinkNode(text); + xmlFreeNode(text); + } // endif type + + xmlUnlinkNode(np); + xmlFreeNode(np); + Delete(dnp); + } // end of DeleteChild + +/* -------------------- class XML2NODELIST ---------------------- */ + +/******************************************************************/ +/* XML2NODELIST constructor. */ +/******************************************************************/ +XML2NODELIST::XML2NODELIST(PXDOC dp, xmlNodeSetPtr lp) + : XMLNODELIST(dp) + { + Listp = lp; + } // end of XML2NODELIST constructor + +/******************************************************************/ +/* Return the length of the list. */ +/******************************************************************/ +int XML2NODELIST::GetLength(void) + { + return (Listp) ? Listp->nodeNr : 0; + } // end of GetLength + +/******************************************************************/ +/* Return the nth element of the list. */ +/******************************************************************/ +PXNODE XML2NODELIST::GetItem(PGLOBAL g, int n, PXNODE np) + { + if (trace) + htrc("GetItem %d\n", n); + + if (!Listp || Listp->nodeNr <= n) + return NULL; + + if (np) { + ((PNODE2)np)->Nodep = Listp->nodeTab[n]; + return np; + } else + return new(g) XML2NODE(Doc, Listp->nodeTab[n]); + + } // end of GetItem + +/* ---------------------- class XML2ATTR ------------------------ */ + +/******************************************************************/ +/* XML2ATTR constructor. */ +/******************************************************************/ +XML2ATTR::XML2ATTR(PXDOC dp, xmlAttrPtr ap, xmlNodePtr np) + : XMLATTRIBUTE(dp) + { + Atrp = ap; + Parent = np; + } // end of XML2ATTR constructor + +/******************************************************************/ +/* Set the content of an attribute. */ +/******************************************************************/ +bool XML2ATTR::SetText(PGLOBAL g, char *txtp, int len) + { + if (trace) + htrc("SetText %s\n", txtp); + + xmlSetProp(Parent, Atrp->name, ((PXDOC2)Doc)->Encode(g, txtp)); + return false; + } // end of SetText -- cgit v1.2.1