/*
This source file is part of Scol
For the latest info, see http://www.scolring.org

Copyright (c) 2011 Stephane Bisaro, aka Iri <iri@irizone.net>

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt

For others informations, please contact us from http://www.scolring.org/
*/

#include "main_sax.h"


/* destroy any sax2 scol object */
static int ObjSax2Destroy (mmachine m, int handsys, int mobj)
{
    s_xml s;
    int res;

    MMechostr(MSKDEBUG, "ObjSax2Destroy : entering ...\n");

    if (mobj == NIL)
    {
        MMechostr(MSKDEBUG, "ObjSax2Destroy : scol object already destroyed\n");
        return 0;
    }

	/* return the object handle */
    s = (s_xml) MMfetch (m, MTOP (mobj), S_LIBSAX2_HANDLE);
    if (s == NULL)
    {
        MMechostr(MSKDEBUG, "ObjSax2Destroy : object already destroyed\n");
        return 0;
    }

	/*if (s->xml->myDoc != NULL)
        xmlFreeDoc (s->xml->myDoc);*/
    /* it's bad, it's ok */
    #if ((defined linux) || (defined __linux))
    res = pthread_cancel (s->sub->thread);
    if (res != 0)
        MMechostr(MSKDEBUG, "reader_xml2_destroy : thread already canceled\n");
    #elif ((defined _WIN32) || (defined __WIN32__))
    res = TerminateThread (s->sub->thread, 0);
    if (res == 0)
        MMechostr(MSKDEBUG, "reader_xml2_destroy : thread already canceled\n");
    #endif
    free (s->sub);
    free (s);
	/* unregister this object to the Scol machine */
    MMstore (m, MTOP (mobj), S_LIBSAX2_HANDLE, (int) NULL);
    MMechostr(MSKDEBUG, "ObjSax2Destroy : object has been destroyed\n");
    return 0;
}


/* XML2 reflexes */
static void s_xml2_cb_elementStart (void *user_data, const xmlChar *name, const xmlChar **attrs)
{
    int cb, i = 0;
    s_xml s;
    mmachine m;

    s = (s_xml) user_data;
    m = s->sub->sm;

    MMechostr(MSKDEBUG, "s_xml2_cb_elementStart : entering ...\n");

    cb = OBJbeginreflex (m, ObjSax2, (int) s, S_LIBXML2_CB_ELEMENT_START);
    if (cb)
    {
        MMechostr (0, "s_xml2_cb_elementStart : no callback 'ElementStart' defined, error %d\n", cb);
        return;
    }

    Mpushstrbloc (m, (char *) name);
    /*OBJcallreflex (m, 1);
    return;*/

    if (attrs == NULL)
    {
        MMpush (m, NIL);
        OBJcallreflex (m, 2);
        return;
    }
    while (attrs[i] != NULL)
    {
        Mpushstrbloc (m, (char *) attrs[i]);
        i++;
    }
    MMpush (m, NIL);
    while (i > 0)
    {
        MMpush (m, ITOM (2));
        MBdeftab (m);
        i--;
    }
    OBJcallreflex (m, 2);
    return;
}

static void s_xml2_cb_elementEnd (void *user_data, const xmlChar *name)
{
    int cb;
    s_xml s;
    mmachine m;

    s = (s_xml) user_data;
    m = s->sub->sm;

    MMechostr(MSKDEBUG, "s_xml2_cb_elementEnd : entering ...\n");

    cb = OBJbeginreflex (m, ObjSax2, (int) s, S_LIBXML2_CB_ELEMENT_END);
    if (cb)
    {
        MMechostr (0, "s_xml2_cb_elementEnd : no callback 'ElementEnd' defined, error %d\n", cb);
        return;
    }

    Mpushstrbloc (m, (char *) name);
    OBJcallreflex (m, 1);
    return;
}

static void s_xml2_cb_documentStart (void *user_data)
{
    int cb;
    s_xml s;
    mmachine m;

    s = (s_xml) user_data;
    m = s->sub->sm;

    MMechostr(MSKDEBUG, "s_xml2_cb_documentStart : entering ...\n");

    cb = OBJbeginreflex (m, ObjSax2, (int) s, S_LIBXML2_CB_DOCUMENT_START);
    if (cb)
    {
        MMechostr (0, "s_xml2_cb_documentStart : no callback 'DocumentStart' defined, error %d\n", cb);
        return;
    }

    OBJcallreflex (m, 0);
    return;
}

static void s_xml2_cb_documentEnd (void *user_data)
{
    int cb;
    s_xml s;
    mmachine m;

    s = (s_xml) user_data;
    m = s->sub->sm;

    MMechostr(MSKDEBUG, "s_xml2_cb_documentEnd : entering ...\n");

    cb = OBJbeginreflex (m, ObjSax2, (int) s, S_LIBXML2_CB_DOCUMENT_END);
    if (cb)
    {
        MMechostr (0, "s_xml2_cb_documentEnd : no callback 'DocumentEnd' defined, error %d\n", cb);
        return;
    }

    OBJcallreflex (m, 0);
    return;
}

static void s_xml2_cb_characters (void *user_data, const xmlChar *ch, int len)
{
    int cb;
    s_xml s;
    mmachine m;
    char *t;

    s = (s_xml) user_data;
    m = s->sub->sm;

    MMechostr(MSKDEBUG, "s_xml2_cb_characters : entering ...\n");

    cb = OBJbeginreflex (m, ObjSax2, (int) s, S_LIBXML2_CB_CHARACTERS);
    if (cb)
    {
        MMechostr (0, "s_xml2_cb_characters : no callback 'Characters' defined, error %d\n", cb);
        return;
    }

    t = malloc (sizeof (char) * (len + 1));
    strncpy (t, (char *) ch, len);
    t[len] = '\0';
    Mpushstrbloc (m, t);    /* ch can be not null terminated */
    free (t);

    OBJcallreflex (m, 1);
    return;
}

static void s_xml2_cb_comment (void *user_data, const xmlChar *ch)
{
    int cb;
    s_xml s;
    mmachine m;

    s = (s_xml) user_data;
    m = s->sub->sm;

    MMechostr(MSKDEBUG, "s_xml2_cb_comment : entering ...\n");

    cb = OBJbeginreflex (m, ObjSax2, (int) s, S_LIBXML2_CB_COMMENT);
    if (cb)
    {
        MMechostr (0, "s_xml2_cb_comment : no callback 'Comment' defined, error %d\n", cb);
        return;
    }

    Mpushstrbloc (m, (char*) ch);
    OBJcallreflex (m, 1);
    return;
}

static xmlEntityPtr s_xml_cb_getEntity (void *user_data, const xmlChar *name)
{
    int cb;
    s_xml s;
    xmlEntityPtr entity;
    mmachine m;

    s = (s_xml) user_data;
    m = s->sub->sm;
    entity = xmlGetPredefinedEntity (name);

    MMechostr(MSKDEBUG, "s_xml_cb_getEntity : entering ...\n");

    cb = OBJbeginreflex (m, ObjSax2, (int) s, S_LIBXML2_CB_ENTITY);
    if (cb)
    {
        MMechostr (0, "s_xml_cb_getEntity : no callback 'GetEntity' defined, error %d\n", cb);
        return NULL;
    }

    Mpushstrbloc (m, (char*) name);
    OBJcallreflex (m, 1);
    return entity;
}

static void s_xml_cb_reference (void *user_data, const xmlChar *name)
{
    int cb;
    s_xml s;
    mmachine m;

    s = (s_xml) user_data;
    m = s->sub->sm;

    MMechostr(MSKDEBUG, "s_xml_cb_reference : entering ...\n");

    cb = OBJbeginreflex (m, ObjSax2, (int) s, S_LIBXML2_CB_REFERENCE);
    if (cb)
    {
        MMechostr (0, "s_xml_cb_reference : no callback 'Reference' defined, error %d\n", cb);
        return;
    }

    Mpushstrbloc (m, (char*) name);
    OBJcallreflex (m, 1);
    return;
}

static void s_xml_cb_cdataBlock (void *user_data, const xmlChar *cdata, int len)
{
    int cb;
    s_xml s;
    mmachine m;

    s = (s_xml) user_data;
    m = s->sub->sm;

    MMechostr(MSKDEBUG, "s_xml_cb_cdataBlock : entering ...\n");

    cb = OBJbeginreflex (m, ObjSax2, (int) s, S_LIBXML2_CB_CDATA);
    if (cb)
    {
        MMechostr (0, "s_xml_cb_cdataBlock : no callback 'CDataBlock' defined, error %d\n", cb);
        return;
    }

    Mpushstrbloc (m, (char*) cdata);
    MMpush (m, ITOM (len));
    OBJcallreflex (m, 2);
    return;
}

static int s_xml_cb_destroyed (s_xml s)
{
    int cb;
    mmachine m;

    MMechostr(MSKDEBUG, "s_xml_cb_destroyed : entering ...\n");

    m = s->sub->sm;
    cb = OBJbeginreflex (m, ObjSax2, (int) s, S_LIBXML2_CB_DESTROYED);
    if (cb)
    {
        MMechostr (0, "s_xml_cb_destroyed : no callback 'Destroyed' defined, error %d\n", cb);
        return 0;
    }
    OBJcallreflex (m, 0);
    return 0;
}



/* define any SAX callbacks */
static void s_xml2set_callback_sax (s_xml s, int flag)
{
    switch (flag)
    {
        case (S_LIBXML2_CB_DOCUMENT_START) :
            s->sax.startDocument = s_xml2_cb_documentStart;
            return;
        case (S_LIBXML2_CB_DOCUMENT_END) :
            s->sax.endDocument = s_xml2_cb_documentEnd;
            return;
        case (S_LIBXML2_CB_ELEMENT_START) :
            s->sax.startElement = s_xml2_cb_elementStart;
            return;
        case (S_LIBXML2_CB_ELEMENT_END) :
            s->sax.endElement = s_xml2_cb_elementEnd;
            return;
        case (S_LIBXML2_CB_CHARACTERS) :
            s->sax.characters = s_xml2_cb_characters;
            return;
        case (S_LIBXML2_CB_COMMENT) :
            s->sax.comment = s_xml2_cb_comment;
            return;
        case (S_LIBXML2_CB_ENTITY):
            s->sax.getEntity = s_xml_cb_getEntity;
            return;
        case (S_LIBXML2_CB_REFERENCE):
            s->sax.reference = s_xml_cb_reference;
            return;
        case (S_LIBXML2_CB_CDATA):
            s->sax.cdataBlock = s_xml_cb_cdataBlock;
            return;
        default:
            return;
    }
}

/* The Scol callback is defined to be NIL (cancel), so, the SAX callback should be at NULL (better perf) */
static void s_xml2del_callback_sax (s_xml s, int flag)
{
    switch (flag)
    {
        case (S_LIBXML2_CB_DOCUMENT_START) :
            s->sax.startDocument = NULL;
            return;
        case (S_LIBXML2_CB_DOCUMENT_END) :
            s->sax.endDocument = NULL;
            return;
        case (S_LIBXML2_CB_ELEMENT_START) :
            s->sax.startElement = NULL;
            return;
        case (S_LIBXML2_CB_ELEMENT_END) :
            s->sax.endElement = NULL;
            return;
        case (S_LIBXML2_CB_CHARACTERS) :
            s->sax.characters = NULL;
            return;
        case (S_LIBXML2_CB_COMMENT) :
            s->sax.comment = NULL;
            return;
        case (S_LIBXML2_CB_ENTITY):
            s->sax.getEntity = NULL;
            return;
        case (S_LIBXML2_CB_REFERENCE):
            s->sax.reference = NULL;
            return;
        case (S_LIBXML2_CB_CDATA):
            s->sax.cdataBlock = NULL;
            return;
        default:
            return;
    }
}

static void s_xml2set_callback (mmachine m, int flag)
{
    int ms, mcb;
    s_xml s;

    ms = MMget (m, 2);
    if (ms == NIL)
    {
        MMechostr(MSKDEBUG, "s_xml2set_callback error : object is nil - flag = %d\n", flag);
        MMpush (m, NIL);
        return;
    }

    s = (s_xml) MMfetch (m, MTOP (ms), S_LIBSAX2_HANDLE);
    mcb = MMget (m, 1);
    if (mcb == NIL)
        s_xml2del_callback_sax (s, flag);
    else
        s_xml2set_callback_sax (s, flag);
    OBJaddreflex (m, ObjSax2, flag);
    return;
}

#if ((defined linux) || (defined __linux))
static void *s_xml2_read (void * user_data)
#elif ((defined _WIN32) || (defined __WIN32__))
static DWORD WINAPI s_xml2_read (LPVOID user_data)
#endif
{
    int res = 0;
    s_xml s;

    MMechostr(MSKDEBUG, "s_xml2_read : entering ...\n");

    #if ((defined linux) || (defined __linux))
    pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL); /* be sure ... */
    pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    #endif

    s = (s_xml) user_data;
    if (s->sub->buffer != NULL)
        res = xmlSAXUserParseMemory ((&(s->sax)), s, s->sub->buffer, strlen (s->sub->buffer));
    else
        res = xmlSAXUserParseFile ((&(s->sax)), s, s->sub->filename);
    /* MMstore (s->sub->sm , (int) s, S_LIBSAX2_HANDLE, (int) NULL);*/
    OBJdelTM (s->sub->sm, ObjSax2, s->sub->mobj);
    /*free (s->sub);
    free (s);*/
    #if ((defined linux) || (defined __linux))
    s_xml_cb_destroyed (s);
    pthread_exit (0);
    return 0;
    #elif ((defined _WIN32) || (defined __WIN32__))
    s_xml_cb_destroyed (s);
    ExitThread (0);
    #endif
}

static int s_xml2_call_read (mmachine m, s_xml s)
{
    #if ((defined linux) || (defined __linux))
    int res = 0;
    #elif ((defined _WIN32) || (defined __WIN32__))
    DWORD dwThreadId;
    #endif

    MMechostr(MSKDEBUG, "s_xml2_call_read : entering ...\n");

    #if ((defined linux) || (defined __linux))
    s->sub->mthread = pthread_self ();
    res = pthread_create ((&(s->sub->thread)), NULL, s_xml2_read, (void *) s);
    if (res)
        return 1;
    #elif ((defined _WIN32) || (defined __WIN32__))
    s->sub->mthread = GetCurrentThreadId ();
    s->sub->thread = CreateThread (/*(LPSECURITY_ATTRIBUTES) THREAD_TERMINATE*/NULL, 0, s_xml2_read, s, 0, &dwThreadId);
    if (NULL == s->sub->thread)
        winHandleThreadError (TEXT ("s_xml2_call_read"));
    #endif
    /*pthread_join (s->sub->thread, NULL);*/
    return 0;
}






/* PUBLIC */

/* Scol reflexes */
int SSAX_xml2CBdestroyed (mmachine m)
{
    int ms;
    s_xml s;

    MMechostr(MSKDEBUG, "SSAX_xml2CBdestroyed : entering ...\n");

    ms = MMget (m, 2);
    if (ms == NIL)
    {
        MMechostr(MSKDEBUG, "SSAX_xml2CBdestroyed : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }
    s = (s_xml) MMfetch (m, MTOP (ms), S_LIBSAX2_HANDLE);
    OBJaddreflex (m, ObjSax2, S_LIBXML2_CB_DESTROYED);

    return 0;
}

int SSAX_xml2CBelementStart (mmachine m)
{
    MMechostr(MSKDEBUG, "SSAX_xml2CBelementStart : entering ...\n");

    s_xml2set_callback (m, S_LIBXML2_CB_ELEMENT_START);
    return 0;
}

int SSAX_xml2CBelementEnd (mmachine m)
{
    MMechostr(MSKDEBUG, "SSAX_xml2CBelementEnd : entering ...\n");

    s_xml2set_callback (m, S_LIBXML2_CB_ELEMENT_END);
    return 0;
}

int SSAX_xml2CBdocumentStart (mmachine m)
{
    MMechostr(MSKDEBUG, "SSAX_xml2CBdocumentStart : entering ...\n");

    s_xml2set_callback (m, S_LIBXML2_CB_DOCUMENT_START);
    return 0;
}

int SSAX_xml2CBdocumentEnd (mmachine m)
{
    MMechostr(MSKDEBUG, "SSAX_xml2CBdocumentEnd : entering ...\n");

    s_xml2set_callback (m, S_LIBXML2_CB_DOCUMENT_END);
    return 0;
}

int SSAX_xml2CBcharacters (mmachine m)
{
    MMechostr(MSKDEBUG, "SSAX_xml2CBcharacters : entering ...\n");

    s_xml2set_callback (m, S_LIBXML2_CB_CHARACTERS);
    return 0;
}

int SSAX_xml2CBcomment (mmachine m)
{
    MMechostr(MSKDEBUG, "SSAX_xml2CBcomment : entering ...\n");

    s_xml2set_callback (m, S_LIBXML2_CB_COMMENT);
    return 0;
}

int SSAX_xml2CBentity (mmachine m)
{
    MMechostr(MSKDEBUG, "SSAX_xml2CBentity : entering ...\n");

    s_xml2set_callback (m, S_LIBXML2_CB_ENTITY);
    return 0;
}

int SSAX_xml2CBreference (mmachine m)
{
    MMechostr(MSKDEBUG, "SSAX_xml2CBreference : entering ...\n");

    s_xml2set_callback (m, S_LIBXML2_CB_REFERENCE);
    return 0;
}

int SSAX_xml2CBcdata (mmachine m)
{
    MMechostr(MSKDEBUG, "SSAX_xml2CBcdata : entering ...\n");

    s_xml2set_callback (m, S_LIBXML2_CB_CDATA);
    return 0;
}



int SSAX_xml2Read (mmachine m)
{
    int ms;
    int res = 0;
    s_xml s;

    MMechostr(MSKDEBUG, "S_xml2Read : entering ...\n");

    ms = MMpull (m);
    if (ms == NIL)
    {
        MMechostr(MSKDEBUG, "S_xml2Read error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    s = (s_xml) MMfetch (m, MTOP (ms), S_LIBSAX2_HANDLE);
    s->sub->mobj = MTOP (ms);
    res = s_xml2_call_read (m, s);
    if (res != 0)
    {
        MMechostr(MSKDEBUG, "S_xml2Read error : unable to launch the thread : err = %d\n", res);
        MMpush (m, NIL);
        return 0;
    }
    MMpush (m, 0);
    return 0;
}

int SSAX_xml2CreateFromFile (mmachine m)
{
    int mchannel, mfile;
    xmlSAXHandler sax = { 0 };
    s_xml s;

    MMechostr(MSKDEBUG, "S_xml2CreateFromFile : entering ...\n");

    mfile = MMpull (m);
    mchannel = MMget (m, 0);

    if (mchannel == NIL)
    {
        MMechostr(MSKDEBUG, "S_xml2CreateFromFile error : channel is nil\n");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }
    else if (mfile == NIL)
    {
        MMechostr(MSKDEBUG, "S_xml2CreateFromFile error : the file is nil\n");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    s = malloc (sizeof (struct S_xml));
    if (s == NULL)
    {
        MMechostr(MSKDEBUG, "S_xml2CreateFromFile error : not enough memory\n");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }
    s->sub = malloc (sizeof (struct Subxml));
    s->sub->filename = MMstartstr (m, MTOP (mfile));
    s->sub->buffer = NULL;
    s->sub->sm = m;
    s->sax = sax;

    s_xml2create_object_sax (m, s);
    return 0;
}

int SSAX_xml2CreateFromString (mmachine m)
{
    int mchannel, mbuffer;
    xmlSAXHandler sax = { 0 };
    s_xml s;

    MMechostr(MSKDEBUG, "S_xml2CreateFromString : entering ...\n");

    mbuffer = MMpull (m);
    mchannel = MMget (m, 0);

    if (mchannel == NIL)
    {
        MMechostr(MSKDEBUG, "S_xml2CreateFromString error : channel is nil\n");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }
    else if (mbuffer == NIL)
    {
        MMechostr(MSKDEBUG, "S_xml2CreateFromString error : the url is nil\n");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    s = malloc (sizeof (struct S_xml));
    if (s == NULL)
    {
        MMechostr(MSKDEBUG, "S_xml2CreateFromString error : not enough memory\n");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }
    s->sub = malloc (sizeof (struct Subxml));
    s->sub->buffer = MMstartstr (m, MTOP (mbuffer));
    s->sub->filename = NULL;
    s->sub->sm = m;
    s->sax = sax;

    s_xml2create_object_sax (m, s);
    return 0;
}



int SSAX_xml2EncAsk (mmachine m)
{
    int ms, mfrom, mto;
    s_xml s;

    MMechostr(MSKDEBUG, "S_xml2EncAsk : entering ...\n");

    mto = MMpull (m);
    mfrom = MMpull (m);
    ms = MMpull (m);

    if (ms == NIL)
    {
        MMechostr(MSKDEBUG, "S_xml2EncAsk error : object is nil\n");
        MMpush (m, NIL);
        return 0;
    }
    else if ((mto == NIL) || (mfrom == NIL))
    {
        MMechostr(MSKDEBUG, "S_xml2EncAsk error : encodage is nil\n");
        MMpush (m, NIL);
        return 0;
    }

    s = (s_xml) MMfetch (m, MTOP (ms), S_LIBSAX2_HANDLE);
    s->sub->enc_from = MMstartstr (m, MTOP (mfrom));
    s->sub->enc_to = MMstartstr (m, MTOP (mto));
    MMpush (m, ms);
    return 0;
}




/* SAX2 API DEFINITION */
char* libxml2sax_name[SSAX_LIBXML2_PKG_NB] =
{
    "ObjSax2",

    "_sax2CreateFromFile",
    "_sax2CreateFromString",
    "_sax2Read",
    "_sax2EncAsk",
    "_sax2CBelementStart",
    "_sax2CBelementEnd",
    "_sax2CBdocumentStart",
    "_sax2CBdocumentEnd",
    "_sax2CBcharacters",
    "_sax2CBcomment",
    "_sax2CBentity",
    "_sax2CBreference",
    "_sax2CBcdata",
    "_sax2CBdestroyed"
};

int (*libxml2sax_fun[SSAX_LIBXML2_PKG_NB]) (mmachine m) =
{
    NULL,

    SSAX_xml2CreateFromFile,
    SSAX_xml2CreateFromString,
    SSAX_xml2Read,
    SSAX_xml2EncAsk,
    SSAX_xml2CBelementStart,
    SSAX_xml2CBelementEnd,
    SSAX_xml2CBdocumentStart,
    SSAX_xml2CBdocumentEnd,
    SSAX_xml2CBcharacters,
    SSAX_xml2CBcomment,
    SSAX_xml2CBentity,
    SSAX_xml2CBreference,
    SSAX_xml2CBcdata,
    SSAX_xml2CBdestroyed
};

int libxml2sax_narg[SSAX_LIBXML2_PKG_NB] =
{
    TYPTYPE,

    2,
    2,
    1,  /* _sax2Read */
    3,  /* _sax2EncAsk */
    3,   /* _sax2CBelementStart */
    3,   /* _sax2CBelementEnd */
    3,   /* _sax2CBdocumentStart */
    3,   /* _sax2CBdocumentEnd */
    3,   /* _sax2CBcharacters */
    3,   /* _sax2CBcomment */
    3,   /* _sax2CBentity */
    3,   /* _sax2CBreference */
    3,   /* _sax2CBcdata */
    3   /* _sax2CBdestroyed */
};

char* libxml2sax_type[SSAX_LIBXML2_PKG_NB] =
{
    NULL,

    "fun [Chn P] ObjSax2",
    "fun [Chn S] ObjSax2",
    "fun [ObjSax2] I",                                      /* _sax2Read */
    "fun [ObjSax2 S S] ObjSax2",                            /* _sax2EncAsk */
    "fun [ObjSax2 fun [ObjSax2 u0 S [S r1]] u1 u0] ObjSax2",        /* _sax2CBelementStart */
    "fun [ObjSax2 fun [ObjSax2 u0 S] u1 u0] ObjSax2",                /* _sax2CBelementEnd */
    "fun [ObjSax2 fun [ObjSax2 u0] u1 u0] ObjSax2",                 /* _sax2CBdocumentStart */
    "fun [ObjSax2 fun [ObjSax2 u0] u1 u0] ObjSax2",                 /* _sax2CBdocumentEnd */
    "fun [ObjSax2 fun [ObjSax2 u0 S] u1 u0] ObjSax2",                /* _sax2CBcharacters */
    "fun [ObjSax2 fun [ObjSax2 u0 S] u1 u0] ObjSax2",                /* _sax2CBcomment */
    "fun [ObjSax2 fun [ObjSax2 u0 S] u1 u0] ObjSax2",                /* _sax2CBentity */
    "fun [ObjSax2 fun [ObjSax2 u0 S] u1 u0] ObjSax2",                /* _sax2CBreference */
    "fun [ObjSax2 fun [ObjSax2 u0 S I] u1 u0] ObjSax2",              /* _sax2CBcdata */
    "fun [ObjSax2 fun [ObjSax2 u0] u1 u0] ObjSax2"                  /* _sax2CBdestroyed */
};

int SSAX_loadPackage (mmachine m)
{
    int k = 0;

    ObjSax2 = OBJregister (SSAX_LIBXML2_RFL_NB, 1, ObjSax2Destroy, "ObjSax2Type");
    k = PKhardpak (m, "LIBXML2_SAXengine", SSAX_LIBXML2_PKG_NB, libxml2sax_name, libxml2sax_fun, libxml2sax_narg, libxml2sax_type);
    return k;
}





