diff options
author | methodus <methodus@web.de> | 2012-10-03 22:39:25 +0200 |
---|---|---|
committer | methodus <methodus@web.de> | 2012-10-03 22:39:25 +0200 |
commit | 4c32f39dafc88b22def26ff8563c82662bb62f6e (patch) | |
tree | 2e66470acd9a4b007c2de2a7266026214328810c | |
parent | e886696b647616273c2570859571e03fa9f8833c (diff) | |
download | vdr-plugin-upnp-4c32f39dafc88b22def26ff8563c82662bb62f6e.tar.gz vdr-plugin-upnp-4c32f39dafc88b22def26ff8563c82662bb62f6e.tar.bz2 |
Added missing files.
-rw-r--r-- | common/ixml.cpp | 330 | ||||
-rw-r--r-- | common/parser.cpp | 538 | ||||
-rw-r--r-- | common/setup.cpp | 333 | ||||
-rwxr-xr-x | httpdocs/img_4894.jpg | bin | 0 -> 11695850 bytes |
4 files changed, 1201 insertions, 0 deletions
diff --git a/common/ixml.cpp b/common/ixml.cpp new file mode 100644 index 0000000..f463124 --- /dev/null +++ b/common/ixml.cpp @@ -0,0 +1,330 @@ +/* + * ixml.cpp + * + * Created on: 03.10.2012 + * Author: savop + */ + +#include "../include/tools/ixml.h" + +namespace upnp { + +namespace ixml { + +void XmlEscapeSpecialChars(string& doc){ + std::string buffer; + + buffer.reserve(doc.size()*1.1); + for(unsigned int i = 0; i < doc.size(); i++){ + switch((long)doc[i]){ + case L'€': buffer.append("€"); break; + case L'"': buffer.append("""); break; + case L'&': buffer.append("&"); break; + case L'<': buffer.append("<"); break; + case L'>': buffer.append(">"); break; + case L'¡': buffer.append("¡"); break; + case L'¢': buffer.append("¢"); break; + case L'£': buffer.append("£"); break; + case L'¤': buffer.append("¤"); break; + case L'¥': buffer.append("¥"); break; + case L'¦': buffer.append("¦"); break; + case L'§': buffer.append("§"); break; + case L'¨': buffer.append("¨"); break; + case L'©': buffer.append("©"); break; + case L'ª': buffer.append("ª"); break; + case L'¬': buffer.append("¬"); break; + case L'': buffer.append("­"); break; + case L'®': buffer.append("®"); break; + case L'¯': buffer.append("¯"); break; + case L'°': buffer.append("°"); break; + case L'±': buffer.append("±"); break; + case L'²': buffer.append("²"); break; + case L'³': buffer.append("³"); break; + case L'´': buffer.append("´"); break; + case L'µ': buffer.append("µ"); break; + case L'¶': buffer.append("¶"); break; + case L'·': buffer.append("·"); break; + case L'¸': buffer.append("¸"); break; + case L'¹': buffer.append("¹"); break; + case L'º': buffer.append("º"); break; + case L'»': buffer.append("»"); break; + case L'«': buffer.append("«"); break; + case L'¼': buffer.append("¼"); break; + case L'½': buffer.append("½"); break; + case L'¾': buffer.append("¾"); break; + case L'¿': buffer.append("¿"); break; + case L'À': buffer.append("À"); break; + case L'Á': buffer.append("Á"); break; + case L'Â': buffer.append("Â"); break; + case L'Ã': buffer.append("Ã"); break; + case L'Ä': buffer.append("Ä"); break; + case L'Å': buffer.append("Å"); break; + case L'Æ': buffer.append("Æ"); break; + case L'Ç': buffer.append("Ç"); break; + case L'È': buffer.append("È"); break; + case L'É': buffer.append("É"); break; + case L'Ê': buffer.append("Ê"); break; + case L'Ë': buffer.append("Ë"); break; + case L'Ì': buffer.append("Ì"); break; + case L'Í': buffer.append("Í"); break; + case L'Î': buffer.append("Î"); break; + case L'Ï': buffer.append("Ï"); break; + case L'Ð': buffer.append("Ð"); break; + case L'Ñ': buffer.append("Ñ"); break; + case L'Ò': buffer.append("Ò"); break; + case L'Ó': buffer.append("Ó"); break; + case L'Ô': buffer.append("Ô"); break; + case L'Õ': buffer.append("Õ"); break; + case L'Ö': buffer.append("Ö"); break; + case L'×': buffer.append("×"); break; + case L'Ø': buffer.append("Ø"); break; + case L'Ù': buffer.append("Ù"); break; + case L'Ú': buffer.append("Ú"); break; + case L'Û': buffer.append("Û"); break; + case L'Ü': buffer.append("Ü"); break; + case L'Ý': buffer.append("Ý"); break; + case L'Þ': buffer.append("Þ"); break; + case L'ß': buffer.append("ß"); break; + case L'à': buffer.append("à"); break; + case L'á': buffer.append("á"); break; + case L'â': buffer.append("â"); break; + case L'ã': buffer.append("ã"); break; + case L'ä': buffer.append("ä"); break; + case L'å': buffer.append("å"); break; + case L'æ': buffer.append("æ"); break; + case L'ç': buffer.append("ç"); break; + case L'è': buffer.append("è"); break; + case L'é': buffer.append("é"); break; + case L'ê': buffer.append("ê"); break; + case L'ë': buffer.append("ë"); break; + case L'ì': buffer.append("ì"); break; + case L'í': buffer.append("í"); break; + case L'î': buffer.append("î"); break; + case L'ï': buffer.append("ï"); break; + case L'ð': buffer.append("ð"); break; + case L'ñ': buffer.append("ñ"); break; + case L'ò': buffer.append("ò"); break; + case L'ó': buffer.append("ó"); break; + case L'ô': buffer.append("ô"); break; + case L'õ': buffer.append("õ"); break; + case L'ö': buffer.append("ö"); break; + case L'÷': buffer.append("÷"); break; + case L'ø': buffer.append("ø"); break; + case L'ù': buffer.append("ù"); break; + case L'ú': buffer.append("ú"); break; + case L'û': buffer.append("û"); break; + case L'ü': buffer.append("ü"); break; + case L'ý': buffer.append("ý"); break; + case L'þ': buffer.append("þ"); break; + default: buffer.append(1, doc[i]); break; + } + } + + doc.swap(buffer); +} + +//Function copied from Intel SDK +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2000-2003 Intel Corporation +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither name of Intel Corporation nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// +/******************************************************************************** + * SampleUtil_GetFirstDocumentItem + * + * Description: + * Given a document node, this routine searches for the first element + * named by the input string item, and returns its value as a string. + * String must be freed by caller using free. + * Parameters: + * doc -- The DOM document from which to extract the value + * item -- The item to search for + * + * + ********************************************************************************/ + +int IxmlGetFirstDocumentItem( IN IXML_Document * doc, IN std::string item, std::string& value ) { + IXML_NodeList *nodeList = NULL; + IXML_Node *textNode = NULL; + IXML_Node *tmpNode = NULL; + + int error = 0; + + nodeList = ixmlDocument_getElementsByTagName( doc, item.c_str() ); + + if( nodeList != NULL ) { + if( ( tmpNode = ixmlNodeList_item( nodeList, 0 ) ) ) { + + textNode = ixmlNode_getFirstChild( tmpNode ); + + if(textNode != NULL){ + value = ixmlNode_getNodeValue( textNode ); + } + } + } else { + error = -1; + } + + if( nodeList != NULL) { + ixmlNodeList_free( nodeList ); + } + + + return error; +} + +IXML_Element* IxmlAddProperty(IXML_Document* document, IXML_Element* node, const string& upnpproperty, const string& value){ + if(!node) return NULL; + IXML_Element* PropertyNode = NULL; + + string tvalue = value.substr(0,MAX_METADATA_LENGTH_L); + + string::size_type pos = upnpproperty.find('@'); + string attribute = pos!=string::npos ? upnpproperty.substr(pos+1) : string(); + string property = pos!=string::npos ? upnpproperty.substr(0, pos) : upnpproperty; + + if(!attribute.empty()){ + if(property.empty()){ + if(ixmlElement_setAttribute(node, attribute.c_str(), tvalue.c_str())!=IXML_SUCCESS){ + return NULL; + } + } + else { + IXML_NodeList* NodeList = ixmlElement_getElementsByTagName(node, property.c_str()); + if(NodeList!=NULL){ + PropertyNode = (IXML_Element*) ixmlNodeList_item(NodeList, 0); + if(PropertyNode){ + if(ixmlElement_setAttribute(PropertyNode, attribute.c_str(), tvalue.c_str())!=IXML_SUCCESS){ + return NULL; + } + } + else { + ixmlNodeList_free(NodeList); + return NULL; + } + } + else { + return NULL; + } + } + } + else { + PropertyNode = ixmlDocument_createElement(document, property.c_str()); + IXML_Node* PropertyText = ixmlDocument_createTextNode(document, tvalue.c_str()); + ixmlNode_appendChild((IXML_Node*) PropertyNode, PropertyText); + ixmlNode_appendChild((IXML_Node*) node, (IXML_Node*) PropertyNode); + } + return PropertyNode; +} + +IXML_Element* IxmlAddFilteredProperty(const StringList& Filter, IXML_Document* document, IXML_Element* node, const string& upnpproperty, const string& value){ + // leave out empty values. + if(value.empty() || !value.compare("0")){ + return NULL; + } + + if((*Filter.begin()).compare("*") == 0) return IxmlAddProperty(document, node, upnpproperty, value); + + for(StringList::const_iterator it = Filter.begin(); it != Filter.end(); ++it){ + if((*it).compare(upnpproperty) == 0) return IxmlAddProperty(document, node, upnpproperty, value); + } + + return NULL; +} + +IXML_Element* IxmlReplaceProperty(IXML_Document* document, IXML_Element* node, const string& upnpproperty, const string& newValue){ + if(!node) return NULL; + IXML_Element* PropertyNode = NULL; + + string tvalue = newValue.substr(0, MAX_METADATA_LENGTH_L); + + string::size_type pos = upnpproperty.find('@'); + string attribute = pos!=string::npos ? upnpproperty.substr(pos+1) : string(); + string property = pos!=string::npos ? upnpproperty.substr(0, pos) : upnpproperty; + + if(!attribute.empty()){ + if(property.empty()){ + if(tvalue.empty()){ + if(ixmlElement_setAttribute(node, attribute.c_str(), tvalue.c_str())!=IXML_SUCCESS){ + return NULL; + } + } + else { + ixmlElement_removeAttribute(node, attribute.c_str()); + } + } + else { + IXML_NodeList* NodeList = ixmlElement_getElementsByTagName(node, property.c_str()); + if(NodeList!=NULL){ + PropertyNode = (IXML_Element*) ixmlNodeList_item(NodeList, 0); + if(PropertyNode){ + if(!tvalue.empty()){ + if(ixmlElement_setAttribute(PropertyNode, attribute.c_str(), tvalue.c_str())!=IXML_SUCCESS){ + return NULL; + } + } + else { + ixmlElement_removeAttribute(PropertyNode, attribute.c_str()); + } + } + else { + ixmlNodeList_free(NodeList); + return NULL; + } + } + else { + return NULL; + } + } + } + else { + IXML_NodeList* NodeList = ixmlElement_getElementsByTagName(node, property.c_str()); + if(NodeList!=NULL){ + PropertyNode = (IXML_Element*) ixmlNodeList_item(NodeList, 0); + IXML_Node* PropertyText = ixmlNode_getFirstChild((IXML_Node*) PropertyNode); + + if(ixmlNode_removeChild((IXML_Node*) PropertyNode, PropertyText, NULL)!=IXML_SUCCESS){ + return NULL; + } + if(!tvalue.empty()){ + PropertyText = ixmlDocument_createTextNode(document, tvalue.c_str()); + } + ixmlNode_appendChild((IXML_Node*) PropertyNode, PropertyText); + } + else { + ixmlNodeList_free(NodeList); + return NULL; + } + } + return PropertyNode; +} + +} // namespace ixml + +} // namespace upnp + diff --git a/common/parser.cpp b/common/parser.cpp new file mode 100644 index 0000000..8c2533a --- /dev/null +++ b/common/parser.cpp @@ -0,0 +1,538 @@ +/* + * parser.cpp + * + * Created on: 16.09.2012 + * Author: savop + */ + +// uncomment this to enable debuging of the grammar +//#define BOOST_SPIRIT_DEBUG + +#include <string> +#include "../include/parser.h" +#include "../include/plugin.h" +#include <boost/spirit/include/classic.hpp> +#include <boost/function.hpp> +#include <boost/bind.hpp> + +using namespace std; +using namespace boost; + +namespace sp = boost::spirit::classic; + +namespace upnp { + + +// 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 +/** @private */ +struct cProperties : sp::symbols<const char*> { + //struct cProperties : symbols<> { + cProperties(){ + add + (property::object::KEY_TITLE, "title") + (property::object::KEY_CREATOR, "creator") + (property::object::KEY_DESCRIPTION, "description") + (property::object::KEY_LONG_DESCRIPTION, "longDescription") + (property::object::KEY_CLASS, "class") + (property::object::KEY_DATE, "date") + (property::object::KEY_LANGUAGE, "language") + (property::resource::KEY_PROTOCOL_INFO, "protocolInfo") + ; + } +} Properties; + +/** @private */ +struct cOperators : sp::symbols<const char*> { + cOperators(){ + add + ("=", "==") + ("!=", "!=") + ("<", "<") + (">", ">") + ("<=", "<=") + (">=", ">=") + ("contains", "LIKE") + ("doesNotContain", "NOT LIKE") + ("derivedfrom", "LIKE") + ; + } +} Operators; + +/** @private */ +struct cConcatOperators : sp::symbols<const char*> { + cConcatOperators(){ + add + ("and", "AND") + ("or", "OR") + ; + } +} ConcatOperators; + +/** @private */ +struct cExistanceOperator : sp::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! +/** @private */ +struct cSearchGrammar : public sp::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> + /** @private */ + struct definition { + sp::rule<scanner> searchCrit, searchExp, logOp, \ + relExp, binOp, relOp, stringOp, \ + existsOp, boolVal, quotedVal, \ + wChar, property, brackedExp, exp; + const sp::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 = sp::confix_p( + sp::ch_p('(')[self.startBrackedExp], + *wChar >> searchExp >> *wChar, + sp::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 = sp::str_p("exists") + ; + + boolVal = Existance[self.pushExistance] + ; + + quotedVal = sp::confix_p('"', (*sp::c_escape_ch_p)[self.pushQuotedValue], '"') + ; + + wChar = sp::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 + } + }; +}; + +/**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cSearch::pushEndBrackedExp(const char){ + sqlWhereStmt << ") "; +} + +void cSearch::pushExpression(const char*, const char*){ + + sqlWhereStmt << currentProperty << " " << currentOperator << " " << currentValue << " "; + + return; +} + +void cSearch::pushProperty(string property){ + currentProperty = property; +} + +void cSearch::pushOperator(string op){ + currentOperator = op; +} + +void cSearch::pushValue(const char* start, const char* end){ + stringstream s; + + s << "'"; + + if(currentOperator.find("LIKE") != string::npos) + s << "%" << string(start, end) << "%"; + else + s << string(start, end); + + s << "'"; + + currentValue = s.str(); +} + +void cSearch::pushExistance(string Exists){ + currentValue = Exists; + currentOperator = "IS"; +} + +void cSearch::pushConcatOp(string Operator){ + sqlWhereStmt << Operator << " "; +} + +void cSearch::pushStartBrackedExp(const char){ + sqlWhereStmt << "( "; +} + +/**********************************************\ + * * + * The rest * + * * + \**********************************************/ + +string cSearch::parse(const string& search){ + static cSearch searchCrit; + + if(searchCrit.parseCriteria(search)){ + return searchCrit.sqlWhereStmt.str(); + } + return string(); +} + +bool cSearch::parseCriteria(string search){ + + sqlWhereStmt.str(string()); + + 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); + + if(!sp::parse(search.c_str(), Grammar).full){ + return false; + } + return true; +} + +cSearch::cSearch(){} + +cSearch::~cSearch(){} + +/**********************************************\ + * * + * The filter * + * * + \**********************************************/ + +/** @private */ +struct cFilterGrammar : public sp::grammar<cFilterGrammar> { + // The callback members + expCallback &pushProperty; + charCallback &pushAsterisk; + + cFilterGrammar( + expCallback &pushProperty, + charCallback &pushAsterisk): + pushProperty(pushProperty), + pushAsterisk(pushAsterisk){} + + template <typename scanner> + /** @private */ + struct definition { + sp::rule<scanner> filterCrit, filterExp, property, propString; + + const sp::rule<scanner> &start(){ + return filterCrit; + } + definition(const cFilterGrammar &self){ + filterCrit = sp::ch_p('*')[self.pushAsterisk] + | filterExp + ; + + filterExp = property >> *(sp::ch_p(',') >> *sp::space_p >> filterExp) + ; + + property = propString[self.pushProperty] + ; + + // TODO: improve this grammer. + // A property has the following pattern: + // [<namespace>:]property[@attribute] OR @id, @parentID, @restricted + // + propString = *(sp::alpha_p | sp::ch_p(':') | sp::ch_p('@')) + ; + } + }; +}; + +cFilterCriteria::cFilterCriteria(){} + +cFilterCriteria::~cFilterCriteria(){} + +StringList cFilterCriteria::parse(const string& filter){ + static cFilterCriteria filterParser; + + StringList list; + + if(filterParser.parseFilter(filter)){ + list = filterParser.getFilterList(); + } + + return list; +} + +bool cFilterCriteria::parseFilter(string filter){ + + mFilterList.clear(); + + mFilterList.push_back(property::object::KEY_OBJECTID); + mFilterList.push_back(property::object::KEY_PARENTID); + mFilterList.push_back(property::object::KEY_TITLE); + mFilterList.push_back(property::object::KEY_CLASS); + mFilterList.push_back(property::object::KEY_RESTRICTED); + mFilterList.push_back(property::resource::KEY_RESOURCE); + mFilterList.push_back(property::resource::KEY_PROTOCOL_INFO); + + if(filter.empty()){ + return true; + } + + charCallback pushAsteriskCB(bind(&cFilterCriteria::pushAsterisk,this,_1)); + expCallback pushPropertyCB(bind(&cFilterCriteria::pushProperty,this,_1, _2)); + + cFilterGrammar Grammar(pushPropertyCB, pushAsteriskCB); + + if(!sp::parse(filter.c_str(), Grammar).full){ + return false; + } + return true; +} + +/**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cFilterCriteria::pushProperty(const char* start, const char* end){ + string s(start, end); + + for(StringList::iterator it = mFilterList.begin(); it != mFilterList.end(); ++it){ + if((*it).compare(s) == 0) + return; + } + + mFilterList.push_back(s); +} + +void cFilterCriteria::pushAsterisk(const char){ + mFilterList.clear(); + mFilterList.push_back("*"); + return; +} + +/**********************************************\ + * * + * The sorter * + * * + \**********************************************/ + +/** @private */ +struct cSortGrammar : public sp::grammar<cSortGrammar> { + // The callback members + propCallback &pushProperty; + charCallback &pushDirection; + + cSortGrammar( + propCallback &pushProperty, + charCallback &pushDirection): + pushProperty(pushProperty), + pushDirection(pushDirection){} + + template <typename scanner> + /** @private */ + struct definition { + sp::rule<scanner> sortCrit, sortExp, property, direction; + + const sp::rule<scanner> &start(){ + return sortCrit; + } + definition(const cSortGrammar &self){ + sortCrit = sortExp + ; + + sortExp = direction >> property >> *(sp::ch_p(',') >> sortExp) + ; + + direction = sp::sign_p[self.pushDirection] + ; + + property = Properties[self.pushProperty] + ; + } + }; +}; + +cSortCriteria::cSortCriteria(){} + +cSortCriteria::~cSortCriteria(){} + +list<SortCrit> cSortCriteria::parse(const string& sort){ + static cSortCriteria sortParser; + + list<SortCrit> list; + + if(sortParser.parseSort(sort)){ + list = sortParser.getSortList(); + } + + return list; +} + +bool cSortCriteria::parseSort(string sort){ + + mCriteriaList.clear(); + + if(sort.empty()){ + return true; + } + + charCallback pushDirectionCB(bind(&cSortCriteria::pushDirection,this,_1)); + propCallback pushPropertyCB(bind(&cSortCriteria::pushProperty,this,_1)); + + cSortGrammar Grammar(pushPropertyCB, pushDirectionCB); + + if(!sp::parse(sort.c_str(), Grammar).full){ + return false; + } + return true; +} + +/**********************************************\ + * * + * The actors * + * * + \**********************************************/ + +void cSortCriteria::pushProperty(string property){ + mCurrentCrit.property = property; + mCriteriaList.push_back(mCurrentCrit); + return; +} + +void cSortCriteria::pushDirection(bool desc){ + mCurrentCrit.sortDescending = (desc)?true:false; + return; +} + +} // namespace upnp diff --git a/common/setup.cpp b/common/setup.cpp new file mode 100644 index 0000000..b4704f3 --- /dev/null +++ b/common/setup.cpp @@ -0,0 +1,333 @@ +/* + * setup.cpp + * + * Created on: 21.09.2012 + * Author: savop + */ + +#include "../include/setup.h" +#include "../include/server.h" +#include "../include/tools.h" +#include <vdr/osdbase.h> +#include <vdr/menuitems.h> + +cMenuSetupUPnP::cMenuSetupUPnP() +: switchExpertSettings(0) +{ + Load(); + Update(); +} + +cMenuSetupUPnP::~cMenuSetupUPnP(){ +} + +void cMenuSetupUPnP::Update(){ + int current = Current(); + Clear(); + // Add OSD menu item for enabling UPnP Server + + Add(new cMenuEditBoolItem(tr("Enable UPnP server"),(int*)&config.enabled,tr("disabled"),tr("enabled"))); + Add(new cMenuEditBoolItem(tr("Use expert settings"),&switchExpertSettings)); + if(switchExpertSettings){ + + cOsdItem *wsCat = new cOsdItem("--- Webserver settings -------------------------------------------------------"); + wsCat->SetSelectable(false); + Add(wsCat); + + Add(new cMenuEditStrItem(tr("Webserver root directory"), webserverRoot, STRING_SIZE)); + Add(new cMenuEditIntItem(tr("Webserver port (0=auto)"), &wsport, 0, 65536)); + + Add(new cMenuEditStrItem(tr("Presentation URL"), presentationUrl, STRING_SIZE)); + + Add(new cMenuEditBoolItem(tr("Use \"live\" plugin for presentation"),&switchLive)); + + if(switchLive){ + Add(new cMenuEditIntItem(tr("Live webserver port (0=auto)"), &lvport, 0, 65536)); + } + + cOsdItem *usCat = new cOsdItem("--- UPnP server settings -----------------------------------------------------"); + usCat->SetSelectable(false); + Add(usCat); + + Add(ctrlGenerate = new cOsdItem(tr("Generate new device UUID"))); + + cMenuEditStrItem* devUUID = new cMenuEditStrItem(tr("Current device UUID"), deviceUUID, STRING_SIZE); + devUUID->SetSelectable(false); + + Add(devUUID); + Add(new cMenuEditIntItem(tr("Max. content length of SOAP Messages"), (int*)&config.maxContentLength, KB(10), KB(200))); + Add(new cMenuEditIntItem(tr("Max. age of UPnP announcements"), &config.announceMaxAge, 0, 3600)); + + Add(new cMenuEditBoolItem(tr("Bind UPnP server to "),&switchBindAddress,tr("interface"),tr("address"))); + if(switchBindAddress){ + Add(new cMenuEditIpItem(tr("Set IP address"), address)); + } else { + GetInterfaces(); + Add(new cMenuEditStraItem(tr("Set network interface"), &interfaceIndex, ifaceCount, interfaces)); + } + Add(new cMenuEditIntItem(tr("UPnP server port (0=auto)"), &upnpport, 0, 65536)); + + cOsdItem *dbCat = new cOsdItem("--- Database settings --------------------------------------------------------"); + dbCat->SetSelectable(false); + Add(dbCat); + + Add(new cMenuEditStrItem(tr("Path to database file"), databaseFile, STRING_SIZE)); + } + + SetCurrent(Get(current)); + Display(); +} + +eOSState cMenuSetupUPnP::ProcessKey(enum eKeys key){ + int oldExpertSettings = switchExpertSettings; + int oldInterfaceBind = switchBindAddress; + int oldUseLive = switchLive; + + cOsdItem *item = this->Get(this->Current()); + + eOSState state = cMenuSetupPage::ProcessKey(key); + + if(item == ctrlGenerate && key == kOk){ + config.GenerateNewDeviceUUID(); + strn0cpy(deviceUUID, config.deviceUUID.c_str(), STRING_SIZE); + Update(); + state = osContinue; + } + + if(key != kNone && (oldExpertSettings != switchExpertSettings || + oldInterfaceBind != switchBindAddress || + oldUseLive != switchLive)){ + Update(); + } + + return state; +} + +void cMenuSetupUPnP::GetInterfaces() { + ifaceVector = upnp::tools::GetNetworkInterfaces(true); + + for(ifaceCount = 0; ifaceCount < (int)ifaceVector.size(); ++ifaceCount){ + interfaces[ifaceCount] = ifaceVector[ifaceCount].c_str(); + } + +} + +int cMenuSetupUPnP::GetIndexOfInterface(std::string interface) const { + for(int i = 0; i < (int)ifaceVector.size(); ++i){ + if(ifaceVector[i].compare(interface) == 0) return i; + } + + return 0; +} + +void cMenuSetupUPnP::Load(){ + config = upnp::cMediaServer::GetInstance()->GetConfiguration(); + + switchExpertSettings = config.expertSettings?1:0; + switchBindAddress = config.bindToAddress?1:0; + switchLive = config.useLive; + interfaceIndex = GetIndexOfInterface(config.interface); + wsport = config.webServerPort; + upnpport = config.port; + lvport = config.livePort; + + strn0cpy(webserverRoot, config.webServerRoot.c_str(), STRING_SIZE); + strn0cpy(address, config.address.c_str(), 16); + strn0cpy(interface, config.interface.c_str(), 16); + strn0cpy(databaseFile, config.databaseFile.c_str(), STRING_SIZE); + strn0cpy(presentationUrl, config.presentationURL.c_str(), STRING_SIZE); + strn0cpy(deviceUUID, config.deviceUUID.c_str(), STRING_SIZE); +} + +void cMenuSetupUPnP::Store(){ + + config.expertSettings = switchExpertSettings?true:false; + config.webServerRoot = webserverRoot; + config.address = address; + config.interface = interface; + config.databaseFile = databaseFile; + config.presentationURL = presentationUrl; + + config.bindToAddress = switchBindAddress?true:false; + config.webServerPort = wsport; + config.port = upnpport; + + config.useLive = switchLive?true:false; + config.livePort = lvport; + + upnp::cMediaServer::GetInstance()->SetConfiguration(config); + + SetupStore("enabled", config.enabled); + SetupStore("expertSettings", config.expertSettings); + SetupStore("webServerRoot", config.webServerRoot.c_str()); + SetupStore("webServerPort", config.webServerPort); + SetupStore("presentationURL", config.presentationURL.c_str()); + SetupStore("useLive", config.useLive); + SetupStore("livePort", config.livePort); + SetupStore("maxContentLength", config.maxContentLength); + SetupStore("announceMaxAge", config.announceMaxAge); + SetupStore("deviceUUID", config.deviceUUID.c_str()); + SetupStore("bindToAddress", config.bindToAddress); + SetupStore("address", config.address.c_str()); + SetupStore("interface", config.interface.c_str()); + SetupStore("port", config.port); + SetupStore("databaseFile", config.databaseFile.c_str()); +} + +bool cMenuSetupUPnP::SetupParse(const char *name, const char *value, upnp::cConfig& config) +{ + + if (strcasecmp(name, "enabled")==0) config.enabled = atoi(value)?true:false; + else if (strcasecmp(name, "expertSettings")==0) config.expertSettings = atoi(value)?true:false; + else if (strcasecmp(name, "webServerRoot")==0) config.webServerRoot = value; + else if (strcasecmp(name, "webServerPort")==0) config.webServerPort = (uint16_t)atoi(value); + else if (strcasecmp(name, "presentationURL")==0) config.presentationURL = value; + else if (strcasecmp(name, "useLive")==0) config.useLive = atoi(value)?true:false; + else if (strcasecmp(name, "livePort")==0) config.livePort = atoi(value); + else if (strcasecmp(name, "maxContentLength")==0) config.maxContentLength = atol(value); + else if (strcasecmp(name, "announceMaxAge")==0) config.announceMaxAge = atoi(value); + else if (strcasecmp(name, "deviceUUID")==0) config.deviceUUID = value; + else if (strcasecmp(name, "bindToAddress")==0) config.bindToAddress = atoi(value)?true:false; + else if (strcasecmp(name, "address")==0) config.address = value; + else if (strcasecmp(name, "interface")==0) config.interface = value; + else if (strcasecmp(name, "port")==0) config.port = (uint16_t)atoi(value); + else if (strcasecmp(name, "databaseFile")==0) config.databaseFile = value; + else return false; + + return true; +} + +cMenuEditIpItem::cMenuEditIpItem(const char *Name, char *Value):cMenuEditItem(Name) { + value = Value; + curNum = -1; + pos = -1; + step = false; + Set(); +} + +cMenuEditIpItem::~cMenuEditIpItem() { +} + +void cMenuEditIpItem::Set(void) { + char buf[1000]; + if (pos >= 0) { + in_addr_t addr = inet_addr(value); + if ((int)addr == -1) + addr = 0; + int p = 0; + for (int i = 0; i < 4; ++i) { + p += snprintf(buf + p, sizeof(buf) - p, pos == i ? "[%d]" : "%d", + pos == i ? curNum : (addr >> (i * 8)) & 0xff); + if (i < 3) + buf[p++] = '.'; + } + SetValue(buf); + } else + SetValue(value); +} + +eOSState cMenuEditIpItem::ProcessKey(eKeys Key) { + in_addr addr; + addr.s_addr = inet_addr(value); + if ((int)addr.s_addr == -1) + addr.s_addr = 0; + + switch (Key) { + case kUp: + if (pos >= 0) { + if (curNum < 255) ++curNum; + } else + return cMenuEditItem::ProcessKey(Key); + break; + + case kDown: + if (pos >= 0) { + if (curNum > 0) --curNum; + } else + return cMenuEditItem::ProcessKey(Key); + break; + + case kOk: + if (pos >= 0) { + addr.s_addr = inet_addr(value); + if ((int)addr.s_addr == -1) + addr.s_addr = 0; + addr.s_addr &= ~(0xff << (pos * 8)); + addr.s_addr |= curNum << (pos * 8); + strcpy(value, inet_ntoa(addr)); + } else + return cMenuEditItem::ProcessKey(Key); + curNum = -1; + pos = -1; + break; + + case kRight: + if (pos >= 0) { + addr.s_addr = inet_addr(value); + if ((int)addr.s_addr == -1) + addr.s_addr = 0; + addr.s_addr &= ~(0xff << (pos * 8)); + addr.s_addr |= curNum << (pos * 8); + strcpy(value, inet_ntoa(addr)); + } + + if (pos == -1 || pos == 3) + pos = 0; + else + ++pos; + + curNum = (addr.s_addr >> (pos * 8)) & 0xff; + step = true; + break; + + case kLeft: + if (pos >= 0) { + addr.s_addr = inet_addr(value); + if ((int)addr.s_addr == -1) + addr.s_addr = 0; + addr.s_addr &= ~(0xff << (pos * 8)); + addr.s_addr |= curNum << (pos * 8); + strcpy(value, inet_ntoa(addr)); + } + + if (pos <= 0) + pos = 3; + else + --pos; + + curNum = (addr.s_addr >> (pos * 8)) & 0xff; + step = true; + break; + + case k0 ... k9: /* Netbeans reports error with this line (.. is okay but wrong) */ + if (pos == -1) + pos = 0; + + if (curNum == -1 || step) { + curNum = Key - k0; + step = false; + } else + curNum = curNum * 10 + (Key - k0); + + if ((curNum * 10 > 255) || (curNum == 0)) { + in_addr addr; + addr.s_addr = inet_addr(value); + if ((int)addr.s_addr == -1) + addr.s_addr = 0; + addr.s_addr &= ~(0xff << (pos * 8)); + addr.s_addr |= curNum << (pos * 8); + strcpy(value, inet_ntoa(addr)); + if (++pos == 4) + pos = 0; + curNum = (addr.s_addr >> (pos * 8)) & 0xff; + step = true; + } + break; + + default: + return cMenuEditItem::ProcessKey(Key); + } + + Set(); + return osContinue; +} diff --git a/httpdocs/img_4894.jpg b/httpdocs/img_4894.jpg Binary files differnew file mode 100755 index 0000000..bdb79a2 --- /dev/null +++ b/httpdocs/img_4894.jpg |