Mentions légales du service

Skip to content
Snippets Groups Projects
ParserDefinitionPaje.cpp 16.30 KiB
/*
** This file is part of the ViTE project.
**
** This software is governed by the CeCILL-A 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-A 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-A license and that you accept its terms.
**
**
** ViTE developers are (for version 0.* to 1.0):
**
**        - COULOMB Kevin
**        - FAVERGE Mathieu
**        - JAZEIX Johnny
**        - LAGRASSE Olivier
**        - MARCOUEILLE Jule
**        - NOISETTE Pascal
**        - REDONDY Arthur
**        - VUCHENER Clément
**
*/

#include <string>
#include <cstring>
#include <iostream>
#include <fstream>
#include <map>
#include <set>
#include <queue>
/* -- */
#include "common/Errors.hpp"
/* -- */
#include "parser/PajeParser/PajeFileManager.hpp" // temporary
#include "parser/PajeParser/PajeDefinition.hpp"
#include "parser/PajeParser/ParserDefinitionPaje.hpp"
/* -- */
using namespace std;

#ifdef WIN32
#define sscanf sscanf_s
#define sprintf sprintf_s
#endif

#define _OUT_A_DEFINITION 0
#define _IN_A_DEFINITION  1

#define INSERT_FNAME(name, allowed)					\
  {									\
      _FieldNames[_PajeFN_##name]._name    = #name;			\
      _FieldNames[_PajeFN_##name]._id      = _PajeFN_##name;		\
      _FieldNames[_PajeFN_##name]._code    = CODE(_PajeFN_##name);	\
      _FieldNames[_PajeFN_##name]._allowed = allowed;			\
      i++;								\
  }

#define INSERT_EVENT(name, required)			\
  {							\
      _EventDefs[_##name]._name       = #name;		\
      _EventDefs[_##name]._id         = _##name;	\
      _EventDefs[_##name]._trid       = -1;		\
      _EventDefs[_##name]._fdpresent  = 0;		\
      _EventDefs[_##name]._fdrequired = required;	\
      i++;						\
  }


std::map<std::string, int> ParserDefinitionPaje::_EvDefStr2Id;
std::map<std::string, int> ParserDefinitionPaje::_FTypeStr2Code;
bool                       ParserDefinitionPaje::_initialized = false;
int                        ParserDefinitionPaje::_nbparsers   = 0;

ParserDefinitionPaje::ParserDefinitionPaje() {
    int i;

    _state = _OUT_A_DEFINITION;
    _defid = -1;
    _nbparsers++;

    if ( !_initialized ) {
        _initialized = true;

        // Initialize the list of EventDef's names
        _EvDefStr2Id.insert(pair<string, int>("PajeDefineContainerType", _PajeDefineContainerType ));
        _EvDefStr2Id.insert(pair<string, int>("PajeDefineEventType"    , _PajeDefineEventType     ));
        _EvDefStr2Id.insert(pair<string, int>("PajeDefineStateType"    , _PajeDefineStateType     ));
        _EvDefStr2Id.insert(pair<string, int>("PajeDefineVariableType" , _PajeDefineVariableType  ));
        _EvDefStr2Id.insert(pair<string, int>("PajeDefineLinkType"     , _PajeDefineLinkType      ));
        _EvDefStr2Id.insert(pair<string, int>("PajeDefineEntityValue"  , _PajeDefineEntityValue   ));
        _EvDefStr2Id.insert(pair<string, int>("PajeCreateContainer"    , _PajeCreateContainer     ));
        _EvDefStr2Id.insert(pair<string, int>("PajeDestroyContainer"   , _PajeDestroyContainer    ));
        _EvDefStr2Id.insert(pair<string, int>("PajeNewEvent"           , _PajeNewEvent            ));
        _EvDefStr2Id.insert(pair<string, int>("PajeSetState"           , _PajeSetState            ));
        _EvDefStr2Id.insert(pair<string, int>("PajePushState"          , _PajePushState           ));
        _EvDefStr2Id.insert(pair<string, int>("PajePopState"           , _PajePopState            ));
        _EvDefStr2Id.insert(pair<string, int>("PajeSetVariable"        , _PajeSetVariable         ));
        _EvDefStr2Id.insert(pair<string, int>("PajeAddVariable"        , _PajeAddVariable         ));
        _EvDefStr2Id.insert(pair<string, int>("PajeSubVariable"        , _PajeSubVariable         ));
        _EvDefStr2Id.insert(pair<string, int>("PajeStartLink"          , _PajeStartLink           ));
        _EvDefStr2Id.insert(pair<string, int>("PajeEndLink"            , _PajeEndLink             ));

        // Initialize the list of types available for field in EventDef declaration
        _FTypeStr2Code.insert(pair<string, int>("int"   ,_FieldType_Int    ));
        _FTypeStr2Code.insert(pair<string, int>("hex"   ,_FieldType_Hex    ));
        _FTypeStr2Code.insert(pair<string, int>("date"  ,_FieldType_Date   ));
        _FTypeStr2Code.insert(pair<string, int>("double",_FieldType_Double ));
        _FTypeStr2Code.insert(pair<string, int>("string",_FieldType_String ));
        _FTypeStr2Code.insert(pair<string, int>("color" ,_FieldType_Color  ));
    }


    // Initialize the list of Field's names for EventDef declaration
    i = 0;
    _FieldNames.resize( FIELDNAME_SIZEMAX );
    INSERT_FNAME(Time,                _FieldType_Date                    );
    INSERT_FNAME(Name,                _FieldType_Int | _FieldType_String );
    INSERT_FNAME(Alias,               _FieldType_Int | _FieldType_String );
    INSERT_FNAME(Type,                _FieldType_Int | _FieldType_String );
    INSERT_FNAME(Container,           _FieldType_Int | _FieldType_String );
    INSERT_FNAME(StartContainerType,  _FieldType_Int | _FieldType_String );
    INSERT_FNAME(EndContainerType,    _FieldType_Int | _FieldType_String );
    INSERT_FNAME(StartContainer,      _FieldType_Int | _FieldType_String );
    INSERT_FNAME(EndContainer,        _FieldType_Int | _FieldType_String );
    INSERT_FNAME(Color,               _FieldType_Color );
    INSERT_FNAME(Value,               _FieldType_Int | _FieldType_String | _FieldType_Double);
    INSERT_FNAME(Key,                 _FieldType_Int | _FieldType_String );
    INSERT_FNAME(File,                _FieldType_String );
    INSERT_FNAME(Line,                _FieldType_Int | _FieldType_String );

    // Initialize the map between the field names and the associated id
    _nbFieldNames = FIELDNAME_SIZE;
    for(i=0; i<FIELDNAME_SIZE; i++) {
        _FNameStr2Id.insert(pair<string, int>(_FieldNames[i]._name, i));
    }

    // Former types no longer used in Paje format
    _FNameStr2Id.insert(pair<string, int>("ContainerType"      , _PajeFN_ContainerType       ));
    _FNameStr2Id.insert(pair<string, int>("EntityType"         , _PajeFN_EntityType          ));
    _FNameStr2Id.insert(pair<string, int>("SourceContainerType", _PajeFN_SourceContainerType ));
    _FNameStr2Id.insert(pair<string, int>("DestContainerType"  , _PajeFN_DestContainerType   ));
    _FNameStr2Id.insert(pair<string, int>("SourceContainer"    , _PajeFN_SourceContainer     ));
    _FNameStr2Id.insert(pair<string, int>("DestContainer"      , _PajeFN_DestContainer       ));

    // Initialize the list of Events available
    i = 0;
    _EventDefs.resize(PAJE_EVENTDEF_SIZE);
    INSERT_EVENT(PajeDefineContainerType, CODE2(Name) | CODE2(Alias) | CODE2(Type) );
    INSERT_EVENT(PajeDefineEventType    , CODE2(Name) | CODE2(Alias) | CODE2(Type) );
    INSERT_EVENT(PajeDefineStateType    , CODE2(Name) | CODE2(Alias) | CODE2(Type) );
    INSERT_EVENT(PajeDefineVariableType , CODE2(Name) | CODE2(Alias) | CODE2(Type) );
    INSERT_EVENT(PajeDefineEntityValue  , CODE2(Name) | CODE2(Alias) | CODE2(Type)    );
    INSERT_EVENT(PajeDestroyContainer   , CODE2(Name) | CODE2(Alias) | CODE2(Time) | CODE2(Type) );
    INSERT_EVENT(PajeCreateContainer    , CODE2(Name) | CODE2(Alias) | CODE2(Time) | CODE2(Type) | CODE2(Container) );
    INSERT_EVENT(PajeDefineLinkType     , CODE2(Name) | CODE2(Alias) | CODE2(Type) | CODE2(StartContainerType) | CODE2(EndContainerType) );
    INSERT_EVENT(PajePopState           , CODE2(Time) | CODE2(Type)  | CODE2(Container) );
    INSERT_EVENT(PajeSetState           , CODE2(Time) | CODE2(Type)  | CODE2(Container) | CODE2(Value) );
    INSERT_EVENT(PajePushState          , CODE2(Time) | CODE2(Type)  | CODE2(Container) | CODE2(Value) );
    INSERT_EVENT(PajeNewEvent           , CODE2(Time) | CODE2(Type)  | CODE2(Container) | CODE2(Value) );
    INSERT_EVENT(PajeSetVariable        , CODE2(Time) | CODE2(Type)  | CODE2(Container) | CODE2(Value) );
    INSERT_EVENT(PajeAddVariable        , CODE2(Time) | CODE2(Type)  | CODE2(Container) | CODE2(Value) );
    INSERT_EVENT(PajeSubVariable        , CODE2(Time) | CODE2(Type)  | CODE2(Container) | CODE2(Value) );
    INSERT_EVENT(PajeStartLink          , CODE2(Time) | CODE2(Type)  | CODE2(Container) | CODE2(Value) | CODE2(Key) | CODE2(StartContainer) );
    INSERT_EVENT(PajeEndLink            , CODE2(Time) | CODE2(Type)  | CODE2(Container) | CODE2(Value) | CODE2(Key) | CODE2(EndContainer) );
}

ParserDefinitionPaje::~ParserDefinitionPaje() {
    int i;

    // Free the string to store extra names
    for( i=FIELDNAME_SIZE ; i<_nbFieldNames; i++) {
        delete[] _FieldNames[i]._name;
    }
    _FieldNames.clear();
    _EventDefs.clear();
    _FNameStr2Id.clear();
    _EvDefTrId2Id.clear();

    _nbparsers--;
    if ( (_nbparsers == 0) && _initialized ) {
        _FTypeStr2Code.clear();
        _EvDefStr2Id.clear();
        _initialized = false;
    }
}

void ParserDefinitionPaje::enter_definition(const PajeLine_t *line){
    int   defid, trid;
    char *defname = line->_tokens[2];
    char *tridstr = line->_tokens[3];
    // The name is missing
    if(defname == NULL) {
        Error::set(Error::VITE_ERR_EXPECT_NAME_DEF, line->_id, Error::VITE_ERRCODE_ERROR);
        return;
    }

    // The id is missing
    if(tridstr == NULL) {
        Error::set(Error::VITE_ERR_EXPECT_ID_DEF, line->_id, Error::VITE_ERRCODE_ERROR);
        return;
    }

    // If we are already trying to define an event,
    // we close it before starting a new one
    if(_state == _IN_A_DEFINITION){
        Error::set(Error::VITE_ERR_EXPECT_END_DEF, line->_id, Error::VITE_ERRCODE_WARNING);
        leave_definition(line);
    }

    // Get the trid of the definition in the trace (trid)
    if(sscanf(tridstr, "%u", &trid) != 1){
        Error::set(Error::VITE_ERR_EXPECT_ID_DEF, line->_id, Error::VITE_ERRCODE_ERROR);
        return;
    }

    // Try to find the name
    if ( _EvDefStr2Id.find(defname) == _EvDefStr2Id.end() ) {
        Error::set(Error::VITE_ERR_UNKNOWN_EVENT_DEF, line->_id, Error::VITE_ERRCODE_ERROR);
        return;
    }

    defid = _EvDefStr2Id[defname];

    // Check if it is the first time we see this Event
    if ( _EventDefs[defid]._trid != -1 ) {
        Error::set(Error::VITE_ERR_EVENT_ALREADY_DEF, line->_id, Error::VITE_ERRCODE_ERROR);
        return;
    }

    // Extra tokens are not supported
    if(line->_nbtks > 4){
        Error::set(Error::VITE_ERR_EXTRA_TOKEN, line->_id, Error::VITE_ERRCODE_WARNING);
    }

    // Everything is ok, we start to store the event
    _EventDefs[defid]._trid = trid;
    _defid = defid;
    _state = _IN_A_DEFINITION;
    _EvDefTrId2Id.insert(pair<int, int>(trid, defid));

    return;
}

void ParserDefinitionPaje::leave_definition(const PajeLine_t *line){

    // We can't end a definition if we are not in one !!!
    if(_state != _IN_A_DEFINITION){
        Error::set(Error::VITE_ERR_EXPECT_EVENT_DEF, line->_id, Error::VITE_ERRCODE_WARNING);
        return;
    }

    _state = _OUT_A_DEFINITION;

    // Check that the event has been correctly defined
    if( !(PajeDef::check_definition(&_EventDefs[_defid])) ) {
        Error::set(Error::VITE_ERR_EVENT_NOT_CORRECT
                   + PajeDef::print_string(&_FieldNames, &_EventDefs[_defid]),
                   line->_id, Error::VITE_ERRCODE_ERROR);

        // We remove the definition
        _EvDefTrId2Id.erase(_EventDefs[_defid]._trid);
        _EventDefs[_defid]._fields.clear();
        _EventDefs[_defid]._trid = -1;
        return;
    }

#ifdef DBG_PARSER_PAJE
    PajeDef::print(&_FieldNames,&_EventDefs[_defid]);
#endif
    _defid = -1;
}

void ParserDefinitionPaje::add_field_to_definition(const PajeLine_t *line){
    char *fieldname = line->_tokens[1];
    char *fieldtype = line->_tokens[2];
    int   idname;
    int   idtype;
    Field fd;

    // Check we are currently defining an event
    if (_state == _OUT_A_DEFINITION) {
        Error::set(Error::VITE_ERR_EXPECT_EVENT_DEF,   line->_id, Error::VITE_ERRCODE_ERROR);
        return;
    }

    // If fieldtype is not defined
    if (fieldname == NULL) {
        Error::set(Error::VITE_ERR_FIELD_NAME_MISSING, line->_id, Error::VITE_ERRCODE_ERROR);
        return;
    }

    // If fieldtype is not defined
    if (fieldtype == NULL) {
        Error::set(Error::VITE_ERR_FIELD_TYPE_MISSING, line->_id, Error::VITE_ERRCODE_ERROR);
        return;
    }

    idtype = _FTypeStr2Code[fieldtype];

    // Type unknown
    if ( idtype  == 0 ) {
        Error::set(Error::VITE_ERR_FIELD_TYPE_UNKNOWN + fieldtype, line->_id, Error::VITE_ERRCODE_ERROR);
        return;
    }

    // Name unknown, we have to store it
    if ( _FNameStr2Id.find(fieldname) == _FNameStr2Id.end() ) {
        int   size  = strlen(fieldname)+1;
        char *newfn = new char[size];
#ifndef WIN32
        strcpy(newfn, fieldname);
#else
        strcpy_s(newfn, size, fieldname);
#endif

        _FieldNames[_nbFieldNames]._name    = newfn;
        _FieldNames[_nbFieldNames]._id      = _nbFieldNames;
        _FieldNames[_nbFieldNames]._code    = (1 << _nbFieldNames);
        _FieldNames[_nbFieldNames]._allowed = idtype;
        idname = _nbFieldNames;
        _nbFieldNames++;
    } else {
        idname =_FNameStr2Id[fieldname];
    }

    // check if type is allowed
    if ( !( idtype & _FieldNames[idname]._allowed ) ) {
        Error::set(Error::VITE_ERR_FIELD_NOT_ALLOWED + "(" + fieldname + "," + fieldtype + ")", line->_id, Error::VITE_ERRCODE_ERROR);
        return;
    }

    // Extra tokens are not supported
    if(line->_nbtks > 3){
        Error::set(Error::VITE_ERR_EXTRA_TOKEN, line->_id, Error::VITE_ERRCODE_WARNING);
    }

    // We had the field and his type to the definition
    fd._idname = idname;
    fd._idtype = idtype;
    _EventDefs[_defid]._fields.push_back( fd );
    _EventDefs[_defid]._fdpresent |= _FieldNames[idname]._code;
}


void ParserDefinitionPaje::store_definition(const PajeLine_t *line){
    string token = line->_tokens[1];

    // We need almost two tokens '%' and "[End]EventDef"
    if(line->_nbtks < 2){
        Error::set(Error::VITE_ERR_EMPTY_DEF, line->_id, Error::VITE_ERRCODE_WARNING);
        return;
    }

    // We start a definition
    if (token.compare("EventDef") == 0){
        enter_definition(line);
    }
    // We stop a definition
    else if (token.compare("EndEventDef") == 0) {
        leave_definition(line);
        if(line->_nbtks > 2){
            Error::set(Error::VITE_ERR_EXTRA_TOKEN, line->_id, Error::VITE_ERRCODE_WARNING);
        }
    }
    // Add a field to the definition
    else{
        add_field_to_definition(line);
    }

}

PajeDefinition *ParserDefinitionPaje::getDefFromTrid(int trid) {
    if ( _EvDefTrId2Id.find(trid) == _EvDefTrId2Id.end() ) {
        return NULL;
    } else {
        return &(_EventDefs[_EvDefTrId2Id[trid]]);
    }
}

void ParserDefinitionPaje::print_definitions() {
    map<int, int>::iterator it     = _EvDefTrId2Id.begin();
    map<int, int>::iterator it_end = _EvDefTrId2Id.end();

    for (; it != it_end ; ++ it){

        cout << "###### " << (*it).first << endl;
        // (*it).second represents the current definition
        PajeDef::print(&_FieldNames, &_EventDefs[(*it).second]);
    }
}

int ParserDefinitionPaje::definitions_number() const {
    return _EvDefTrId2Id.size();
}

const vector<PajeFieldName> *ParserDefinitionPaje::get_FieldNames() const {
    return &_FieldNames;
}