/*-----------------------------------------------------------------*/
/*! 
  \file scscpbinary.h
  \brief  support of the binary encoding for OpenMath objects
  \author  M. Gastineau 
           Astronomie et Systemes Dynamiques, IMCCE, CNRS, Observatoire de Paris. 

   Copyright, 2009,2010,2012,  M. Gastineau, IMCCE-CNRS
   email of the author : gastineau@imcce.fr
 
   \bug M. GASTINEAU 01/10/12 : ticket [#8520] omf wrong hexa encoding with big-endian order

*/
/*-----------------------------------------------------------------*/

/*-----------------------------------------------------------------*/
/* 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*/
#if HAVE_WINDOWS_H
#include <windows.h>
#endif /*HAVE_CONFIG_H*/
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <libxml/parser.h>
#include <libxml/tree.h>
#define __SCSCP_WITHIN_SCSCP
#include "scscp.h"
#include "scscpinternal.h"
#include "scscpdebug.h"
#include "scscpfileclient.h"
#include "scscpfileserver.h"
#include "scscpbinary.h"
#include "scscpomdoc.h"


/*-----------------------------------------------------------------*/
/* private definitions */
/*-----------------------------------------------------------------*/
/*! return 1 if long flag is set  */
#define SCSCP_binary_islongflagset(c) ((c)&128U)

/*-----------------------------------------------------------------*/
/* private types */
/*-----------------------------------------------------------------*/
/*! buffer definition */
typedef struct 
{
 unsigned char *m_Buffer; /*!< data */
 size_t         m_Size;   /*!< size of the buffer */
 size_t         m_Readpos; /*!< read position */ 
 size_t         m_Writepos; /*!< write position */
 xmlInputReadCallback m_StreamRead; /*!< function to read the stream */
 void          *m_UserData; /*!< user data (provided to streamread) */ 
} t_buffer;

/*-----------------------------------------------------------------*/
/* private functions */
/*-----------------------------------------------------------------*/
static int SCSCP_buffer_init(t_buffer *buffer, xmlInputReadCallback streamread, void *user_data, SCSCP_status* status);
static void SCSCP_buffer_clear(t_buffer *buffer);
static int SCSCP_buffer_getuchar(t_buffer *buffer, unsigned char *c);
static int SCSCP_buffer_getchar(t_buffer *buffer, char *c);
static int SCSCP_buffer_getucharn(t_buffer *buffer, unsigned char *c, int n);
static int SCSCP_buffer_peekuchar(t_buffer *buffer, unsigned char *c);
static unsigned char* SCSCP_buffer_loaducharn(t_buffer *buffer, int n);
static int SCSCP_DOMbinaryReadIO_parsecheck(unsigned char token, t_buffer *buffer);
static int SCSCP_DOMbinaryReadIO_parsetest(unsigned char token, t_buffer *buffer);

static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMOBJ(SCSCP_xmldocptr doc, t_buffer *buffer);
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_parse(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer);
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMIchar(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token);
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMIstr(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token);
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMF(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token);
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMS(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token);
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMV(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token);
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMSTR(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token);
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMR(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token);
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMsimple(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token, unsigned char lasttoken);

static int SCSCP_DOMbinaryReadIO_getustring(t_buffer *buffer, int nvalue, int *lenvalue,  unsigned char **value, unsigned char token);
 
/*-----------------------------------------------------------------*/
/*! initialize the buffer data structure 
   return 0 on error
  @param buffer (out) object to initialize
  @param streamread (in)  function to read to stream
  @param user_data (in)  user data (provided to streamread)
  @param status (inout) status error
*/
/*-----------------------------------------------------------------*/
int SCSCP_buffer_init(t_buffer *buffer, xmlInputReadCallback streamread, void *user_data, SCSCP_status* status)
{
 buffer->m_Size = SCSCP_PI_MAXLENBUFFER;
 buffer->m_Buffer = (unsigned char *)SCSCP_malloc(buffer->m_Size, status);
 buffer->m_Readpos = 0;
 buffer->m_Writepos = 0;
 buffer->m_StreamRead = streamread;
 buffer->m_UserData = user_data;
 return (buffer->m_Buffer!=NULL);
}

/*-----------------------------------------------------------------*/
/*! clear the buffer data structure 
  @param buffer (inout) object to destroy
*/
/*-----------------------------------------------------------------*/
void SCSCP_buffer_clear(t_buffer *buffer)
{
 buffer->m_Size = 0;
 buffer->m_Readpos = 0;
 buffer->m_Writepos = 0;
 free(buffer->m_Buffer);
}


/*-----------------------------------------------------------------*/
/*! retrieve one character from the buffer data structure 
   return 0 on error
  @param buffer (inout) object to read
  @param c (out) array of 1 characters
*/
/*-----------------------------------------------------------------*/
int SCSCP_buffer_getuchar(t_buffer *buffer, unsigned char *c)
{
 int retval = SCSCP_buffer_peekuchar(buffer, c);
 if (retval) buffer->m_Readpos++;
 return retval;
}

/*-----------------------------------------------------------------*/
/*! retrieve one character from the buffer data structure 
   return 0 on error
  @param buffer (inout) object to read
  @param c (out) array of 1 characters
*/
/*-----------------------------------------------------------------*/
int SCSCP_buffer_getchar(t_buffer *buffer, char *c)
{
 return SCSCP_buffer_getuchar(buffer, (unsigned char*)c);
}

/*-----------------------------------------------------------------*/
/*! peek one character from the buffer data structure but don't remove from buffer
   return 0 on error
  @param buffer (inout) object to read
  @param c (out) array of 1 characters
*/
/*-----------------------------------------------------------------*/
int SCSCP_buffer_peekuchar(t_buffer *buffer, unsigned char *c)
{
 int retval = 1;
 if (buffer->m_Writepos==buffer->m_Readpos)
 {
  int nread = buffer->m_StreamRead(buffer->m_UserData, (char *)buffer->m_Buffer, buffer->m_Size);
  if (nread>0) 
  {
   *c = buffer->m_Buffer[0];
   buffer->m_Readpos = 0;
   buffer->m_Writepos = nread; 
  }
  else 
  {
   retval = 0;
  } 
 }
 else *c = buffer->m_Buffer[buffer->m_Readpos];
 return retval;
}

/*-----------------------------------------------------------------*/
/*! retrieve n characters from the buffer data structure 
   return 0 on error
  @param buffer (inout) object to read
  @param c (out) array of n characters
  @param n (in) n numbers of characters
*/
/*-----------------------------------------------------------------*/
int SCSCP_buffer_getucharn(t_buffer *buffer, unsigned char *c, int n)
{
 unsigned char* buffloc;
 int retval;
 buffloc = SCSCP_buffer_loaducharn(buffer, n);
 
 retval = (buffloc!=NULL);
 if (retval)
 {
  memcpy(c,buffloc, n);
 }
 return retval;
}


/*-----------------------------------------------------------------*/
/*! retrieve n characters from the buffer data structure 
   return the address of the data
  @param buffer (inout) object to read
  @param n (in) n numbers of characters
*/
/*-----------------------------------------------------------------*/
unsigned char * SCSCP_buffer_loaducharn(t_buffer *buffer, int n)
{
 unsigned char *bufferload=NULL;

 if (buffer->m_Writepos<=buffer->m_Readpos+n-1)
 {
  int nread;
  size_t copylen = buffer->m_Writepos-buffer->m_Readpos;
  if (copylen>0) memmove(buffer->m_Buffer, buffer->m_Buffer+buffer->m_Readpos, copylen);
  buffer->m_Readpos = 0;
  buffer->m_Writepos = copylen;  
  
  nread = buffer->m_StreamRead(buffer->m_UserData, (char *)buffer->m_Buffer+buffer->m_Writepos, buffer->m_Size-buffer->m_Writepos);  
  if (nread>1) 
  {
   buffer->m_Writepos+=nread;
   copylen = buffer->m_Writepos-buffer->m_Readpos;
   if (copylen>=n) 
   {
    bufferload = buffer->m_Buffer+buffer->m_Readpos;
    buffer->m_Readpos += n;
   }
  }
 }
 else 
 {
  bufferload = buffer->m_Buffer+buffer->m_Readpos;
  buffer->m_Readpos += n;
 }
 return bufferload;
}

/*-----------------------------------------------------------------*/
/*! read one token and check if the value is correct
 return 0 on error
 @param token (in) value to check
 @param buffer (inout) buffer
*/ 
/*-----------------------------------------------------------------*/
int SCSCP_DOMbinaryReadIO_parsecheck(unsigned char token, t_buffer *buffer)
{
 int retval;
 unsigned char c;
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_parsecheck(%d) - enter\n",(int)token);
 retval = SCSCP_buffer_getuchar(buffer, &c);
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_parsecheck() - c=%d - return %d\n",c, retval && c==token );
 return retval && c==token;
}

/*-----------------------------------------------------------------*/
/*! read one token and test if the value is correct
 return 1 if token is equal
 return 0 on error
 return -1 if token isn't equal
 @param token (in) value to check
 @param buffer (inout) buffer
*/ 
/*-----------------------------------------------------------------*/
int SCSCP_DOMbinaryReadIO_parsetest(unsigned char token, t_buffer *buffer)
{
 int retval;
 unsigned char c;
 int res;
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_parsetest(%d) - enter\n",(int)token);
 retval = SCSCP_buffer_peekuchar(buffer, &c);
 res  = (retval==0)?0:(c==token?1:-1);
 if (res==1)  res = SCSCP_buffer_getuchar(buffer, &c);
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_parsetest() - c=%d - return %d\n",c, res);
 return res;
}


/*-----------------------------------------------------------------*/
/*! read nvalue integers accoding to the token flags
put the location of the strings and their len in lenvalue and value
  @param buffer (inout) buffer
*/ 
/*-----------------------------------------------------------------*/
static int SCSCP_DOMbinaryReadIO_getustring(t_buffer *buffer, int nvalue, int *lenvalue,  unsigned char **value, unsigned char token)
{
 int retval = 1;
 int j;
 unsigned char *bufferloc;
 size_t lenstrings;
 
 if (SCSCP_binary_isidflagset(token)) nvalue++;
 
 if (!SCSCP_binary_islongflagset(token))
 {
  char *nlen = (char *)alloca(nvalue*sizeof(char));
  retval = SCSCP_buffer_getucharn(buffer,(unsigned char*)nlen, nvalue);
  if (retval)
  {
   for (j=0; j<nvalue; j++)
   {
    lenvalue[j] = nlen[j];
   }
  }
 }
 else
 {
  uint32_t *nlen32 = (uint32_t *)alloca(nvalue*sizeof(uint32_t));
  retval = SCSCP_buffer_getucharn(buffer,(unsigned char*)nlen32, nvalue*sizeof(uint32_t));
  if (retval)
  {
   for (j=0; j<nvalue; j++)
   {
    lenvalue[j] = ntohl(nlen32[j]);
   }
  }
 }  
 
 /* the token=2 has an additional sign */
 if (retval && SCSCP_binary_gettoken(token)==2) lenvalue[0]+=1;
  
 /* compute the required size to get all data */
 if (retval)
 {
   lenstrings = 0;
   for (j=0; j<nvalue; j++)
   {
    lenstrings += lenvalue[j];
   }

   /* read the string */
   bufferloc = SCSCP_buffer_loaducharn(buffer, lenstrings);
   if (!bufferloc)  retval = 0;
   else
   {
    lenstrings = 0;
    for (j=0; j<nvalue; j++)
    {
     value[j] = bufferloc+lenstrings;
     lenstrings += lenvalue[j];
    }
   }
 }
 return retval;
}


/*-----------------------------------------------------------------*/
/*! read a token and choose the appropriate function
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param buffer (inout) buffer
*/ 
/*-----------------------------------------------------------------*/
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_parse(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer)
{
 SCSCP_xmlnodeptr node=NULL;
 int retval;
 unsigned char c;
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_parse() - enter\n");
 retval = SCSCP_buffer_getuchar(buffer, &c);
 if (retval)
 {
  switch (SCSCP_binary_gettoken(c))
  {
   case 1 : node = SCSCP_DOMbinaryReadIO_OMIchar(doc,owner, buffer,c); break;
   case 2 : node = SCSCP_DOMbinaryReadIO_OMIstr(doc, owner, buffer,c); break;
   case 3 : node = SCSCP_DOMbinaryReadIO_OMF(doc, owner, buffer,c); break;
   case 5 : node = SCSCP_DOMbinaryReadIO_OMV(doc, owner, buffer,c); break;
   case 6 : node = SCSCP_DOMbinaryReadIO_OMSTR(doc, owner, buffer,c); break;
   case 8 : node = SCSCP_DOMbinaryReadIO_OMS(doc, owner, buffer,c); break;
   case 16 : node = SCSCP_DOMbinaryReadIO_OMsimple(doc, owner, buffer, c,  17); break;
   case 18 : node = SCSCP_DOMbinaryReadIO_OMsimple(doc, owner, buffer, c,  19); break;
   case 20 : node = SCSCP_DOMbinaryReadIO_OMsimple(doc, owner, buffer, c,  21);  break;
   case 22 : node = SCSCP_DOMbinaryReadIO_OMsimple(doc, owner, buffer, c,  23);  break;
   case 31 : node = SCSCP_DOMbinaryReadIO_OMR(doc, owner, buffer,c); break;
     
   default:
     SCSCP_debugprint("unknown token : '%d/%d'\n", (int)c, (int)SCSCP_binary_gettoken(c));
     break;
  }
 }
 
 
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_parse() - return %p\n", node);
 return node;
}

 
/*-----------------------------------------------------------------*/
/*! read a token of type name
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param buffer (inout) buffer
 @param token (in) current token
 @param name (in) name of the node
 @param lasttoken (in) token to read at the end of the object
*/ 
/*-----------------------------------------------------------------*/
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMsimple(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token, unsigned char lasttoken)
{
 SCSCP_xmlnodeptr node=NULL;
 SCSCP_xmlnodeptr childnode;
 int retval=1;
 int last;
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMsimple(,%u,%u) - enter\n",(unsigned int)token, (unsigned int)lasttoken);
 
 node = SCSCP_xmlnode_inittoken(doc, owner, token);
 if (node)
 {
  do
  {
   childnode = SCSCP_DOMbinaryReadIO_parse(doc,node, buffer);
   if (childnode==NULL) retval = 0;
   /*check if we have processed the object */
   last = SCSCP_DOMbinaryReadIO_parsetest(lasttoken, buffer);
  } while (retval && last==-1);
  if (last==0) retval = 0;
  
  if (retval==0)
  {
   SCSCP_xmlnode_clear(node); node = NULL;
  }
 }
 
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMsimple() - return %p\n", node);
 return node;
}

/*-----------------------------------------------------------------*/
/*! read a token of type OMS
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param buffer (inout) buffer
 @param c (in) current token
*/ 
/*-----------------------------------------------------------------*/
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMS(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token)
{
 SCSCP_xmlnodeptr node=NULL;
 int retval=1;
 int lenname[3]; /* cd and symbol and id */
 unsigned char * name[3]; /* address of the value */
 const char * attrname[3]={"cd","name","id" }; /* attribute name */
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMS() - enter\n");
 
 retval = SCSCP_DOMbinaryReadIO_getustring(buffer,2, lenname,  name, token);
 if (retval)
 {
  node = SCSCP_xmlnode_inittokenattr(doc,owner,token, 3, attrname, (char **)name, lenname);
 }

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

/*-----------------------------------------------------------------*/
/*! read a token of type OMV
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param buffer (inout) buffer
 @param c (in) current token
*/ 
/*-----------------------------------------------------------------*/
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMV(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token)
{
 SCSCP_xmlnodeptr node=NULL;
 int retval=1;
 int lenname[2]; /* name and id  */
 unsigned char * name[2]; /* address of the value */
 const char * attrname[2]={"name","id" }; /* attribute name */
 
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMV() - enter\n");
 
 retval = SCSCP_DOMbinaryReadIO_getustring(buffer,1, lenname,  name, token);
 if (retval)
 {
  node = SCSCP_xmlnode_inittokenattr(doc,owner,token, 2, attrname, (char **) name, lenname);
 }

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

/*-----------------------------------------------------------------*/
/*! read a token of type OMR
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param buffer (inout) buffer
 @param c (in) current token
*/ 
/*-----------------------------------------------------------------*/
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMR(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token)
{
 SCSCP_xmlnodeptr node=NULL;
 int retval=1;
 int lenname[2]; /* uri */
 unsigned char * name[2]; /* address of the value */
 const char * attrname[2]={"href","id" }; /* attribute name */
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMR() - enter\n");
 
 retval = SCSCP_DOMbinaryReadIO_getustring(buffer,1, lenname,  name, token);
 if (retval)
 {
  node = SCSCP_xmlnode_inittokenattr(doc,owner,token, 2, attrname, (char **) name, lenname);
 }

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

/*-----------------------------------------------------------------*/
/*! read a token of type OMF
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param buffer (inout) buffer
 @param c (in) current token
*/ 
/*-----------------------------------------------------------------*/
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMF(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token)
{
 SCSCP_xmlnodeptr node=NULL;
 int retval=1;
 int lenname[2]; /* value and id */
 unsigned char * name[2]; /* address of the value */
 const char * attrname[2]={"hex","id" }; /* attribute name */
 unsigned char valuedbl[8];
 unsigned char valuestrdbl[17];
 const unsigned char hexArray[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
 int j;
 
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMF() - enter\n");
 
 retval = SCSCP_DOMbinaryReadIO_getustring(buffer,0, lenname+1,  name+1, token);
 if (retval)
 {
  retval = SCSCP_buffer_getucharn(buffer, valuedbl, 8);
  for(j=0; j<8; j++) 
  {
      unsigned char val = valuedbl[j];
      valuestrdbl[2*j] = hexArray[val>>4];
      valuestrdbl[2*j+1] = hexArray[val&0xF];
  }
  valuestrdbl[16]='\0';
  lenname[0]=16;
  name[0] = valuestrdbl;
 }
 if (retval)
 {
  node = SCSCP_xmlnode_inittokenattr(doc,owner,token, 2, attrname, (char **) name, lenname);
 }

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

/*-----------------------------------------------------------------*/
/*! read a token of type OMSTR
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param buffer (inout) buffer
 @param c (in) current token
*/ 
/*-----------------------------------------------------------------*/
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMSTR(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token)
{
 SCSCP_xmlnodeptr node=NULL;
 int retval=1;
 int lenname[2]; /* name and id  */
 unsigned char * name[2]; /* address of the value */
 const char *attrname[]={"id"};
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMSTR() - enter\n");
 
 retval = SCSCP_DOMbinaryReadIO_getustring(buffer,1, lenname,  name, token);
 if (retval)
 {
  node = SCSCP_xmlnode_inittokenattrcontent(doc,owner,token, 1,attrname, (char **)(&(name[1])), lenname+1, (char*)name[0], lenname[0]);

 }

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


/*-----------------------------------------------------------------*/
/*! read a token of type OMI
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param buffer (inout) buffer
 @param c (in) current token
*/ 
/*-----------------------------------------------------------------*/
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMIchar(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token)
{
 SCSCP_xmlnodeptr node=NULL;
 int retval=1;
 int lenname[1]; /*  id  */
 unsigned char * name[1]; /* address of the value */
 char c;
 int32_t c32 = 0;
 unsigned char c4[4];
 const char *attrname[1]={"id"};
 
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMIchar(, %u) - enter\n",(unsigned int ) token);
 
 retval = SCSCP_DOMbinaryReadIO_getustring(buffer,0, lenname,  name, token);
 if (retval)
 {
    if (SCSCP_binary_islongflagset(token))  
    {
     retval = SCSCP_buffer_getucharn(buffer,c4,4);
     c32 = ntohl(*(uint32_t *)c4);
    }
    else
    {
     retval = SCSCP_buffer_getchar(buffer,&c);
     c32 = (int32_t)c;
    }
   
   if (retval)
   {
    char cstr[128];
    sprintf(cstr, "%ld", (long)c32); 
   // const char *cstr="             ";
    node = SCSCP_xmlnode_inittokenattrcontent(doc, owner, token,1,attrname, (char **)name, lenname ,cstr, (int)strlen(cstr));
    SCSCP_omnode_setbinary(doc, node, &c32,sizeof(c32));
   }
 }

 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMIchar( c32=%d) - return %p\n",  (int)c32, node);
 return node;
}

/*-----------------------------------------------------------------*/
/*! read a token 2 of type OMI
 @param doc (inout) XML document to build
 @param owner (inout) parent node of this object
 @param buffer (inout) buffer
 @param c (in) current token
*/ 
/*-----------------------------------------------------------------*/
static SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMIstr(SCSCP_xmldocptr doc, SCSCP_xmlnodeptr owner, t_buffer *buffer, unsigned char token)
{
 SCSCP_xmlnodeptr node=NULL;
 int retval=1;
 int lenname[1]; /*  digits + id  */
 unsigned char * name[1]; /* address of the value */
 const char *attrname[]={"id"};
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMIstr(,%u) - enter\n",(unsigned int) token);
 
 retval = SCSCP_DOMbinaryReadIO_getustring(buffer,1, lenname, name, token);
 if (retval)
 {
  node = SCSCP_xmlnode_inittokenattrcontent(doc,owner, token,1,attrname, (char **)(&(name[1])), lenname+1 , (char *)name[0], lenname[0]);

 }

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

/*-----------------------------------------------------------------*/
/*! read the start statement .
 provide the user_data to streamread.
 update the XML document
 @param doc (inout) XML document to update
 @param buffer (inout) buffer
*/ 
/*-----------------------------------------------------------------*/
 SCSCP_xmlnodeptr SCSCP_DOMbinaryReadIO_OMOBJ(SCSCP_xmldocptr doc, t_buffer *buffer)
{
 int retval;
 unsigned char c;
 unsigned char c2[2];
 SCSCP_xmlnodeptr rootnode = NULL;
 SCSCP_xmlnodeptr node = NULL;
 
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMOBJ() - enter\n");
 
  /* read the start statement */
  retval = SCSCP_buffer_getuchar(buffer, &c);
  if (retval==0 || SCSCP_binary_gettoken(c)!=SCSCP_omnodetype_OMOBJ)
  {
   SCSCP_debugprint("token=%d retval=%d\n", (int)SCSCP_binary_gettoken(c), retval);
   retval = 0;
  } 
  /* read version if long flag set */
  else if (SCSCP_binary_islongflagset(c))
  {
   /* read version number */
   retval = SCSCP_buffer_getucharn(buffer, c2,2);
  }
  
  if (retval) 
  {
    rootnode = SCSCP_xmlnode_initroottoken(doc, SCSCP_omnodetype_OMOBJ); 
    if (rootnode) 
    {
     node = SCSCP_DOMbinaryReadIO_parse(doc, rootnode, buffer);
    }
    if (node)
    {
       retval = SCSCP_DOMbinaryReadIO_parsecheck(25, buffer);
    }
    else retval = 0;
    
    if (retval==0)  {SCSCP_debugprint("clear %p\n",rootnode); SCSCP_xmlnode_clear(rootnode);  rootnode = NULL; }
  }
 
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO_OMOBJ() - return %p\n", rootnode);
 return rootnode;
} 
 

/*-----------------------------------------------------------------*/
/*! read the openmath stream encoded in binary.
 provide the user_data to streamread.
 return an XML document
 @param streamread (in)  function to read to stream
 @param user_data (in)  user data (provided to streamread)
*/ 
/*-----------------------------------------------------------------*/
SCSCP_xmldocptr SCSCP_DOMbinaryReadIO(xmlInputReadCallback streamread, void *user_data)
{
 SCSCP_xmldocptr pdoc = NULL;
 SCSCP_xmlnodeptr rootnode = NULL;
 t_buffer buffer;

 SCSCP_debugprint("SCSCP_DOMbinaryReadIO()  -enter\n");
 
 if (SCSCP_buffer_init(&buffer, streamread, user_data, SCSCP_STATUS_IGNORE))
 {
   /* start processing */
  pdoc = SCSCP_xmldoc_init((xmlChar*)"1.0");
  if (pdoc!=NULL)
  {  
   rootnode = SCSCP_DOMbinaryReadIO_OMOBJ(pdoc, &buffer);
   SCSCP_buffer_clear(&buffer);
   /* set root document */
   if (rootnode==NULL) 
   {
    SCSCP_xmldoc_free(pdoc);
    pdoc =NULL;
   }
   else
   {
#if !defined(SCSCP_DISABLE_DEBUG)    
     SCSCP_xmldoc_dump(stdout, pdoc);
#endif
   }
  }
 } 
 
 
 SCSCP_debugprint("SCSCP_DOMbinaryReadIO()  - return %p\n", pdoc);
 return pdoc;
}


