mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 10:56:12 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1249 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1249 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /******************************************************************/
 | |
| /*  Implementation of XML document processing using libxml2       */
 | |
| /*  Author: Olivier Bertrand                2007-2016             */
 | |
| /******************************************************************/
 | |
| #include "my_global.h"
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| #include <libxml/parser.h>
 | |
| #include <libxml/tree.h>
 | |
| #include <libxml/xpath.h>
 | |
| #include <libxml/xpathInternals.h>
 | |
| #include <libxml/catalog.h>
 | |
| #include <libxml/xmlschemastypes.h>
 | |
| #include <libxml/relaxng.h>
 | |
| 
 | |
| #if !defined(LIBXML_TREE_ENABLED) || !defined(LIBXML_OUTPUT_ENABLED)
 | |
| #error "tree support not compiled in"
 | |
| #endif
 | |
| 
 | |
| #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"
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Declaration of XML document processing using libxml2          */
 | |
| /*  Author: Olivier Bertrand                2007-2012             */
 | |
| /******************************************************************/
 | |
| #include "plgxml.h"
 | |
| 
 | |
| typedef class LIBXMLDOC    *PXDOC2;
 | |
| typedef class XML2NODE     *PNODE2;
 | |
| typedef class XML2ATTR     *PATTR2;
 | |
| typedef class XML2NODELIST *PLIST2;
 | |
| 
 | |
| /******************************************************************/
 | |
| /* XML2 block. Must have the same layout than FBLOCK up to Type.  */
 | |
| /******************************************************************/
 | |
| typedef struct _x2block {         /* Loaded XML file block        */
 | |
|   struct _x2block   *Next;
 | |
|   LPCSTR             Fname;       /* Point on file name           */
 | |
|   size_t             Length;      /* Used to tell if read mode    */
 | |
|   short              Count;       /* Nb of times file is used     */
 | |
|   short              Type;        /* TYPE_FB_XML                  */
 | |
|   int                Retcode;     /* Return code from Load        */
 | |
|   xmlDocPtr          Docp;        /* Document interface pointer   */
 | |
|   } X2BLOCK, *PX2BLOCK;
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Declaration of libxml2 document.                              */
 | |
| /******************************************************************/
 | |
| class LIBXMLDOC : public XMLDOCUMENT {
 | |
|   friend class XML2NODE;
 | |
|   friend class XML2ATTR;
 | |
|  public:
 | |
|   // Constructor
 | |
|   LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp);
 | |
| 
 | |
|   // Properties
 | |
|   short  GetDocType(void) override {return TYPE_FB_XML2;}
 | |
|   void  *GetDocPtr(void) override {return Docp;}
 | |
|   void   SetNofree(bool b) override {Nofreelist = b;}
 | |
| 
 | |
|   // Methods
 | |
| 	bool    Initialize(PGLOBAL g, PCSZ entry, bool zipped) override;
 | |
|   bool    ParseFile(PGLOBAL g, char *fn) override;
 | |
|   bool    NewDoc(PGLOBAL g, PCSZ ver) override;
 | |
|   void    AddComment(PGLOBAL g, char *com) override;
 | |
|   PXNODE  GetRoot(PGLOBAL g) override;
 | |
|   PXNODE  NewRoot(PGLOBAL g, char *name) override;
 | |
|   PXNODE  NewPnode(PGLOBAL g, char *name) override;
 | |
|   PXATTR  NewPattr(PGLOBAL g) override;
 | |
|   PXLIST  NewPlist(PGLOBAL g) override;
 | |
|   int     DumpDoc(PGLOBAL g, char *ofn) override;
 | |
|   void    CloseDoc(PGLOBAL g, PFBLOCK xp) override;
 | |
|   PFBLOCK LinkXblock(PGLOBAL g, MODE m, int rc, char *fn) override;
 | |
| 
 | |
|  protected:
 | |
| //        bool     CheckDocument(FILE *of, xmlNodePtr np);
 | |
|           xmlNodeSetPtr GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp);
 | |
|           int      Decode(xmlChar *cnt, char *buf, int n);
 | |
|           xmlChar *Encode(PGLOBAL g, char *txt);
 | |
| 
 | |
|   // Members
 | |
|   xmlDocPtr          Docp;
 | |
|   xmlNodeSetPtr      Nlist;
 | |
|   xmlXPathContextPtr Ctxp;
 | |
|   xmlXPathObjectPtr  Xop;
 | |
|   xmlXPathObjectPtr  NlXop;
 | |
|   char              *Buf;                  // Temporary
 | |
|   bool               Nofreelist;
 | |
| }; // end of class LIBXMLDOC
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Declaration of libxml2 node.                                  */
 | |
| /******************************************************************/
 | |
| class XML2NODE : public XMLNODE {
 | |
|   friend class LIBXMLDOC;
 | |
|   friend class XML2NODELIST;
 | |
|  public:
 | |
|   // Properties
 | |
|   char  *GetName(PGLOBAL g) override {return (char*)Nodep->name;}
 | |
|   int    GetType(void) override;
 | |
|   PXNODE GetNext(PGLOBAL g) override;
 | |
|   PXNODE GetChild(PGLOBAL g) override;
 | |
| 
 | |
|   // Methods
 | |
|   RCODE  GetContent(PGLOBAL g, char *buf, int len) override;
 | |
|   bool   SetContent(PGLOBAL g, char *txtp, int len) override;
 | |
|   PXNODE Clone(PGLOBAL g, PXNODE np) override;
 | |
|   PXLIST GetChildElements(PGLOBAL g, char *xp, PXLIST lp) override;
 | |
|   PXLIST SelectNodes(PGLOBAL g, char *xp, PXLIST lp) override;
 | |
|   PXNODE SelectSingleNode(PGLOBAL g, char *xp, PXNODE np) override;
 | |
|   PXATTR GetAttribute(PGLOBAL g, char *name, PXATTR ap) override;
 | |
|   PXNODE AddChildNode(PGLOBAL g, PCSZ name, PXNODE np) override;
 | |
|   PXATTR AddProperty(PGLOBAL g, char *name, PXATTR ap) override;
 | |
|   void   AddText(PGLOBAL g, PCSZ txtp) override;
 | |
|   void   DeleteChild(PGLOBAL g, PXNODE dnp) override;
 | |
| 
 | |
|  protected:
 | |
|   // Constructor
 | |
|   XML2NODE(PXDOC dp, xmlNodePtr np);
 | |
| 
 | |
|   // Members
 | |
|   xmlDocPtr  Docp;
 | |
|   xmlChar   *Content;
 | |
|   xmlNodePtr Nodep;
 | |
| }; // end of class XML2NODE
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Declaration of libxml2 node list.                             */
 | |
| /******************************************************************/
 | |
| class XML2NODELIST : public XMLNODELIST {
 | |
|   friend class LIBXMLDOC;
 | |
|   friend class XML2NODE;
 | |
|  public:
 | |
|   // Methods
 | |
|   int    GetLength(void) override;
 | |
|   PXNODE GetItem(PGLOBAL g, int n, PXNODE np) override;
 | |
|   bool   DropItem(PGLOBAL g, int n) override;
 | |
| 
 | |
|  protected:
 | |
|   // Constructor
 | |
|   XML2NODELIST(PXDOC dp, xmlNodeSetPtr lp);
 | |
| 
 | |
|   // Members
 | |
|   xmlNodeSetPtr Listp;
 | |
| }; // end of class XML2NODELIST
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Declaration of libxml2 attribute.                             */
 | |
| /******************************************************************/
 | |
| class XML2ATTR : public XMLATTRIBUTE {
 | |
|   friend class LIBXMLDOC;
 | |
|   friend class XML2NODE;
 | |
|  public:
 | |
|   // Properties
 | |
|   char  *GetName(PGLOBAL g) override {return (char*)Atrp->name;}
 | |
|   PXATTR GetNext(PGLOBAL g) override;
 | |
| 
 | |
|   // Methods
 | |
|   RCODE  GetText(PGLOBAL g, char *bufp, int len) override;
 | |
|   bool   SetText(PGLOBAL g, char *txtp, int len) override;
 | |
| 
 | |
|  protected:
 | |
|   // Constructor
 | |
|   XML2ATTR(PXDOC dp, xmlAttrPtr ap, xmlNodePtr np);
 | |
| 
 | |
|   // Members
 | |
|   xmlAttrPtr Atrp;
 | |
|   xmlNodePtr Parent;
 | |
| }; // end of class XML2ATTR
 | |
| 
 | |
| 
 | |
| 
 | |
| extern "C" {
 | |
| extern char version[];
 | |
| } //   "C"
 | |
| 
 | |
| #if defined(MEMORY_TRACE)
 | |
| static int  m = 0;
 | |
| static char s[500];
 | |
| /**************************************************************************/
 | |
| /*  Tracing output function.                                              */
 | |
| /**************************************************************************/
 | |
| void xtrc(char const *fmt, ...)
 | |
|   {
 | |
|   va_list ap;
 | |
|   va_start (ap, fmt);
 | |
| 																							;
 | |
| //vfprintf(stderr, fmt, ap);
 | |
|   vsprintf(s, fmt, ap);
 | |
|   if (s[strlen(s)-1] == '\n')
 | |
|       s[strlen(s)-1] = 0;
 | |
|   va_end (ap);
 | |
|   } // end of htrc
 | |
| 
 | |
| static xmlFreeFunc Free; 
 | |
| static xmlMallocFunc Malloc;
 | |
| static xmlMallocFunc MallocA; 
 | |
| static xmlReallocFunc Realloc; 
 | |
| static xmlStrdupFunc Strdup;
 | |
| 
 | |
| void xmlMyFree(void *mem)
 | |
| {
 | |
|   if (trace(1)) { 
 | |
|     htrc("%.4d Freeing          at %p   %-.256s\n", ++m, mem, s);
 | |
|     *s = 0;
 | |
|     } // endif trace
 | |
|   Free(mem);
 | |
| } // end of xmlMyFree
 | |
| 
 | |
| void *xmlMyMalloc(size_t size)
 | |
| {
 | |
|   void *p = Malloc(size);
 | |
|   if (trace(1)) { 
 | |
|     htrc("%.4d Allocating %.5d at %p   %-.256s\n", ++m, size, p, s);
 | |
|     *s = 0;
 | |
|     } // endif trace
 | |
|   return p;
 | |
| } // end of xmlMyMalloc
 | |
| 
 | |
| void *xmlMyMallocAtomic(size_t size)
 | |
| {
 | |
|   void *p = MallocA(size);
 | |
|   if (trace(1)) { 
 | |
|     htrc("%.4d Atom alloc %.5d at %p   %-.256s\n", ++m, size, p, s);
 | |
|     *s = 0;
 | |
|     } // endif trace
 | |
|   return p;
 | |
| } // end of xmlMyMallocAtomic
 | |
| 
 | |
| void *xmlMyRealloc(void *mem, size_t size)
 | |
| {
 | |
|   void *p = Realloc(mem, size);
 | |
|   if (trace(1)) { 
 | |
|     htrc("%.4d ReAlloc    %.5d to %p from %p   %-.256s\n", ++m, size, p, mem, s);
 | |
|     *s = 0;
 | |
|     } // endif trace
 | |
|   return p;
 | |
| } // end of xmlMyRealloc
 | |
| 
 | |
| char *xmlMyStrdup(const char *str)
 | |
| {
 | |
|   char *p = Strdup(str);
 | |
|   if (trace(1)) { 
 | |
|     htrc("%.4d Duplicating      to %p from %p %-.256s   %-.256s\n", ++m, p, str, str, s);
 | |
|     *s = 0;
 | |
|     } // endif trace
 | |
|   return p;
 | |
| } // end of xmlMyStrdup
 | |
| #define htrc xtrc
 | |
| #endif   // MEMORY_TRACE
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  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)
 | |
|   {
 | |
| #if defined(MEMORY_TRACE)
 | |
| int	rc = xmlGcMemGet(&Free, &Malloc, &MallocA, &Realloc, &Strdup);
 | |
| 
 | |
| if (!rc)
 | |
|   rc = xmlGcMemSetup(xmlMyFree, 
 | |
|                      xmlMyMalloc, 
 | |
|                      xmlMyMallocAtomic,
 | |
|                      xmlMyRealloc,
 | |
|                      xmlMyStrdup); 
 | |
| 
 | |
| #endif   // MEMORY_TRACE
 | |
|   xmlInitParser();
 | |
|   } // end of XmlInitParserLib
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  XML library cleanup function.                                 */
 | |
| /******************************************************************/
 | |
| void XmlCleanupParserLib(void)
 | |
|   {
 | |
|   } // end of XmlCleanupParserLib
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Close a loaded libxml2 XML file.                              */
 | |
| /******************************************************************/
 | |
| void CloseXML2File(PGLOBAL g, PFBLOCK fp, bool all)
 | |
|   {
 | |
|   PX2BLOCK xp = (PX2BLOCK)fp;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("CloseXML2File: xp=%p count=%d\n", xp, (xp) ? xp->Count : 0);
 | |
| 
 | |
|   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;
 | |
|   NlXop = NULL;
 | |
|   Buf = NULL;
 | |
|   Nofreelist = false;
 | |
|   } // end of LIBXMLDOC constructor
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Initialize XML parser and check library compatibility.        */
 | |
| /******************************************************************/
 | |
| bool LIBXMLDOC::Initialize(PGLOBAL g, PCSZ entry, bool zipped)
 | |
| {
 | |
| 	if (zipped && InitZip(g, entry))
 | |
| 		return true;
 | |
| 
 | |
|   xmlKeepBlanksDefault(1);
 | |
|   return MakeNSlist(g);
 | |
| } // end of Initialize
 | |
| 
 | |
| /******************************************************************/
 | |
| /* Parse the XML file and construct node tree in memory.          */
 | |
| /******************************************************************/
 | |
| bool LIBXMLDOC::ParseFile(PGLOBAL g, char *fn)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("ParseFile\n");
 | |
| 
 | |
| 	if (zip) {
 | |
| 		// Parse an in memory document
 | |
| 		char *xdoc = GetMemDoc(g, fn);
 | |
| 
 | |
| 		Docp = (xdoc) ? xmlParseDoc((const xmlChar *)xdoc) : NULL;
 | |
| 	} else
 | |
| 		Docp = xmlParseFile(fn);
 | |
| 
 | |
| 	if (Docp) {
 | |
| 		if (Docp->encoding)
 | |
|       Encoding = (char*)Docp->encoding;
 | |
| 
 | |
|     return false;
 | |
|   } else if (xmlGetLastError())
 | |
|     xmlResetLastError();
 | |
| 
 | |
|   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)PlugDup(g, fn);
 | |
|   xp->Count = 1;
 | |
|   xp->Length = (m == MODE_READ) ? 1 : 0;
 | |
|   xp->Retcode = rc;
 | |
|   xp->Docp = Docp;
 | |
| 
 | |
|   // Return xp as a fp
 | |
|   return (PFBLOCK)xp;
 | |
|   } // end of LinkXblock
 | |
| 
 | |
| /******************************************************************/
 | |
| /* Construct and add the XML processing instruction node.         */
 | |
| /******************************************************************/
 | |
| bool LIBXMLDOC::NewDoc(PGLOBAL g, PCSZ ver)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("NewDoc\n");
 | |
| 
 | |
|   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)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("AddComment: %-.256s\n", 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)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("GetRoot\n");
 | |
| 
 | |
|   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)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("NewRoot: %-.256s\n", 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)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("NewNode: %-.256s\n", 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 = 0;
 | |
|   FILE *of;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("DumpDoc: %-.256s\n", ofn);
 | |
| 
 | |
|   if (!(of= global_fopen(g, MSGID_CANNOT_OPEN, ofn, "w")))
 | |
|     return -1;
 | |
| 
 | |
| #if 1
 | |
|   // This function does not crash (
 | |
|   if (xmlSaveFormatFileEnc((const char *)ofn, Docp, Encoding, 0) < 0) {
 | |
|     const xmlError *err = xmlGetLastError();
 | |
|     strcpy(g->Message, (err) ? err->message : "Error saving XML doc");
 | |
|     xmlResetLastError();
 | |
|     rc = -1;
 | |
|     } // endif Save
 | |
| //  rc = xmlDocDump(of, Docp);
 | |
| #else // 0
 | |
|   // Until this function is fixed, do the job ourself
 | |
|   xmlNodePtr Rootp;
 | |
| 
 | |
|   // Save the modified document
 | |
|   fprintf(of, "<?xml version=\"1.0\" encoding=\"%-.256s\"?>\n", Encoding);
 | |
|   fprintf(of, "<!-- Created by CONNECT %-.256s -->\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 (trace(1))
 | |
|     htrc("CloseDoc: xp=%p count=%d\n", xp, (xp) ? xp->Count : 0);
 | |
| 
 | |
| //if (xp && xp->Count == 1) {
 | |
|   if (xp) {
 | |
|     if (Nlist) {
 | |
|       xmlXPathFreeNodeSet(Nlist);
 | |
| 
 | |
|       if (xmlGetLastError())
 | |
|         xmlResetLastError();
 | |
| 
 | |
|       Nlist = NULL;
 | |
|       } // endif Nlist
 | |
| 
 | |
|     if (Xop) {
 | |
|       xmlXPathFreeObject(Xop);
 | |
| 
 | |
|       if (xmlGetLastError())
 | |
|         xmlResetLastError();
 | |
| 
 | |
|       Xop = NULL;
 | |
|       } // endif Xop
 | |
| 
 | |
|     if (NlXop) {
 | |
|       xmlXPathFreeObject(NlXop);
 | |
| 
 | |
|       if (xmlGetLastError())
 | |
|         xmlResetLastError();
 | |
| 
 | |
|       NlXop = NULL;
 | |
|       } // endif NlXop
 | |
| 
 | |
|     if (Ctxp) {
 | |
|       xmlXPathFreeContext(Ctxp);
 | |
| 
 | |
|       if (xmlGetLastError())
 | |
|         xmlResetLastError();
 | |
| 
 | |
|       Ctxp = NULL;
 | |
|       } // endif Ctxp
 | |
| 
 | |
|     } // endif xp
 | |
| 
 | |
|   CloseXML2File(g, xp, false);
 | |
| 	CloseZip();
 | |
|   } // end of Close
 | |
| 
 | |
| /******************************************************************/
 | |
| /* Evaluate the passed Xpath from the passed context node.        */
 | |
| /******************************************************************/
 | |
| xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp)
 | |
|   {
 | |
|   const xmlError *xerr;
 | |
|   xmlNodeSetPtr nl;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("GetNodeList: %-.256s np=%p\n", xp, np);
 | |
| 
 | |
|   if (!Ctxp) {
 | |
|     // Init Xpath
 | |
|     if (trace(1))
 | |
|       htrc("Calling xmlPathInit\n");
 | |
| 
 | |
|     xmlInitParser();
 | |
| 
 | |
|     if (trace(1))
 | |
|       htrc("Calling xmlXPathNewContext Docp=%p\n", Docp);
 | |
| 
 | |
|     // Create xpath evaluation context
 | |
|     if (!(Ctxp = xmlXPathNewContext(Docp))) {
 | |
|       strcpy(g->Message, MSG(XPATH_CNTX_ERR));
 | |
| 
 | |
|       if (trace(1))
 | |
|         htrc("Context error: %-.256s\n", g->Message);
 | |
| 
 | |
|       return NULL;
 | |
|       } // endif xpathCtx
 | |
| 
 | |
|     // Register namespaces from list (if any)
 | |
|     for (PNS nsp = Namespaces; nsp; nsp = nsp->Next) {
 | |
|       if (trace(1))
 | |
|         htrc("Calling xmlXPathRegisterNs Prefix=%-.256s Uri=%-.512s\n", 
 | |
|              nsp->Prefix, nsp->Uri);
 | |
| 
 | |
|       if (xmlXPathRegisterNs(Ctxp, BAD_CAST nsp->Prefix,
 | |
|                                    BAD_CAST nsp->Uri)) {
 | |
|         snprintf(g->Message, sizeof(g->Message), MSG(REGISTER_ERR), nsp->Prefix, nsp->Uri);
 | |
| 
 | |
|         if (trace(1))
 | |
|           htrc("Ns error: %-.256s\n", g->Message);
 | |
| 
 | |
|         return NULL;
 | |
|         } // endif Registering
 | |
| 
 | |
|       } // endfor nsp
 | |
| 
 | |
|     } // endif Ctxp
 | |
| 
 | |
|   if (Xop) {
 | |
|     if (trace(1))
 | |
|       htrc("Calling xmlXPathFreeNodeSetList Xop=%p NOFREE=%d\n", 
 | |
|                                             Xop, Nofreelist);
 | |
| 
 | |
|     if (Nofreelist) {
 | |
|       // Making Nlist that must not be freed yet
 | |
| //    xmlXPathFreeNodeSetList(Xop);       // Caused memory leak
 | |
|       assert(!NlXop);
 | |
|       NlXop = Xop;                        // Freed on closing
 | |
|       Nofreelist = false;
 | |
|     } else
 | |
|       xmlXPathFreeObject(Xop);            // Caused node not found
 | |
| 
 | |
|     if ((xerr = xmlGetLastError())) {
 | |
|       strcpy(g->Message, xerr->message);
 | |
|       xmlResetLastError();
 | |
|       return NULL;
 | |
|       } // endif xerr
 | |
| 
 | |
|     } // endif Xop
 | |
| 
 | |
|   // Set the context to the calling node
 | |
|   Ctxp->node = np;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("Calling xmlXPathEval %-.256s Ctxp=%p\n", xp, Ctxp);
 | |
| 
 | |
|   // Evaluate table xpath
 | |
|   if (!(Xop = xmlXPathEval(BAD_CAST xp, Ctxp))) {
 | |
|     snprintf(g->Message, sizeof(g->Message), MSG(XPATH_EVAL_ERR), xp);
 | |
| 
 | |
|     if (trace(1))
 | |
|       htrc("Path error: %-.256s\n", g->Message);
 | |
| 
 | |
|     return NULL;
 | |
|   } else
 | |
|     nl = Xop->nodesetval;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("GetNodeList nl=%p n=%p\n", nl, (nl) ? nl->nodeNr : 0);
 | |
| 
 | |
|   return nl;
 | |
|   } // end of GetNodeList
 | |
| 
 | |
| #if 0                                // Not used anymore
 | |
| /******************************************************************/
 | |
| /*  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, "</%s>", 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_utf8mb3_general_ci, txt,
 | |
|                                strlen(txt), &my_charset_utf8mb3_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_utf8mb3_general_ci;
 | |
|   const CHARSET_INFO *ocs= &my_charset_utf8mb3_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
 | |
| #endif // 0
 | |
| 
 | |
| /* ---------------------- 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(1))
 | |
|     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 (trace(1))
 | |
|     htrc("GetNext\n");
 | |
| 
 | |
|   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 (trace(1))
 | |
|     htrc("GetChild\n");
 | |
| 
 | |
|   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.                    */
 | |
| /******************************************************************/
 | |
| RCODE XML2NODE::GetContent(PGLOBAL g, char *buf, int len)
 | |
|   {
 | |
|   RCODE rc = RC_OK;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("GetContent\n");
 | |
| 
 | |
|   if (Content)
 | |
|     xmlFree(Content);
 | |
| 
 | |
|   if ((Content = xmlNodeGetContent(Nodep))) {
 | |
|     char *p1 = (char*)Content, *p2 = buf;
 | |
|     bool  b = false;
 | |
| 
 | |
|     // Copy content eliminating extra characters
 | |
|     for (; *p1; p1++)
 | |
|       if ((p2 - buf) < len) {
 | |
|         if (strchr(" \t\r\n", *p1)) {
 | |
|           if (b) {
 | |
|             // This to have one blank between sub-nodes
 | |
|             *p2++ = ' ';
 | |
|             b = false;
 | |
|             }  // endif b
 | |
|     
 | |
|         } else {
 | |
|           *p2++ = *p1;
 | |
|           b = true;
 | |
|         } // endif p1
 | |
| 
 | |
|       } else {
 | |
|         snprintf(g->Message, sizeof(g->Message), "Truncated %-.256s content", Nodep->name);
 | |
|         rc = RC_INFO;
 | |
|       } // endif len
 | |
| 
 | |
|     *p2 = 0;
 | |
| 
 | |
|     if (trace(1))
 | |
|       htrc("GetText buf='%-.256s' len=%d\n", buf, len);
 | |
| 
 | |
|     xmlFree(Content);
 | |
|     Content = NULL;
 | |
|   } else
 | |
|     *buf = '\0';
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("GetContent: %-.256s\n", buf);
 | |
| 
 | |
|   return rc;
 | |
|   } // end of GetContent
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Set the content of a node.                                    */
 | |
| /******************************************************************/
 | |
| bool XML2NODE::SetContent(PGLOBAL g, char *txtp, int len)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("SetContent: %-.256s\n", txtp);
 | |
| 
 | |
|   xmlChar *buf = xmlEncodeEntitiesReentrant(Docp, BAD_CAST txtp);
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("SetContent: %-.256s -> %-.256s\n", txtp, buf);
 | |
| 
 | |
|   xmlNodeSetContent(Nodep, buf);
 | |
|   xmlFree(buf);
 | |
|   return false;
 | |
|   } // end of SetContent
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Return a clone of this node.                                  */
 | |
| /******************************************************************/
 | |
| PXNODE XML2NODE::Clone(PGLOBAL g, PXNODE np)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("Clone: np=%p\n", 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(1))
 | |
|     htrc("GetChildElements: %-.256s\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(1))
 | |
|     htrc("SelectNodes: %-.256s\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(1))
 | |
|     htrc("SelectSingleNode: %-.256s\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)
 | |
|   {
 | |
|   xmlAttrPtr atp;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("GetAttribute: %-.256s\n", SVP(name));
 | |
| 
 | |
|   if (name)
 | |
|     atp = xmlHasProp(Nodep, BAD_CAST name);
 | |
|   else
 | |
|     atp = Nodep->properties;
 | |
| 
 | |
| 
 | |
|   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, PCSZ name, PXNODE np)
 | |
|   {
 | |
|   char *p, *pn, *pf = NULL, *nmp = PlugDup(g, name);
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("AddChildNode: %-.256s\n", name);
 | |
| 
 | |
|   // Is a prefix specified
 | |
|   if ((pn = strchr(nmp, ':'))) {
 | |
|     pf = nmp;
 | |
|     *pn++ = '\0';                    // Separate name from prefix
 | |
|   } else
 | |
|     pn = nmp;
 | |
| 
 | |
|   // If name has the format m[n] only m is taken as node name
 | |
|   if ((p = strchr(pn, '[')))
 | |
|     p = BufAlloc(g, pn, int(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(1))
 | |
|     htrc("AddProperty: %-.256s\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, PCSZ txtp)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("AddText: %-.256s\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)
 | |
|   {
 | |
|   const xmlError *xerr;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("DeleteChild: node=%p\n", 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);
 | |
| 
 | |
|     if ((xerr = xmlGetLastError()))
 | |
|       goto err;
 | |
| 
 | |
|     xmlFreeNode(text);
 | |
| 
 | |
|     if ((xerr = xmlGetLastError()))
 | |
|       goto err;
 | |
| 
 | |
|     } // endif type
 | |
| 
 | |
|   xmlUnlinkNode(np);
 | |
| 
 | |
|   if ((xerr = xmlGetLastError()))
 | |
|     goto err;
 | |
| 
 | |
|   xmlFreeNode(np);
 | |
| 
 | |
|   if ((xerr = xmlGetLastError()))
 | |
|     goto err;
 | |
| 
 | |
|   Delete(dnp);
 | |
| 
 | |
|   if ((xerr = xmlGetLastError()))
 | |
|     goto err;
 | |
| 
 | |
|   return;
 | |
| 
 | |
| err:
 | |
|   if (trace(1))
 | |
|     htrc("DeleteChild: errmsg=%-.256s\n", xerr->message);
 | |
| 
 | |
|   xmlResetLastError();
 | |
|   } // 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(1))
 | |
|     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
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Reset the pointer on the deleted item.                        */
 | |
| /******************************************************************/
 | |
| bool XML2NODELIST::DropItem(PGLOBAL g, int n)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("DropItem: n=%d\n", n);
 | |
| 
 | |
|   // We should do something here
 | |
|   if (!Listp || Listp->nodeNr <= n)
 | |
|     return true;
 | |
| 
 | |
|   Listp->nodeTab[n] = NULL;   // This was causing Valgrind warning
 | |
|   return false;
 | |
|   } // end of DropItem
 | |
| 
 | |
| /* ---------------------- class XML2ATTR ------------------------ */
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  XML2ATTR constructor.                                         */
 | |
| /******************************************************************/
 | |
| XML2ATTR::XML2ATTR(PXDOC dp, xmlAttrPtr ap, xmlNodePtr np)
 | |
|         : XMLATTRIBUTE(dp)
 | |
|   {
 | |
|   Atrp = ap;
 | |
|   Parent = np;
 | |
|   } // end of XML2ATTR constructor
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Return the next sibling of the attribute.                     */
 | |
| /******************************************************************/
 | |
| PXATTR XML2ATTR::GetNext(PGLOBAL g)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("Attr GetNext\n");
 | |
| 
 | |
|   if (!Atrp->next)
 | |
|     return NULL;
 | |
|   else
 | |
|     return new(g) XML2ATTR(Doc, Atrp->next, Atrp->parent);
 | |
| 
 | |
|   } // end of GetNext
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Return the text of an attribute.                              */
 | |
| /******************************************************************/
 | |
| RCODE XML2ATTR::GetText(PGLOBAL g, char *buf, int len)
 | |
|   {
 | |
|   RCODE    rc = RC_OK;
 | |
|   xmlChar *txt;
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("GetText\n");
 | |
| 
 | |
|   if ((txt = xmlGetProp(Atrp->parent, Atrp->name))) {
 | |
|     // Copy the text to the buffer
 | |
|     if (strlen((char*)txt) >= (unsigned)len) {
 | |
|       memcpy(buf, txt, len - 1);
 | |
|       buf[len - 1] = 0;
 | |
|       snprintf(g->Message, sizeof(g->Message), "Truncated %-.256s content", Atrp->name);
 | |
|       rc = RC_INFO;
 | |
|     } else
 | |
|       strcpy(buf, (const char*)txt);
 | |
| 
 | |
|     xmlFree(txt);
 | |
|   } else
 | |
|     *buf = '\0';
 | |
| 
 | |
|   if (trace(1))
 | |
|     htrc("GetText: %-.256s\n", buf);
 | |
| 
 | |
|   return rc;
 | |
|   } // end of GetText
 | |
| 
 | |
| /******************************************************************/
 | |
| /*  Set the content of an attribute.                              */
 | |
| /******************************************************************/
 | |
| bool XML2ATTR::SetText(PGLOBAL g, char *txtp, int len)
 | |
|   {
 | |
|   if (trace(1))
 | |
|     htrc("SetText: %-.256s %d\n", txtp, len);
 | |
| 
 | |
|   xmlSetProp(Parent, Atrp->name, BAD_CAST txtp);
 | |
|   return false;
 | |
|   } // end of SetText
 | 
