www.pudn.com > xvoice-0.8.1.rar > ParseEventStream.cc


/**
 * ParseEventStream.cc
 *
 * Description: parse an event stream XML, and create an EventStream object
 *
 * Copyright (c) 1999, David Z. Creemer.
 * See the LICENSE file. All rights not granted therein are reserved.
 *
 * @author David Z. Creemer
 * @author Tom Doris
 * @version 1.0
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include 
#include 
#include 
#include 

#include 
#include 
#include 

#include "expat/xmlparse.h"
#include "EventStream.h"
#include "ParseEventStream.h"
#include "Error.h"
#include "Voice.h"

enum appType { APPAPP, APPDEF, APPVOC }; 
struct configCtx {
    application* app;
    appType type;
    applicationList* applist;
    bool inCdata;
    const char *gDir;
    int gFd;
};

typedef struct configCtx configCtx;

/* userData is the EventStream object created in ParseFile */

static void startElement( void *userData, const char *name, const char **attrs )
{
    configCtx *ctx = (configCtx *)userData;
    const char *aname = NULL, *expr = NULL;

    if (strcasecmp(name, "xvoice") == 0) return;

    dbgprintf(("name %s\n", name));
    while  (*attrs != NULL) {
        dbgprintf(("attribute %s\n", *attrs));
        if (strcasecmp(*attrs, "name") == 0) aname = *++attrs;
        else if (strcasecmp(*attrs, "expr") == 0) expr = *++attrs;
        else attrs++;
        attrs++;
    }
    if (aname == NULL) LogMessage(E_FATAL, "No application name given!");
    if (strcasecmp(name, "application") == 0) {
        if (expr == NULL) expr = aname;
        ctx->app = new application(aname,expr);
        ctx->type = APPAPP;
    } else if (strcasecmp(name, "vocab") == 0) {
        ctx->app = new application(aname,"");
        ctx->type = APPVOC;
    } else if (strcasecmp(name, "define") == 0) {
        ctx->app = new application(aname,"");
        ctx->type = APPDEF;
    }
}

static void endElement(void *userData, const char *name)
{
    configCtx *ctx = (configCtx *)userData;
    if(strcasecmp(name, "application") == 0 ) {
        ctx->applist->push_back(*ctx->app);
    } else if (strcasecmp(name, "vocab") == 0 ) {
        delete ctx->app;
    } else if (strcasecmp(name, "define") == 0 ) {
        delete ctx->app;
    }
}

static void endCdataSection(void *userData)
{
    configCtx *ctx = (configCtx *)userData;
    char *name = ctx->app->name;
    close(ctx->gFd);
    dbgprintf(("wrote bnf\n"));
    if (ctx->type != APPDEF) {
        compileGrammar(name);
    }
    ctx->inCdata = false;
}

static void startCdataSection(void *userData)
{       
    configCtx *ctx = (configCtx *)userData;
    close(ctx->gFd);
    fstring buff;
    buff.appendf("%s/%s.bnf", ctx->gDir, ctx->app->name);
    dbgprintf(("opening bnf %s\n",buff.c_str()));
    ctx->gFd = open( buff.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0644);
    if ( ctx->gFd == -1 )
    {
        LogMessage(E_FATAL, "Could not open bnf file %s", buff.c_str());
    }

    ctx->inCdata = true;
}

static void handleCharData(void *userData, const XML_Char *s, int len)
{
    configCtx *ctx = (configCtx *)userData;
    if (ctx->inCdata == true) {
        dbgprintf(("writing %d chars\n",len));
        if (write(ctx->gFd, s, len) < 0) 
            LogMessage(E_FATAL, "Error writing to bnf");
    }
}


applicationList* parseFile( const char* filename, const char* gdir)
{
    applicationList* es = new applicationList();
    configCtx ctx;
    ctx.gDir = gdir;
    ctx.gFd = -1;
    ctx.applist = es;
    ctx.inCdata = false;
    int fd = open(filename, O_RDONLY);

    if (fd == -1)
    {
        delete es;
        return NULL;
    }

    off_t fsize = lseek(fd, 0, SEEK_END);

    char* bytes = (char*) mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0);

    if (bytes != MAP_FAILED)
    {
        int done;
        XML_Parser parser = XML_ParserCreate(NULL);
        //es becomes the "userData" arg to the handlers:
        XML_SetUserData(parser, &ctx);
        XML_SetElementHandler(parser, startElement, endElement);
        XML_SetCharacterDataHandler(parser, handleCharData);
        XML_SetCdataSectionHandler(parser, startCdataSection, endCdataSection);
        do
        {
            if (!XML_Parse(parser, bytes, fsize, done))
            {
                LogMessage(E_CONFIG, "%s at line %d\n",
                        XML_ErrorString(XML_GetErrorCode(parser)),
                        XML_GetCurrentLineNumber(parser));

                delete es;
                return NULL;
            }
        }
        while (!done);

        XML_ParserFree(parser);
        munmap(bytes, fsize);
    }
    else
    {
        LogMessage(E_FATAL, "MMAP error");
        delete es;
        return NULL;
    }

    close(fd);

    return es;
}


static void startElementB(void *userData, const char *name, const char **attrs)
{
    dbgprintf(("name %s attr %s\n", name, attrs[0]));
    EventStream *es = (EventStream*) userData;
    if (strcasecmp(name, "key") == 0)
    {
        es->parseKeyEvent(attrs);
    }
    else if (strcasecmp(name, "mouse") == 0)
    {
        es->parseMouseEvent(attrs);
    }
    else if (strcasecmp(name, "grammar") == 0)
    {
        es->parseGrammarEvent(attrs);
    }
}

static void endElementB(void *userData, const char *name)
{
    dbgprintf(("name %s\n", name));
}

EventStream* parseBuff(const char* bytes)
{
    EventStream* es = new EventStream();
    off_t fsize = strlen(bytes);
    XML_Parser parser = XML_ParserCreate(NULL);

    //es becomes the "userData" arg to the handlers:
    XML_SetUserData(parser, es);
    XML_SetElementHandler(parser, startElementB, endElementB);
    XML_Parse( parser, "", 3, 0); /* keeps the parser happy */
    if (!XML_Parse(parser, bytes, fsize, 0))
    {
        LogMessage(E_CONFIG, "%s at line %d\n",
                XML_ErrorString(XML_GetErrorCode(parser)),
                XML_GetCurrentLineNumber(parser));

        delete es;
        return NULL;
    }
    XML_Parse(parser, "", 3, 1); /* keeps the parser happy */

    XML_ParserFree(parser);

    return es;
}