summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormethodus <methodus@web.de>2012-10-03 22:39:25 +0200
committermethodus <methodus@web.de>2012-10-03 22:39:25 +0200
commit4c32f39dafc88b22def26ff8563c82662bb62f6e (patch)
tree2e66470acd9a4b007c2de2a7266026214328810c
parente886696b647616273c2570859571e03fa9f8833c (diff)
downloadvdr-plugin-upnp-4c32f39dafc88b22def26ff8563c82662bb62f6e.tar.gz
vdr-plugin-upnp-4c32f39dafc88b22def26ff8563c82662bb62f6e.tar.bz2
Added missing files.
-rw-r--r--common/ixml.cpp330
-rw-r--r--common/parser.cpp538
-rw-r--r--common/setup.cpp333
-rwxr-xr-xhttpdocs/img_4894.jpgbin0 -> 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("&euro;"); break;
+ case L'"': buffer.append("&quot;"); break;
+ case L'&': buffer.append("&amp;"); break;
+ case L'<': buffer.append("&lt;"); break;
+ case L'>': buffer.append("&gt;"); break;
+ case L'¡': buffer.append("&iexcl;"); break;
+ case L'¢': buffer.append("&cent;"); break;
+ case L'£': buffer.append("&pound;"); break;
+ case L'¤': buffer.append("&curren;"); break;
+ case L'¥': buffer.append("&yen;"); break;
+ case L'¦': buffer.append("&brvbar;"); break;
+ case L'§': buffer.append("&sect;"); break;
+ case L'¨': buffer.append("&uml;"); break;
+ case L'©': buffer.append("&copy;"); break;
+ case L'ª': buffer.append("&ordf;"); break;
+ case L'¬': buffer.append("&not;"); break;
+ case L'­': buffer.append("&shy;"); break;
+ case L'®': buffer.append("&reg;"); break;
+ case L'¯': buffer.append("&macr;"); break;
+ case L'°': buffer.append("&deg;"); break;
+ case L'±': buffer.append("&plusmn;"); break;
+ case L'²': buffer.append("&sup2;"); break;
+ case L'³': buffer.append("&sup3;"); break;
+ case L'´': buffer.append("&acute;"); break;
+ case L'µ': buffer.append("&micro;"); break;
+ case L'¶': buffer.append("&para;"); break;
+ case L'·': buffer.append("&middot;"); break;
+ case L'¸': buffer.append("&cedil;"); break;
+ case L'¹': buffer.append("&sup1;"); break;
+ case L'º': buffer.append("&ordm;"); break;
+ case L'»': buffer.append("&raquo;"); break;
+ case L'«': buffer.append("&laquo;"); break;
+ case L'¼': buffer.append("&frac14;"); break;
+ case L'½': buffer.append("&frac12;"); break;
+ case L'¾': buffer.append("&frac34;"); break;
+ case L'¿': buffer.append("&iquest;"); break;
+ case L'À': buffer.append("&Agrave;"); break;
+ case L'Á': buffer.append("&Aacute;"); break;
+ case L'Â': buffer.append("&Acirc;"); break;
+ case L'Ã': buffer.append("&Atilde;"); break;
+ case L'Ä': buffer.append("&Auml;"); break;
+ case L'Å': buffer.append("&Aring;"); break;
+ case L'Æ': buffer.append("&AElig;"); break;
+ case L'Ç': buffer.append("&Ccedil;"); break;
+ case L'È': buffer.append("&Egrave;"); break;
+ case L'É': buffer.append("&Eacute;"); break;
+ case L'Ê': buffer.append("&Ecirc;"); break;
+ case L'Ë': buffer.append("&Euml;"); break;
+ case L'Ì': buffer.append("&Igrave;"); break;
+ case L'Í': buffer.append("&Iacute;"); break;
+ case L'Î': buffer.append("&Icirc;"); break;
+ case L'Ï': buffer.append("&Iuml;"); break;
+ case L'Ð': buffer.append("&ETH;"); break;
+ case L'Ñ': buffer.append("&Ntilde;"); break;
+ case L'Ò': buffer.append("&Ograve;"); break;
+ case L'Ó': buffer.append("&Oacute;"); break;
+ case L'Ô': buffer.append("&Ocirc;"); break;
+ case L'Õ': buffer.append("&Otilde;"); break;
+ case L'Ö': buffer.append("&Ouml;"); break;
+ case L'×': buffer.append("&times;"); break;
+ case L'Ø': buffer.append("&Oslash;"); break;
+ case L'Ù': buffer.append("&Ugrave;"); break;
+ case L'Ú': buffer.append("&Uacute;"); break;
+ case L'Û': buffer.append("&Ucirc;"); break;
+ case L'Ü': buffer.append("&Uuml;"); break;
+ case L'Ý': buffer.append("&Yacute;"); break;
+ case L'Þ': buffer.append("&THORN;"); break;
+ case L'ß': buffer.append("&szlig;"); break;
+ case L'à': buffer.append("&agrave;"); break;
+ case L'á': buffer.append("&aacute;"); break;
+ case L'â': buffer.append("&acirc;"); break;
+ case L'ã': buffer.append("&atilde;"); break;
+ case L'ä': buffer.append("&auml;"); break;
+ case L'å': buffer.append("&aring;"); break;
+ case L'æ': buffer.append("&aelig;"); break;
+ case L'ç': buffer.append("&ccedil;"); break;
+ case L'è': buffer.append("&egrave;"); break;
+ case L'é': buffer.append("&eacute;"); break;
+ case L'ê': buffer.append("&ecirc;"); break;
+ case L'ë': buffer.append("&euml;"); break;
+ case L'ì': buffer.append("&igrave;"); break;
+ case L'í': buffer.append("&iacute;"); break;
+ case L'î': buffer.append("&icirc;"); break;
+ case L'ï': buffer.append("&iuml;"); break;
+ case L'ð': buffer.append("&eth;"); break;
+ case L'ñ': buffer.append("&ntilde;"); break;
+ case L'ò': buffer.append("&ograve;"); break;
+ case L'ó': buffer.append("&oacute;"); break;
+ case L'ô': buffer.append("&ocirc;"); break;
+ case L'õ': buffer.append("&otilde;"); break;
+ case L'ö': buffer.append("&ouml;"); break;
+ case L'÷': buffer.append("&divide;"); break;
+ case L'ø': buffer.append("&oslash;"); break;
+ case L'ù': buffer.append("&ugrave;"); break;
+ case L'ú': buffer.append("&uacute;"); break;
+ case L'û': buffer.append("&ucirc;"); break;
+ case L'ü': buffer.append("&uuml;"); break;
+ case L'ý': buffer.append("&yacute;"); break;
+ case L'þ': buffer.append("&thorn;"); 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
new file mode 100755
index 0000000..bdb79a2
--- /dev/null
+++ b/httpdocs/img_4894.jpg
Binary files differ