/*-----------------------------------------------------------------*/
/*! 
  \file scscpxmlnode.c
  \brief  xml node  implementation.
  \author  M. Gastineau 
           Astronomie et Systemes Dynamiques, IMCCE, CNRS, Observatoire de Paris. 

   Copyright, 2008, 2009, 2012, M. Gastineau, IMCCE-CNRS
   email of the author : gastineau@imcce.fr
   
*/
/*-----------------------------------------------------------------*/

/*-----------------------------------------------------------------*/
/* License  of this file :
 This file is "dual-licensed", you have to choose one  of the two licenses 
 below to apply on this file.
 
    CeCILL-C
    	The CeCILL-C license is close to the GNU LGPL.
    	( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
 
 or CeCILL v2.0
      The CeCILL license is compatible with the GNU GPL.
      ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
 

This library is governed by the CeCILL-C or the CeCILL license under 
French law and abiding by the rules of distribution of free software.  
You can  use, modify and/ or redistribute the software under the terms 
of the CeCILL-C or CeCILL license as circulated by CEA, CNRS and INRIA  
at the following URL "http://www.cecill.info". 

As a counterpart to the access to the source code and  rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty  and the software's author,  the holder of the
economic rights,  and the successive licensors  have only  limited
liability. 

In this respect, the user's attention is drawn to the risks associated
with loading,  using,  modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean  that it is complicated to manipulate,  and  that  also
therefore means  that it is reserved for developers  and  experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or 
data to be ensured and,  more generally, to use and operate it in the 
same conditions as regards security. 

The fact that you are presently reading this means that you have had
knowledge of the CeCILL-C or CeCILL license and that you accept its terms.
*/
/*-----------------------------------------------------------------*/


#if HAVE_CONFIG_H
#include "scscpconfig.h"
#endif /*HAVE_CONFIG_H*/
#include <stdio.h>
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#if HAVE_LIMITS_H
#include <limits.h>
#endif
#include <errno.h>
#include <ctype.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/globals.h>
#define __SCSCP_WITHIN_SCSCP
#include "scscp.h"
#include "scscpinternal.h"
#include "scscpdebug.h"
#include "scscpfileclient.h"
#include "scscpfileserver.h"
#include "scscpbinary.h"

/***************************************************************************/
/* macros locales aux fichiers */
/***************************************************************************/
/*! conversion de xmlchar en char */
#define xmlChar2char(x) ((const char*)(x))

/*----------------------------------------------------------------------------------------------*/
/*! private functions */
/*----------------------------------------------------------------------------------------------*/
/* specific for DOM parser */
static const char* xmlNodePtr_getname(xmlNodePtr curnode);
static const char* xmlNodePtr_getcontent(xmlNodePtr curnode);
static int xmlAttrPtr_getvalue(xmlAttrPtr attr, const char **name, const char **value);
static int xmlNodePtr_movetotag(xmlNodePtr* curnode, const char *string, int children, int gotochildnode);
static int xmlNodePtr_SetProp(xmlNodePtr node, const char *name, const char *value, int lenvalue);
static int xmlNodePtr_SetPropID(xmlNodePtr node, unsigned char token, const char *value, int lenvalue);


/*----------------------------------------------------------------------------------------------*/
/*! return the next node after the current xml node.
  return NULL if curnode is the last node.
  @param curnode (in) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
SCSCP_xmlnodeptr SCSCP_xmlnode_getnext(SCSCP_xmlnodeptr curnode)
{
 return curnode->next;
}

/*----------------------------------------------------------------------------------------------*/
/*! return the name after the current xml node.
  @param curnode (in) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
const char* SCSCP_xmlnode_getname(SCSCP_xmlnodeptr curnode)
{ 
#if SCSCP_PARSERTYPE==SCSCP_PARSERDOM
 return xmlNodePtr_getname(curnode);
#elif SCSCP_PARSERTYPE==SCSCP_PARSERSAX
 return SCSCP_omnode_getname(curnode);
#else
...
#endif
}

/*----------------------------------------------------------------------------------------------*/
/*! read the id of the current node. could return NULL if unset
  @param curnode (in) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
const char * SCSCP_xmlnode_getid(SCSCP_xmlnodeptr node)
{ 
  const char* name = NULL;
  const char* szType;
  const char* szContent;
  
  SCSCP_xmlattrptr pattAttribut;

  SCSCP_debugprint("SCSCP_xmlnode_getid(%p) - enter\n", node);
 	
  pattAttribut = SCSCP_xmlnode_getattr(node);

  while (pattAttribut!=NULL && name==NULL)
  {
 	SCSCP_xmlattr_getvalue(pattAttribut, &szType, &szContent);
 	if (strcmp(szType,"id")==0)
 	{
 		name = szContent;
  	}
 	pattAttribut=SCSCP_xmlattr_getnext(pattAttribut);
  }
   
 SCSCP_debugprint("SCSCP_xmlnode_getid() - returns %p\n", name);
 return name;
}



/*----------------------------------------------------------------------------------------------*/
/*! read the content of the current node in the current xml node
  @param curnode (in) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
const char * SCSCP_xmlnode_getcontent(SCSCP_xmlnodeptr curnode)
{ 
#if SCSCP_PARSERTYPE==SCSCP_PARSERDOM
 return xmlNodePtr_getcontent(curnode);
#elif SCSCP_PARSERTYPE==SCSCP_PARSERSAX
 return SCSCP_omnode_getcontent(curnode);
#else
...
#endif
}

/*----------------------------------------------------------------------------------------------*/
/*! return the first child node the current xml node.
  return NULL if no child present
  @param curnode (in) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
SCSCP_xmlnodeptr SCSCP_xmlnode_getchild(SCSCP_xmlnodeptr curnode)
{ 
 return curnode->children;
}

/*----------------------------------------------------------------------------------------------*/
/*! read the first attribute of the current node
  return NULL if no attribute present
  @param curnode (in) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
SCSCP_xmlattrptr SCSCP_xmlnode_getattr(SCSCP_xmlnodeptr curnode)
{ 
 return  curnode->properties;
}

/*----------------------------------------------------------------------------------------------*/
/*! get the content of the attribute 
  return 0 on failure and non-zero on success
  @param attr (in) current attribute. mustn't be NULL 
  @param name (out) name of this attribute
  @param value (out) value of this attribute
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlattr_getvalue(SCSCP_xmlattrptr attr, const char **name, const char **value)
{ 
#if SCSCP_PARSERTYPE==SCSCP_PARSERDOM
 return xmlAttrPtr_getvalue(attr, name, value);
#elif SCSCP_PARSERTYPE==SCSCP_PARSERSAX
 return SCSCP_omattr_getvalue(attr, name, value);
#else
...
#endif
}

/*-----------------------------------------------------------------*/
/*! return the associated value to the attributes specified by the name
  return NULL if not found
  @param iter (in) iterator on the xml doc
  @param p_pszName (in) name of the attribute
*/
/*-----------------------------------------------------------------*/
const char* SCSCP_xmlnode_findattr(SCSCP_xmlnodeptr iter, const char *p_pszName)
{
 const char* attr = NULL;
 const char* value = NULL;
 const char* szType;
 SCSCP_xmlattrptr pattAttribut=iter->properties;
 
 SCSCP_debugprint("OML_FindAttributes(%p,%s) -enter\n", iter, p_pszName);
 
  while (pattAttribut && attr==NULL)
  {
            SCSCP_xmlattr_getvalue(pattAttribut,&szType,&value);
            if (strcmp(szType,p_pszName)==0) attr = value;
            pattAttribut=pattAttribut->next;
  }

 SCSCP_debugprint("OML_FindAttributes() -returns %p\n", attr);
 return attr;
}


/*----------------------------------------------------------------------------------------------*/
/*!  return the next attribute after attr 
  return NULL if attr is the last attribute
  @param attr (in) current valid attribute. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
SCSCP_xmlattrptr SCSCP_xmlattr_getnext(SCSCP_xmlattrptr attr)
{ 
 return attr->next;
}



/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath Symbol and return its name and its cd.
  return 0  on error
  @param node (in) current valid node. mustn't be NULL 
  @param cdname (out) name of CD
  @param symbolname (out) name of the symbol
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readOMS(SCSCP_xmlnodeptr* curnode, const char **cdname, const char **symbolname)
{
  int res ;
  const char* szContent;
  const char* szType;
  
  SCSCP_xmlattrptr pattAttribut;

  SCSCP_debugprint("SCSCP_xmlnode_readOMS(%p,%p,%p) - enter\n", *curnode, cdname, symbolname);
 	
  *cdname = NULL;
  *symbolname = NULL;
  pattAttribut = SCSCP_xmlnode_getattr(*curnode);

  while (pattAttribut!=NULL)
  {
 			SCSCP_xmlattr_getvalue(pattAttribut, &szType, &szContent);
 			if (strcmp(szType,"cd")==0)
 			{
 				*cdname = szContent;
  			}
  			else if (strcmp(xmlChar2char(szType),"name")==0)
  			{
  				*symbolname = szContent;
 			}
 			pattAttribut=SCSCP_xmlattr_getnext(pattAttribut);
  }
  res = (*symbolname!=NULL)?1:0;
 
  *curnode = SCSCP_xmlnode_getnext(*curnode);
   
 SCSCP_debugprint("SCSCP_xmlnode_readOMS(%p,%s,%s) - returns %d\n", *curnode, *cdname, *symbolname,res);
 return res;
}

/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath integer and return its value.
  return 0  on error
  @param node (in) current valid node. mustn't be NULL 
  @param value (out) value of the integer
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readOMIstr(SCSCP_xmlnodeptr* curnode, const char **value)
{
  int res;
  *value = SCSCP_xmlnode_getcontent(SCSCP_xmlnode_getchild(*curnode));
  *curnode = SCSCP_xmlnode_getnext(*curnode);
  res =(*value!=NULL);
  SCSCP_debugprint("SCSCP_xmlnode_readOMIstr(%p,%s) - returns %d\n", *curnode, *value,res);
  return res;
}

/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath integer and return its value.
  return 0  on error
  @param node (in) current valid node. mustn't be NULL 
  @param value (out) value of the integer
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readOMIint(SCSCP_xmlnodeptr* curnode, int* value)
{
 int res;
 const char *buffer;
#if SCSCP_PARSERTYPE==SCSCP_PARSERSAX 
 if ((*curnode)->m_binarycontent!=NULL)
 {
  if ((*curnode)->omtype==SCSCP_omnodetype_OMIchar || (*curnode)->omtype==SCSCP_omnodetype_OMIint32)
  {
   *value = *(int32_t*)(*curnode)->m_binarycontent;
   res = 1;
  }
  else
  {
   SCSCP_debugprint("SCSCP_xmlnode_readOMIint() - bad value %d\n", (*curnode)->omtype);
   res = 0;
  }
  *curnode = SCSCP_xmlnode_getnext(*curnode);
 }
 else
#endif
 { 
  res = SCSCP_xmlnode_readOMIstr(curnode, &buffer);
  if (res)
  {
   long lval;
   errno = 0;
   lval = strtol(buffer, (char **)NULL, 10);
   *value = (int)lval;
   res = (errno==0 && ((long)*value)==lval);
  }
 }
 SCSCP_debugprint("SCSCP_xmlnode_readOMIint(%p,%d) - returns %d\n", *curnode, *value,res);
 return res;
}

/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath integer and return its value.
  return 0  on error
  @param node (in) current valid node. mustn't be NULL 
  @param value (out) value of the integer
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readOMIsizet(SCSCP_xmlnodeptr* curnode, size_t* value)
{
 int res;
 const char *buffer;
#if SCSCP_PARSERTYPE==SCSCP_PARSERSAX 
 if ((*curnode)->m_binarycontent!=NULL)
 {
  if ((*curnode)->omtype==SCSCP_omnodetype_OMIchar || (*curnode)->omtype==SCSCP_omnodetype_OMIint32)
  {
   *value = *(int32_t*)(*curnode)->m_binarycontent;
   res = 1;
  }
  else
  {
   SCSCP_debugprint("SCSCP_xmlnode_readOMIint() - bad value %d\n", (*curnode)->omtype);
   res = 0;
  }
  *curnode = SCSCP_xmlnode_getnext(*curnode);
 }
 else
#endif
 { 
  res = SCSCP_xmlnode_readOMIstr(curnode, &buffer);
  if (res)
  {
   unsigned long long lval;
   errno = 0;
   lval = strtoull(buffer, (char **)NULL, 10);
   *value = (size_t)lval;
   res = (errno==0 && ((unsigned long long)*value)==lval);
  }
 }
 SCSCP_debugprint("SCSCP_xmlnode_readOMIsizet(%p,%d) - returns %d\n", *curnode, (int)*value,res);
 return res;
}


/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath error and return the optional arguments as a raw string.
  return 0  on error
  @param client (in) client session
  @param node (in) current valid node. mustn't be NULL
                   return the node just after the head symbol 
  @param cdname (out) name of the CD
  @param symbolname (out) name of the symbol
  @param value (out) openmath expression (after the 1st symbol). ust be freed by the user using free
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_sc_xmlnodereadOMEstr(SCSCP_socketclient* client, SCSCP_xmlnodeptr* curnode, const char **cdname, 
                             const char **symbolname, char **value, SCSCP_status *status)
{
 int res;
 SCSCP_xmlnodeptr child;
 SCSCP_debugprint("SCSCP_xmlnode_readOMEstr(%p, %p, %p,%p,%p) -enter\n", client, curnode, cdname, symbolname, value);
  
  child = SCSCP_xmlnode_getchild(*curnode);
  if (child==NULL)
  {
   res = 0;
   SCSCP_status_seterror(status, SCSCP_STATUS_OPENMATHNOTVALID);
  }
  else
  {
   res = SCSCP_xmlnode_readOMS(&child, cdname, symbolname);
   
   if (res)
   {
    *value = SCSCP_sc_getxmlnoderawstring(client, child, status);
   
    *curnode = SCSCP_xmlnode_getnext(*curnode);
    res = (*value!=NULL);
   }
  }
 
 SCSCP_debugprint("SCSCP_xmlnode_readOMEstr(,%s,%d) - returns %d\n", *value, SCSCP_status_is(status), res);
 return res; 
}


/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath floating-point  and return its value.
  return 0  on error
  @param curnode (inout) current valid node. mustn't be NULL 
  @param value (out) value of the float
  @param base (out) base ( 16 for "hex", 10 for "dec" or 0 on error)
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readOMFstr(SCSCP_xmlnodeptr* curnode, const char **value, int *base)
{
  int res = 0;
 
  *base = 0;
  *value = SCSCP_xmlnode_findattr(*curnode, "dec");
  if (*value!=NULL) { *base = 10; res = 1; }
  else 
  {
   *value = SCSCP_xmlnode_findattr(*curnode, "hex");
   if (*value!=NULL) { *base = 16; res = 1; }
  }
  if (res) *curnode = SCSCP_xmlnode_getnext(*curnode);
  
 SCSCP_debugprint("SCSCP_xmlnode_readOMFstr(%p, %s,%d) - returns %d\n", *curnode, *value, *base, res);
 return res;
}

/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath floating-point  and return its value.
  return 0  on error
  @param curnode (inout) current valid node. mustn't be NULL 
  @param value (out) value of the float
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readOMFdouble(SCSCP_xmlnodeptr* curnode, double *value)
{
  int res, j;
  const char *valuestr;
 
  valuestr = SCSCP_xmlnode_findattr(*curnode, "dec");
  if (valuestr!=NULL)
  {
   *value = strtod(valuestr, (char **)NULL);
  }
  else
  {
   valuestr = SCSCP_xmlnode_findattr(*curnode, "hex");
   if (valuestr!=NULL)
   { /*convert from hexa to double */
     char *valuec = (char *)value;
     if (strlen(valuestr)==16)
     {
      for (j=0; j<8; j++)
      {
       char c;
       c = valuestr[2*j];
       valuec[j]=(isdigit(c)?(c-'0'):c-'A'+10)<<4;
       c = valuestr[2*j+1];
       valuec[j]|= isdigit(c)?(c-'0'):c-'A'+10;
      }
      *value = SCSCP_ntohd(*value);
     }
   }
  }

  res = (valuestr!=NULL);
  if (res) *curnode = SCSCP_xmlnode_getnext(*curnode);
  
 SCSCP_debugprint("SCSCP_xmlnode_readOMFdouble(%p, %23.16E) - returns %d\n", *curnode, *value, res);
 return res;
}

/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath string  and return its value.
  return 0  on error
  @param curnode (inout) current valid node. mustn't be NULL 
  @param value (out) value of the integer
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readOMSTR(SCSCP_xmlnodeptr* curnode, const char **value)
{
 int res;
 SCSCP_xmlnodeptr child = SCSCP_xmlnode_getchild(*curnode);
 
  *value = (child==NULL)? NULL: SCSCP_xmlnode_getcontent(child);
  if (*value==NULL || strlen(*value)==0) 
     res = 0;
  else 
  {
   *curnode = SCSCP_xmlnode_getnext(*curnode);
   res=1;
  }
  
 SCSCP_debugprint("SCSCP_xmlnode_readOMSTR(%p, %s) - returns %d\n", *curnode, *value, res);
 return res;
}


/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath reference and return its value.
  return 0  on error
  @param curnode (inout) current valid node. mustn't be NULL 
  @param value (out) reference name
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readOMR(SCSCP_xmlnodeptr* curnode, const char **value)
{
 int res;
 SCSCP_debugprint("SCSCP_xmlnode_readOMR(%p, %p) -enter\n", *curnode, value);

  *value = SCSCP_xmlnode_findattr(*curnode, "href");
  if (*value==NULL) 
  {
   res=0;
  }
  else
  {
   *curnode = SCSCP_xmlnode_getnext(*curnode);
   res = 1;
  }
 
 SCSCP_debugprint("SCSCP_xmlnode_readOMR(%p,%s) - returns %d\n",*curnode, *value, res);
 return res;
}


/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath variable  and return its value.
  return 0  on error
  @param curnode (inout) current valid node. mustn't be NULL 
  @param value (out) value of the integer
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readOMV(SCSCP_xmlnodeptr* curnode, const char **value)
{
 int res;
 SCSCP_xmlnodeptr child;
 
 SCSCP_debugprint("SCSCP_xmlnode_readOMV(%p, %p) - enter\n", *curnode, value);
  child = SCSCP_xmlnode_getchild(*curnode);
   
  *value = SCSCP_xmlnode_findattr(*curnode, "name");
  if (*value==NULL && child!=NULL)
  {
   *value = SCSCP_xmlnode_getcontent(child);
  }
  res = (*value!=NULL);
  
  *curnode = SCSCP_xmlnode_getnext(*curnode);
  
 SCSCP_debugprint("SCSCP_xmlnode_readOMV(%p, %s) - returns %d\n", *curnode, *value, res);
 return res;
}


/*----------------------------------------------------------------------------------------------*/
/*! find the first <OMOBJ>, look in child node
  return 0  on error
  @param node (inout) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readbeginOMOBJ(SCSCP_xmlnodeptr* curnode)
{
 return SCSCP_xmlnode_movetotag(curnode, "OMOBJ", 1,1);
}

/*----------------------------------------------------------------------------------------------*/
/*! find the first <OMA>, look in child node
  return 0  on error
  @param node (inout) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readbeginOMA(SCSCP_xmlnodeptr* curnode)
{
 return SCSCP_xmlnode_movetotag(curnode, "OMA", 1,1);
}

/*----------------------------------------------------------------------------------------------*/
/*! find the first <OMATTR>, look in child node
  return 0  on error
  @param node (inout) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readbeginOMATTR(SCSCP_xmlnodeptr* curnode)
{
 return SCSCP_xmlnode_movetotag(curnode, "OMATTR", 1,1);
}

/*----------------------------------------------------------------------------------------------*/
/*! find the first <OMATP>, look in child node
  return 0  on error
  @param node (inout) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readbeginOMATP(SCSCP_xmlnodeptr* curnode)
{
 return SCSCP_xmlnode_movetotag(curnode, "OMATP", 1,1);
}

/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath Symbol, check the symbol name with symbolname and the CD anme 
     and return the next OpenMath string.
  return 0  on error
  @param node (in) current valid node. mustn't be NULL 
  @param value (out) value of the integer
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readpairOMSOMSTR(SCSCP_xmlnodeptr* curnode, const char *cdname, const char *symbolname, const char **buffer)
{
 int res = SCSCP_xmlnode_readcheckOMS(curnode, cdname, symbolname);
 if (res) res = SCSCP_xmlnode_readOMSTR(curnode, buffer);
 return res;
}

/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath Symbol, check the symbol name with symbolname and the CD anme 
     and return the next OpenMath integer.
  return 0  on error
  @param node (in) current valid node. mustn't be NULL 
  @param value (out) value of the integer
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readpairOMSOMIsizet(SCSCP_xmlnodeptr* curnode, const char *cdname, const char *symbolname, size_t *value)
{
 int res = SCSCP_xmlnode_readcheckOMS(curnode, cdname, symbolname);
 if (res) res = SCSCP_xmlnode_readOMIsizet(curnode, value);
 return res;
}

/*----------------------------------------------------------------------------------------------*/
/*!  read an OpenMath Symbol, check the symbol name with symbolname and the CD anme 
     and return the next OpenMath integer.
  return 0  on error
  @param node (in) current valid node. mustn't be NULL 
  @param value (out) value of the integer
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readpairOMSOMIint(SCSCP_xmlnodeptr* curnode, const char *cdname, const char *symbolname, int *value)
{
 int res = SCSCP_xmlnode_readcheckOMS(curnode, cdname, symbolname);
 if (res) res = SCSCP_xmlnode_readOMIint(curnode, value);
 return res;
}

/*----------------------------------------------------------------------------------------------*/
/*!   move the current node pointer to the specified symbol
     read an OpenMath Symbol, check the symbol name with symbolname and the CD anme 
  return 0  on error
  @param node (in) current valid node. mustn't be NULL 
  @param value (out) value of the integer
*/
/*----------------------------------------------------------------------------------------------*/
int SCSCP_xmlnode_readcheckOMS(SCSCP_xmlnodeptr* curnode, const char *cdname, const char *symbolname)
{
 int res = 1;
 int bfound = 0;
 SCSCP_debugprint("SCSCP_xmlnode_readcheckOMS(%p,%s, %s ) - enter\n", curnode, cdname, symbolname);

 while (!bfound && res)
 {
  if (SCSCP_xmlnode_movetotag(curnode, "OMS", 0, 0))
  {
    /* check cdname and name */
    const char *cdread, *symbolread;
    if ((res=SCSCP_xmlnode_readOMS(curnode, &cdread, &symbolread))==1)
    {
     bfound = (strcmp(cdname,cdread)==0 && strcmp(symbolname, symbolread)==0);
    }
  } 
  else { break; /* exit from loop */ }
 }
 
 res = res & bfound;
 
 SCSCP_debugprint("SCSCP_xmlnode_readcheckOMS(%p) - returns %d\n", curnode, res);
 return res;
}

/*-----------------------------------------------------------------*/
/*!move the current node pointer to the first specified item
 return true on success
  @param curnode (inout) iterator on the xml doc
  @param string (in) string to find
  @param children (in) = true => look only in the children
  @param gotochildnode (in) = 0 => return the looking node
                           = 1 =>  return the first child node
*/
/*-----------------------------------------------------------------*/
int SCSCP_xmlnode_movetotag(SCSCP_xmlnodeptr* curnode, const char *string, int children, int gotochildnode)
{
#if SCSCP_PARSERTYPE==SCSCP_PARSERDOM
 return xmlNodePtr_movetotag(curnode,string, children, gotochildnode);
#elif SCSCP_PARSERTYPE==SCSCP_PARSERSAX
 return SCSCP_omnode_movetotag(curnode,string, children, gotochildnode);
#else
...
#endif
}


/*-----------------------------------------------------------------*/
/*!move the current node pointer to the first specified item
 return true on success
  @param curnode (inout) iterator on the xml doc
  @param string (in) string to find
  @param children (in) = true => look only in the children
  @param gotochildnode (in) = 0 => return the looking node
                           = 1 =>  return the first child node
*/
/*-----------------------------------------------------------------*/
static int xmlNodePtr_movetotag(xmlNodePtr* curnode, const char *string, int children, int gotochildnode)
{
  int res = 0;
#if SCSCP_PARSERTYPE==SCSCP_PARSERDOM
  xmlNodePtr itertmp = *curnode;
  xmlNodePtr iter = *curnode;
  
  SCSCP_debugprint("xmlNodePtr_movetotag(%p,%s,%d) - enter\n", *curnode, string, children);

  if (children)
  {
      if (iter)
      {
       if (iter->type==XML_TEXT_NODE)
       { // cas de texte entre les noeuds
        SCSCP_xmlnodeptr next = SCSCP_xmlnode_getnext(iter);
        res = SCSCP_xmlnode_movetotag(&next, string, children, gotochildnode);
       }
       else if (iter->type == XML_ELEMENT_NODE) 
       {
        SCSCP_debugprint("xmlNodePtr_movetotag() - node %s type XML_ELEMENT_NODE \n", iter->name);
        res = (xmlStrcmp(BAD_CAST string, iter->name)==0);
        if (res == 0 && xmlStrncasecmp(BAD_CAST "om:", iter->name,3)==0)  res = (xmlStrcmp(BAD_CAST string, iter->name+3)==0);
      }
       if (!res) 
       {
        itertmp = SCSCP_xmlnode_getchild(iter);
        res = SCSCP_xmlnode_movetotag(&itertmp, string, children, gotochildnode);
        if (res) *curnode = itertmp;
       }
      }
  }
  else
  {
      while (iter!=NULL && !res)
      {
       if (iter->type == XML_ELEMENT_NODE) 
       {
        SCSCP_debugprint("xmlNodePtr_movetotag() - node %s type XML_ELEMENT_NODE \n", iter->name);
        res = (xmlStrcmp(BAD_CAST string, iter->name)==0);
        if (res == 0 && xmlStrncasecmp(BAD_CAST "om:", iter->name,3)==0)  res = (xmlStrcmp(BAD_CAST string, iter->name+3)==0);
       }
       if (!res) iter = SCSCP_xmlnode_getnext(iter);
      }
      *curnode = iter;
  }      
 
 if (res && gotochildnode) *curnode = SCSCP_xmlnode_getchild(*curnode);
#endif /*SCSCP_PARSERTYPE==SCSCP_PARSERDOM*/
 
 SCSCP_debugprint("xmlNodePtr_movetotag(%p,) - returns %d\n", *curnode, res);
 return res;
}

/*-----------------------------------------------------------------*/
/*! set the id of the node if the token contains an id using the followed value
 @param node (inout) node
 @param token (in) token of the current
 @param value (in) value of id (only the lenvalue first characters are valid)
 @param lenvalue (in) valid character of value
*/ 
/*-----------------------------------------------------------------*/
static int xmlNodePtr_SetPropID(xmlNodePtr node, unsigned char token, const char *value, int lenvalue)
{
 int retval = 1;
 if (SCSCP_binary_isidflagset(token))
 {
  retval = xmlNodePtr_SetProp(node, "id",  value, lenvalue);
 }
 return retval;
}

/*-----------------------------------------------------------------*/
/*! set the attribute of the node using the value
 @param node (inout) node
 @param token (in) token of the current
 @param name (in) name of the attribute
 @param value (in) value of id (only the lenvalue first characters are valid)
 @param lenvalue (in) valid character of value
*/ 
/*-----------------------------------------------------------------*/
static int xmlNodePtr_SetProp(xmlNodePtr node, const char *name, const char *value, int lenvalue)
{
 int retval = 1;
 xmlChar *xmlvalue = xmlCharStrndup(value, lenvalue);
 if (xmlvalue==NULL) retval=0;
 else
 {
  if (xmlSetProp(node, BAD_CAST name, xmlvalue)==NULL) retval = 0;
  xmlFree(xmlvalue);
 }
 return retval;
}

/*-----------------------------------------------------------------*/
/*! create a new node inside the document doc.
 its parent is owner
 and set its attributes
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param token (in)  token 
 @param nattr (in) number of elements in attrname and attrvalue
 @param attrname (in) name of the attributes
  last one in the array must be "id"
 @param attrvalue (in) value of the attribute
 @param attrvaluelen (in) length of the strings of attrvalue
*/ 
/*-----------------------------------------------------------------*/
xmlNodePtr xmlNodePtr_inittokenattr(xmlDocPtr doc, xmlNodePtr owner, unsigned char token, int nattr, const char *attrname[], char *attrvalue[], int attrvaluelen[] )
{ 
 xmlNodePtr node;
 int j;
 SCSCP_debugprint("xmlNodePtr_inittokenattr(,%u,) - enter\n",(unsigned int)token);
 
  node = xmlNewChild(owner,NULL, BAD_CAST SCSCP_omnode_namefromtype((SCSCP_omnodetype)SCSCP_binary_gettoken(token)), NULL);
  if (node && nattr>=1)
  {
   int retval=1;
   for (j=0;j<nattr-1 && retval==1; j++)
   {
    if (!xmlNodePtr_SetProp(node,attrname[j], attrvalue[j], attrvaluelen[j])) retval = 0;
   }
   if (!xmlNodePtr_SetPropID(node,token, attrvalue[nattr-1], attrvaluelen[nattr-1])) retval = 0;
   if (retval==0) { xmlFreeNode(node); node = NULL; }
  }

 SCSCP_debugprint("xmlNodePtr_inittokenattr() - return %p\n", node);
 return node;
}

/*-----------------------------------------------------------------*/
/*! create a new node inside the document doc.
 its parent is owner
 and set its attributes
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param token (in)  token 
 @param nattr (in) number of elements in attrname and attrvalue
 @param attrname (in) name of the attributes
  last one in the array must be "id"
 @param attrvalue (in) value of the attribute
 @param attrvaluelen (in) length of the strings of attrvalue
 @param content (in) value of the content
 @param contentlen (in) length of  content
*/ 
/*-----------------------------------------------------------------*/
xmlNodePtr xmlNodePtr_inittokenattrcontent(xmlDocPtr doc, xmlNodePtr owner, unsigned char token, int nattr, const char *attrname[], char *attrvalue[], int attrvaluelen[], char *content, int contentlen )
{ 
 xmlNodePtr node;
 SCSCP_debugprint("xmlNodePtr_inittokenattrcontent(,%u,) - enter\n",(unsigned int)token);
 
  node = xmlNodePtr_inittokenattr(doc, owner, token, nattr, attrname, attrvalue, attrvaluelen);
  if (node) xmlNodeSetContentLen(node, BAD_CAST content, contentlen);

 SCSCP_debugprint("xmlNodePtr_inittokenattrcontent() - return %p\n", node);
 return node;
}


/*-----------------------------------------------------------------*/
/*! create a new node inside the document doc.
 its parent is owner
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param token (in)  token (valid if name!=NULL)
*/ 
/*-----------------------------------------------------------------*/
xmlNodePtr xmlNodePtr_inittoken(xmlDocPtr doc, xmlNodePtr owner,  unsigned char token)
{ 
 xmlNodePtr node;
 SCSCP_debugprint("xmlNodePtr_inittoken(,%u,) - enter\n",(unsigned int)token);
 
 node = xmlNewChild(owner,NULL, BAD_CAST SCSCP_omnode_namefromtype((SCSCP_omnodetype)SCSCP_binary_gettoken(token)), NULL);

 SCSCP_debugprint("xmlNodePtr_inittoken() - return %p\n", node);
 return node;
}

/*-----------------------------------------------------------------*/
/*! create a new node inside the document doc.
 its parent is owner
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param token (in)  token (valid if name!=NULL)
*/ 
/*-----------------------------------------------------------------*/
xmlNodePtr xmlNodePtr_initname(xmlDocPtr doc, xmlNodePtr owner,  const char *name)
{ 
 xmlNodePtr node;
 SCSCP_debugprint("xmlNodePtr_initname(,%s) - enter\n",name);
 
 node = xmlNewChild(owner,NULL, BAD_CAST name, NULL);

 SCSCP_debugprint("xmlNodePtr_initname() - return %p\n", node);
 return node;
}


/*-----------------------------------------------------------------*/
/*! create the first node inside the document doc.
 its parent is owner
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param token (in)  token (valid if name!=NULL)
*/ 
/*-----------------------------------------------------------------*/
xmlNodePtr xmlNodePtr_initroottoken(xmlDocPtr doc,  unsigned char token)
{ 
 xmlNodePtr node;
 SCSCP_debugprint("xmlNodePtr_initroottoken(,%u,) - enter\n",(unsigned int)token);
 
 node = xmlNewDocNode(doc,NULL, BAD_CAST SCSCP_omnode_namefromtype((SCSCP_omnodetype)SCSCP_binary_gettoken(token)), NULL);
 if (node) SCSCP_xmldoc_setrootnode(doc, node);

 SCSCP_debugprint("xmlNodePtr_initroottoken() - return %p\n", node);
 return node;
}

/*----------------------------------------------------------------------------------------------*/
/*! return the name after the current xml node.
  @param curnode (in) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
static const char* xmlNodePtr_getname(xmlNodePtr curnode)
{ 
 return xmlChar2char(curnode->name);
}

/*----------------------------------------------------------------------------------------------*/
/*! read the content of the current node in the current xml node
  @param curnode (in) current valid node. mustn't be NULL 
*/
/*----------------------------------------------------------------------------------------------*/
static const char * xmlNodePtr_getcontent(xmlNodePtr curnode)
{ 
 return xmlChar2char(XML_GET_CONTENT(curnode));
}

/*-----------------------------------------------------------------*/
/*! set the content of the node using the value
 @param doc (inout) document
 @param node (inout) node
 @param value (in) value of the content
 @param lenvalue (in) valid character of value
*/ 
/*-----------------------------------------------------------------*/
int xmlNodePtr_setcontent(xmlDocPtr doc, xmlNodePtr node, const char *value, int lenvalue)
{
 xmlNodePtr child = xmlNewTextLen(BAD_CAST value, lenvalue);
 if (child)
 {
  xmlAddChild(node, child);
  return 1;
 }
 else return 0;
}

/*----------------------------------------------------------------------------------------------*/
/*! get the content of the attribute 
  return 0 on failure and non-zero on success
  @param attr (in) current attribute. mustn't be NULL 
  @param name (out) name of this attribute
  @param value (out) value of this attribute
*/
/*----------------------------------------------------------------------------------------------*/
static int xmlAttrPtr_getvalue(xmlAttrPtr attr, const char **name, const char **value)
{ 
 *name = xmlChar2char(attr->name);
 *value = xmlChar2char(attr->children->content);
 return  1;
}

/*-----------------------------------------------------------------*/
/*! set the attribute of the node using the value
 @param doc (inout) document
 @param node (inout) node
 @param token (in) token of the current
 @param name (in) name of the attribute
 @param value (in) value of id (only the lenvalue first characters are valid)
 @param lenvalue (in) valid character of value
*/ 
/*-----------------------------------------------------------------*/
int xmlNodePtr_setattr(xmlDocPtr doc, xmlNodePtr node, const char *name, const char *value, int lenvalue)
{
 xmlChar *chdup = xmlStrndup(BAD_CAST value, lenvalue);
 xmlAttrPtr attrptr;
 if (chdup)
 {
  attrptr = xmlNewProp(node,BAD_CAST name,  chdup);
  xmlFree(chdup);
  return (attrptr!=NULL);
 }
 else return 0;
}


