diff options
Diffstat (limited to 'misc/search.cpp')
-rw-r--r-- | misc/search.cpp | 795 |
1 files changed, 795 insertions, 0 deletions
diff --git a/misc/search.cpp b/misc/search.cpp new file mode 100644 index 0000000..deee8b0 --- /dev/null +++ b/misc/search.cpp @@ -0,0 +1,795 @@ +/* + * File: search.cpp + * Author: savop + * + * Created on 27. August 2009, 21:21 + */ + +// uncomment this to enable debuging of the grammar +//#define BOOST_SPIRIT_DEBUG + +#include <string> +#include "search.h" +#include "../common.h" +#include <boost/spirit.hpp> +#include <boost/function.hpp> +#include <boost/bind.hpp> + +using namespace std; +using namespace boost; +using namespace boost::spirit; + +// This is the standard callback function which will be overloaded +// with all the specific callbacks +typedef function2<void, const char*, const char*> expCallback; +typedef function1<void, const char*> propCallback; +typedef function1<void, const char*> opCallback; +typedef function1<void, const char> charCallback; +typedef function1<void, int> intCallback; + +// The defined ColumnNames +struct cProperties : symbols<const char*> { +//struct cProperties : symbols<> { + cProperties(){ + add +// (UPNP_PROP_OBJECTID, UPNP_PROP_OBJECTID) +// (UPNP_PROP_PARENTID, UPNP_PROP_PARENTID) +// (UPNP_PROP_RESTRICTED, UPNP_PROP_RESTRICTED) +// (UPNP_PROP_CLASS, UPNP_PROP_CLASS) +// (UPNP_PROP_CLASSNAME, UPNP_PROP_CLASSNAME) +// (UPNP_PROP_WRITESTATUS, UPNP_PROP_WRITESTATUS) +// (UPNP_PROP_CHILDCOUNT, UPNP_PROP_CHILDCOUNT) +// (UPNP_PROP_REFERENCEID, UPNP_PROP_REFERENCEID) +// (UPNP_PROP_TITLE, UPNP_PROP_TITLE) +// (UPNP_PROP_CREATOR, UPNP_PROP_CREATOR) +// ("dc:description", "Description") +// ("dc:date", "Date") +// ("res", "Resource") +// ("res@bitrate", "Bitrate") +// ("res@duration", "Duration") +// ("res@size", "Size") +// ("res@sampleFrequency", "SampleFrequency") +// ("res@resolution", "Resolution") +// ("res@protocolInfo", "ProtocolInfo") +// ; + (UPNP_PROP_OBJECTID,UPNP_PROP_OBJECTID) + (UPNP_PROP_PARENTID,UPNP_PROP_PARENTID) + (UPNP_PROP_TITLE,UPNP_PROP_TITLE) + (UPNP_PROP_CREATOR,UPNP_PROP_CREATOR) + (UPNP_PROP_RESTRICTED,UPNP_PROP_RESTRICTED) + (UPNP_PROP_WRITESTATUS,UPNP_PROP_WRITESTATUS) + (UPNP_PROP_CLASS,UPNP_PROP_CLASS) + (UPNP_PROP_CLASSNAME,UPNP_PROP_CLASSNAME) + (UPNP_PROP_SEARCHCLASS,UPNP_PROP_SEARCHCLASS) + (UPNP_PROP_SCLASSDERIVED,UPNP_PROP_SCLASSDERIVED) + (UPNP_PROP_REFERENCEID,UPNP_PROP_REFERENCEID) + (UPNP_PROP_SCLASSNAME,UPNP_PROP_SCLASSNAME) + (UPNP_PROP_SEARCHABLE,UPNP_PROP_SEARCHABLE) + (UPNP_PROP_CHILDCOUNT,UPNP_PROP_CHILDCOUNT) + (UPNP_PROP_RESOURCE,UPNP_PROP_RESOURCE) + (UPNP_PROP_PROTOCOLINFO,UPNP_PROP_PROTOCOLINFO) + (UPNP_PROP_SIZE,UPNP_PROP_SIZE) + (UPNP_PROP_DURATION,UPNP_PROP_DURATION) + (UPNP_PROP_BITRATE,UPNP_PROP_BITRATE) + (UPNP_PROP_SAMPLEFREQUENCE,UPNP_PROP_SAMPLEFREQUENCE) + (UPNP_PROP_BITSPERSAMPLE,UPNP_PROP_BITSPERSAMPLE) + (UPNP_PROP_NOAUDIOCHANNELS,UPNP_PROP_NOAUDIOCHANNELS) + (UPNP_PROP_COLORDEPTH,UPNP_PROP_COLORDEPTH) + (UPNP_PROP_RESOLUTION,UPNP_PROP_RESOLUTION) + (UPNP_PROP_GENRE,UPNP_PROP_GENRE) + (UPNP_PROP_LONGDESCRIPTION,UPNP_PROP_LONGDESCRIPTION) + (UPNP_PROP_PRODUCER,UPNP_PROP_PRODUCER) + (UPNP_PROP_RATING,UPNP_PROP_RATING) + (UPNP_PROP_ACTOR,UPNP_PROP_ACTOR) + (UPNP_PROP_DIRECTOR,UPNP_PROP_DIRECTOR) + (UPNP_PROP_DESCRIPTION,UPNP_PROP_DESCRIPTION) + (UPNP_PROP_PUBLISHER,UPNP_PROP_PUBLISHER) + (UPNP_PROP_LANGUAGE,UPNP_PROP_LANGUAGE) + (UPNP_PROP_RELATION,UPNP_PROP_RELATION) + (UPNP_PROP_STORAGEMEDIUM,UPNP_PROP_STORAGEMEDIUM) + (UPNP_PROP_DVDREGIONCODE,UPNP_PROP_DVDREGIONCODE) + (UPNP_PROP_CHANNELNAME,UPNP_PROP_CHANNELNAME) + (UPNP_PROP_SCHEDULEDSTARTTIME,UPNP_PROP_SCHEDULEDSTARTTIME) + (UPNP_PROP_SCHEDULEDENDTIME,UPNP_PROP_SCHEDULEDENDTIME) + (UPNP_PROP_ICON,UPNP_PROP_ICON) + (UPNP_PROP_REGION,UPNP_PROP_REGION) + (UPNP_PROP_CHANNELNR,UPNP_PROP_CHANNELNR) + (UPNP_PROP_RIGHTS,UPNP_PROP_RIGHTS) + (UPNP_PROP_RADIOCALLSIGN,UPNP_PROP_RADIOCALLSIGN) + (UPNP_PROP_RADIOSTATIONID,UPNP_PROP_RADIOSTATIONID) + (UPNP_PROP_RADIOBAND,UPNP_PROP_RADIOBAND) + (UPNP_PROP_CONTRIBUTOR,UPNP_PROP_CONTRIBUTOR) + (UPNP_PROP_DATE,UPNP_PROP_DATE) + (UPNP_PROP_ALBUM,UPNP_PROP_ALBUM) + (UPNP_PROP_ARTIST,UPNP_PROP_ARTIST) + (UPNP_PROP_DLNA_CONTAINERTYPE,UPNP_PROP_DLNA_CONTAINERTYPE) + ; + } +} Properties; + +struct cOperators : symbols<const char*> { + cOperators(){ + add + ("=", "==") + ("!=", "!=") + ("<", "<") + (">", ">") + ("<=", "<=") + (">=", ">=") + ("contains", "LIKE") + ("doesNotContain", "NOT LIKE") + ("derivedfrom", "derivedFrom") + ; + } +} Operators; + +struct cConcatOperators : symbols<const char*> { + cConcatOperators(){ + add + ("and", "AND") + ("or", "OR") + ; + } +} ConcatOperators; + +struct cExistanceOperator : symbols<const char*> { + cExistanceOperator(){ + add + ("true", "NOT NULL") + ("false", "NULL") + ; + } +} Existance; + +// THE GRAMMAR! +// This is the grammar including the functors which calls the member functions +// of search. The callback definitions at the end of the constructor are +// essential. DO NOT MODIFY if you don't know how! +struct cSearchGrammar : public boost::spirit::grammar<cSearchGrammar> { + // The callbacks members + charCallback &endBrackedExp; + expCallback &pushSimpleExp; + opCallback &pushOperator; + expCallback &pushQuotedValue; + opCallback &pushExistance; + propCallback &pushProperty; + opCallback &pushConcatOp; + charCallback &startBrackedExp; + + // Constructor with the callback functions + cSearchGrammar( + charCallback &endBrackedExp, + expCallback &pushSimpleExp, + opCallback &pushOperator, + expCallback &pushQuotedValue, + opCallback &pushExistance, + propCallback &pushProperty, + opCallback &pushConcatOp, + charCallback &startBrackedExp): + endBrackedExp(endBrackedExp), + pushSimpleExp(pushSimpleExp), + pushOperator(pushOperator), + pushQuotedValue(pushQuotedValue), + pushExistance(pushExistance), + pushProperty(pushProperty), + pushConcatOp(pushConcatOp), + startBrackedExp(startBrackedExp){} + + template <typename scanner> + struct definition { + boost::spirit::rule<scanner> searchCrit, searchExp, logOp, \ + relExp, binOp, relOp, stringOp, \ + existsOp, boolVal, quotedVal, \ + wChar, property, brackedExp, exp; + const boost::spirit::rule<scanner> &start(){ + return searchCrit; + } + definition(const cSearchGrammar &self){ + /*************************************************************************\ + * * + * The grammar of a UPnP search expression * + * * + * searchCrit ::= searchExp | asterisk * + * * + * searchExp ::= relExp | * + * searchExp wChar+ logOp wChar+ searchExp | * + * '(' wChar* searchExp wChar* ')' * + * * + * logOp ::= 'and' | 'or' * + * * + * relExp ::= property wChar+ binOp wChar+ quotedVal | * + * property wChar* existsOp wChar+ boolVal * + * * + * binOp ::= relOp | stringOp * + * * + * relOp ::= '=' | '!=' | '<' | '<=' | '>' | '>=' * + * * + * stringOp ::= 'contains' | 'doesNotContain' | 'derivedfrom' * + * * + * existsOp ::= 'exists' * + * * + * boolVal ::= 'true' | 'false' * + * * + * quotedVal ::= dQuote escapedQuote dQuote * + * * + * wChar ::= space | hTab | lineFeed | * + * vTab | formFeed | return * + * * + * property ::= See ContentDirectory Section 2.4 * + * * + * escapedQuote ::= See ContentDirectory Section 2.3.1 * + * * + \*************************************************************************/ + searchCrit = searchExp | "*"; + + searchExp = exp >> *(+wChar >> logOp >> +wChar >> exp); + ; + + exp = relExp + | brackedExp + ; + + brackedExp = confix_p( + ch_p('(')[self.startBrackedExp], + *wChar >> searchExp >> *wChar, + ch_p(')')[self.endBrackedExp] + ) + ; + + logOp = ConcatOperators[self.pushConcatOp] + ; + + relExp = (property >> +wChar >> binOp >> +wChar >> quotedVal) [self.pushSimpleExp] + | (property >> +wChar >> existsOp >> +wChar >> boolVal) [self.pushSimpleExp] + ; + + binOp = Operators[self.pushOperator] + ; + + existsOp = str_p("exists") + ; + + boolVal = Existance[self.pushExistance] + ; + + quotedVal = confix_p('"', (*c_escape_ch_p)[self.pushQuotedValue], '"'); + + wChar = space_p; + + property = Properties[self.pushProperty] + ; + + // Debug mode + #ifdef BOOST_SPIRIT_DEBUG + BOOST_SPIRIT_DEBUG_NODE(searchCrit); + BOOST_SPIRIT_DEBUG_NODE(searchExp); + BOOST_SPIRIT_DEBUG_NODE(logOp); + BOOST_SPIRIT_DEBUG_NODE(relExp); + BOOST_SPIRIT_DEBUG_NODE(binOp); + BOOST_SPIRIT_DEBUG_NODE(relOp); + BOOST_SPIRIT_DEBUG_NODE(stringOp); + BOOST_SPIRIT_DEBUG_NODE(existsOp); + BOOST_SPIRIT_DEBUG_NODE(boolVal); + BOOST_SPIRIT_DEBUG_NODE(quotedVal); + BOOST_SPIRIT_DEBUG_NODE(wChar); + BOOST_SPIRIT_DEBUG_NODE(property); + #endif + } + }; +}; + +struct cSortGrammar : public boost::spirit::grammar<cSortGrammar> { + // The callback members + propCallback &pushProperty; + charCallback &pushDirection; + + cSortGrammar( + propCallback &pushProperty, + charCallback &pushDirection): + pushProperty(pushProperty), + pushDirection(pushDirection){} + + template <typename scanner> + struct definition { + boost::spirit::rule<scanner> sortCrit, sortExp, property, direction; + + const boost::spirit::rule<scanner> &start(){ + return sortCrit; + } + definition(const cSortGrammar &self){ + sortCrit = sortExp + ; + + sortExp = direction >> property >> *(ch_p(',') >> sortExp) + ; + + direction = sign_p[self.pushDirection] + ; + + property = Properties[self.pushProperty] + ; + } + }; +}; + +struct cFilterGrammar : public boost::spirit::grammar<cFilterGrammar> { + // The callback members + propCallback &pushProperty; + charCallback &pushAsterisk; + + cFilterGrammar( + propCallback &pushProperty, + charCallback &pushAsterisk): + pushProperty(pushProperty), + pushAsterisk(pushAsterisk){} + + template <typename scanner> + struct definition { + boost::spirit::rule<scanner> filterCrit, filterExp, property; + + const boost::spirit::rule<scanner> &start(){ + return filterCrit; + } + definition(const cFilterGrammar &self){ + filterCrit = filterExp + | ch_p('*')[self.pushAsterisk] + ; + + filterExp = property >> *(ch_p(',') >> filterExp) + ; + + property = Properties[self.pushProperty] + ; + } + }; +}; + + /**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cSearch::pushEndBrackedExp(const char){ + MESSAGE("Pushing closing bracket"); + if(asprintf(&this->SQLWhereStmt, "%s)", this->SQLWhereStmt)==-1){ + ERROR("Unable to allocate SQL Statement"); + return; + } +} + +void cSearch::pushExpression(const char*, const char*){ + + const char* Property = this->CurrentProperty; + const char* Operator = this->CurrentOperator; + const char* Value = this->CurrentValue; + + if(Property && Operator && Value){ + char* Statement; + long int IntegerValue; + + if(sscanf(Value, "%ld", &IntegerValue)!=EOF && sscanf(Value, "%*4d-%*2d-%*2d")==EOF){ + MESSAGE("Popping '%s %s %ld'",Property, Operator, IntegerValue); + if(asprintf(&Statement, "%s %s %ld", Property, Operator, IntegerValue)==-1){ + ERROR("Failed to allocated memory for statement."); + return; + } + } + else if(!strcasecmp(Operator, "IS")){ + MESSAGE("Popping '%s %s %s'", Property, Operator, Value); + if(asprintf(&Statement, "%s %s %s", Property, Operator, Value)==-1){ + ERROR("Failed to allocated memory for statement."); + return; + } + } + else { + MESSAGE("Popping '%s %s \"%s\"'",Property, Operator, Value); + if(asprintf(&Statement, "%s %s '%s'", Property, Operator, Value)==-1){ + ERROR("Failed to allocated memory for statement."); + return; + } + } + + if(asprintf(&this->SQLWhereStmt, "%s %s", this->SQLWhereStmt, Statement)==-1){ + ERROR("Unable to allocate SQL Statement"); + return; + } + + } + return; +} + +void cSearch::pushProperty(const char* Property){ + this->CurrentProperty = strdup(Property); + MESSAGE("Property %s added",Property); +} + +void cSearch::pushOperator(const char* Operator){ + this->CurrentOperator = strdup(Operator); + MESSAGE("Operator %s added",Operator); +} + +void cSearch::pushValue(const char* Start, const char* End){ + const char* Value = string(Start,End).c_str(); + if(!Value || !strcmp(Value,"")) return; + + this->CurrentValue = strdup(Value); + MESSAGE("Value %s added", Value); +} + +void cSearch::pushExistance(const char* Exists){ + this->CurrentValue = strdup(Exists); + this->CurrentOperator = strdup("IS"); + MESSAGE("Existance expression called. '%s'", Exists); +} + +void cSearch::pushConcatOp(const char* Operator){ + if(asprintf(&this->SQLWhereStmt, "%s %s ", this->SQLWhereStmt, Operator)==-1){ + ERROR("Unable to allocate SQL Statement"); + return; + } + + MESSAGE("Concatenation expression called. '%s'", Operator); +} + +void cSearch::pushStartBrackedExp(const char){ + MESSAGE("Pushing opening bracket"); + if(asprintf(&this->SQLWhereStmt, "%s(", this->SQLWhereStmt)==-1){ + ERROR("Unable to allocate SQL Statement"); + return; + } +} + + /**********************************************\ + * * + * The rest * + * * + \**********************************************/ + +cSearch* cSearch::mInstance = NULL; + +const char* cSearch::parse(const char* Search){ + if(!cSearch::mInstance) cSearch::mInstance = new cSearch(); + + if(cSearch::mInstance && cSearch::mInstance->parseCriteria(Search)){ + return cSearch::mInstance->SQLWhereStmt; + } + return NULL; +} + +bool cSearch::parseCriteria(const char* Search){ + + charCallback endBrackedExpCB(bind(&cSearch::pushEndBrackedExp, this, _1)); + expCallback pushSimpleExpCB(bind(&cSearch::pushExpression, this, _1, _2)); + opCallback pushOperatorCB(bind(&cSearch::pushOperator, this, _1)); + expCallback pushQuotedValueCB(bind(&cSearch::pushValue, this, _1, _2)); + opCallback pushExistanceCB(bind(&cSearch::pushExistance, this, _1)); + propCallback pushPropertyCB(bind(&cSearch::pushProperty, this, _1)); + opCallback pushConcatOpCB(bind(&cSearch::pushConcatOp, this, _1)); + charCallback startBrackedExpCB(bind(&cSearch::pushStartBrackedExp, this, _1)); + + // Craft the grammar + cSearchGrammar Grammar(endBrackedExpCB, + pushSimpleExpCB, + pushOperatorCB, + pushQuotedValueCB, + pushExistanceCB, + pushPropertyCB, + pushConcatOpCB, + startBrackedExpCB); + + MESSAGE("Starting search parsing"); + + if(boost::spirit::parse(Search, Grammar).full){ + MESSAGE("Parsing successful"); + } + else { + ERROR("Parsing failed"); + return false; + } + return true; +} + +cSearch::cSearch(){ + this->CurrentOperator = NULL; + this->CurrentProperty = NULL; + this->CurrentValue = NULL; + this->SQLWhereStmt = strdup(""); +} + +cSearch::~cSearch(){ + delete this->CurrentOperator; + delete this->CurrentProperty; + delete this->CurrentValue; +} + + /**********************************************\ + * * + * The filter * + * * + \**********************************************/ + +cFilterCriteria::cFilterCriteria(){ + this->mFilterList = NULL; +} + +cFilterCriteria::~cFilterCriteria(){} + +cStringList* cFilterCriteria::parse(const char* Filter){ + cFilterCriteria* FilterParser = new cFilterCriteria; + cStringList* List = NULL; + + if(FilterParser && FilterParser->parseFilter(Filter)){ + List = FilterParser->getFilterList(); + } + + delete FilterParser; + + return List; +} + +bool cFilterCriteria::parseFilter(const char* Filter){ + this->mFilterList = new cStringList; + + if(Filter && !strcasecmp(Filter, "")){ + MESSAGE("Empty filter"); + return true; + } + + charCallback pushAsteriskCB(bind(&cFilterCriteria::pushAsterisk,this,_1)); + propCallback pushPropertyCB(bind(&cFilterCriteria::pushProperty,this,_1)); + + cFilterGrammar Grammar(pushPropertyCB, pushAsteriskCB); + + if(boost::spirit::parse(Filter, Grammar).full){ + MESSAGE("Parse filter successful"); + } + else { + ERROR("Parsing filter failed"); + return false; + } + return true; +} + + /**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cFilterCriteria::pushProperty(const char* Property){ + MESSAGE("Pushing property"); + this->mFilterList->Append(strdup(Property)); +} + +void cFilterCriteria::pushAsterisk(const char){ + MESSAGE("Pushing asterisk (*)"); + if(this->mFilterList) delete this->mFilterList; + this->mFilterList = NULL; + return; +} + + /**********************************************\ + * * + * The sorter * + * * + \**********************************************/ + +cSortCriteria::cSortCriteria(){ + this->mCriteriaList = new cList<cSortCrit>; + this->mCurrentCrit = NULL; +} + +cSortCriteria::~cSortCriteria(){} + +cList<cSortCrit>* cSortCriteria::parse(const char* Sort){ + cSortCriteria* SortParser = new cSortCriteria; + cList<cSortCrit>* List = NULL; + if(SortParser && SortParser->parseSort(Sort)){ + List = SortParser->getSortList(); + } + + delete SortParser; + + return List; +} + +bool cSortCriteria::parseSort(const char* Sort){ + if(!Sort || !strcasecmp(Sort, "")){ + MESSAGE("Empty Sort"); + return true; + } + + charCallback pushDirectionCB(bind(&cSortCriteria::pushDirection,this,_1)); + propCallback pushPropertyCB(bind(&cSortCriteria::pushProperty,this,_1)); + + cSortGrammar Grammar(pushPropertyCB, pushDirectionCB); + + if(boost::spirit::parse(Sort, Grammar).full){ + MESSAGE("Parse Sort successful"); + } + else { + ERROR("Parsing Sort failed"); + return false; + } + return true; +} + + /**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cSortCriteria::pushProperty(const char* Property){ + MESSAGE("Pushing property '%s'", Property); + this->mCurrentCrit->Property = strdup(Property); + this->mCriteriaList->Add(this->mCurrentCrit); + return; +} + +void cSortCriteria::pushDirection(const char Direction){ + MESSAGE("Pushing direction '%c'", Direction); + this->mCurrentCrit = new cSortCrit; + this->mCurrentCrit->SortDescending = (Direction=='-')?true:false; + return; +} + + /**********************************************\ + * * + * The pathparser * + * * + \**********************************************/ + +struct cWebserverSections : symbols<> { + cWebserverSections(){ + add + (UPNP_DIR_SHARES) + ; + } +} WebserverSections; + +struct cWebserverMethods : symbols<int> { + cWebserverMethods(){ + add + ("browse", UPNP_WEB_METHOD_BROWSE) + ("download", UPNP_WEB_METHOD_DOWNLOAD) + ("search", UPNP_WEB_METHOD_SEARCH) + ("show", UPNP_WEB_METHOD_SHOW) + ("get", UPNP_WEB_METHOD_STREAM) + ; + } +} WebserverMethods; + +struct cPathParserGrammar : public boost::spirit::grammar<cPathParserGrammar> { + + intCallback &pushSection; + intCallback &pushMethod; + expCallback &pushPropertyKey; + expCallback &pushPropertyValue; + + cPathParserGrammar(intCallback &pushSection, + intCallback &pushMethod, + expCallback &pushPropertyKey, + expCallback &pushPropertyValue): + pushSection(pushSection), + pushMethod(pushMethod), + pushPropertyKey(pushPropertyKey), + pushPropertyValue(pushPropertyValue){} + + template <typename scanner> + struct definition { + boost::spirit::rule<scanner> pathExp, section, method, methodProperties, + property, key, value, uncriticalChar; + + const boost::spirit::rule<scanner> &start(){ + return pathExp; + } + definition(const cPathParserGrammar &self){ + pathExp = section >> ch_p('/') >> method >> ch_p('?') >> methodProperties + ; + + section = WebserverSections[self.pushSection] + ; + + method = WebserverMethods[self.pushMethod] + ; + + methodProperties = property >> *(ch_p('&') >> methodProperties) + ; + + property = key >> ch_p('=') >> value + ; + + key = (+alnum_p)[self.pushPropertyKey] + ; + + value = (*uncriticalChar)[self.pushPropertyValue] + ; + + uncriticalChar = chset_p("-_.%~0-9A-Za-z") + ; + } + }; +}; + +cPathParser::cPathParser(){ + this->mSection = 0; + this->mMethod = 0; +} + +cPathParser::~cPathParser(){} + +bool cPathParser::parse(const char* Path, int* Section, int* Method, propertyMap* Properties){ + cPathParser* Parser = new cPathParser(); + bool ret = (Parser && Parser->parsePath(Path, Section, Method, Properties)) ? true : false; + + delete Parser; + + return ret; +} + +bool cPathParser::parsePath(const char* Path, int* Section, int* Method, propertyMap* Properties){ + if(!Path){ + return false; + } + + intCallback pushSectionCB(bind(&cPathParser::pushSection,this,_1)); + intCallback pushMethodCB(bind(&cPathParser::pushMethod,this,_1)); + expCallback pushPropertyKeyCB(bind(&cPathParser::pushPropertyKey, this, _1, _2)); + expCallback pushPropertyValueCB(bind(&cPathParser::pushPropertyValue, this, _1, _2)); + + cPathParserGrammar Grammar(pushSectionCB, pushMethodCB, pushPropertyKeyCB, pushPropertyValueCB); + + if(boost::spirit::parse(Path, Grammar).full){ + MESSAGE("Parse path successful"); + *Section = this->mSection; + *Method = this->mMethod; + *Properties = this->mProperties; + return true; + } + else { + ERROR("Parsing path failed"); + return false; + } + + return true; +} + + /**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cPathParser::pushPropertyKey(const char* Start, const char* End){ + char* Key = strndup(Start, End-Start); + + MESSAGE("Pushing key '%s'", Key); + + this->mKey = Key; + + free(Key); +} + +void cPathParser::pushPropertyValue(const char* Start, const char* End){ + char* Value = strndup(Start, End-Start); + + MESSAGE("Pushing value '%s'", Value); + // TODO: urlDecode Value + + if(*this->mKey){ + char* Key = strdup(this->mKey); + this->mProperties[Key] = Value; + } +} + +void cPathParser::pushMethod(int Method){ + MESSAGE("Pushing method '%d'", Method); + this->mMethod = Method; +} + +void cPathParser::pushSection(int Section){ + MESSAGE("Pushing section '%d'", Section); + this->mSection = Section; +}
\ No newline at end of file |