mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +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
 |