/******************************************************************************* * libretroshare/src/retroshare: rsexpr.cc * * * * libretroshare: retroshare core library * * * * Copyright 2007-2008 by Kashif Kaleem * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public License * * along with this program. If not, see . * * * *******************************************************************************/ #include "retroshare/rsexpr.h" #include "retroshare/rstypes.h" #include #include /****************************************************************************************** eval functions of relational expressions. ******************************************************************************************/ namespace RsRegularExpression { template<> void RelExpression::linearize(LinearizedExpression& e) const { e._ints.push_back(Op) ; e._ints.push_back(LowerValue) ; e._ints.push_back(HigherValue) ; } bool DateExpression::eval(const ExpFileEntry& file) { return evalRel(file.file_modtime()); } bool SizeExpressionMB::eval(const ExpFileEntry& file) { return evalRel((int)(file.file_size() >> 20)); // MAX_INT is 2^31-1, so the max value that this check can handle is (2^31-1)*2^20, which is 2.147TB } bool SizeExpression::eval(const ExpFileEntry& file) { // Maximum size that we can compare to the stored value (which is a signed int, so (2^32-1) / 2) // Not taking care of this would cast file.file_size() to int, with unpredictable consequences (sign switch, etc) int caped_size = (int)std::min( (uint64_t)(~(uint32_t)0 >> 1), file.file_size() ); return evalRel(caped_size); } bool PopExpression::eval(const ExpFileEntry& file) { return evalRel(file.file_popularity()); } /****************************************************************************************** Code for evaluating string expressions ******************************************************************************************/ bool NameExpression::eval(const ExpFileEntry& file) { return evalStr(file.file_name()); } bool PathExpression::eval(const ExpFileEntry& file) { return evalStr(file.file_parent_path()); } bool ExtExpression::eval(const ExpFileEntry& file) { std::string ext; /*Get the part of the string after the last instance of . in the filename */ size_t index = file.file_name().find_last_of('.'); if (index != std::string::npos) { ext = file.file_name().substr(index+1); if (ext != "" ){ return evalStr(ext); } } return false; } bool HashExpression::eval(const ExpFileEntry& file){ return evalStr(file.file_hash().toStdString()); } /*Check whether two strings are 'equal' to each other*/ static bool StrEquals(const std::string & str1, const std::string & str2, bool IgnoreCase ){ if ( str1.size() != str2.size() ){ return false; } else if (IgnoreCase) { std::equal( str1.begin(), str1.end(), str2.begin(), CompareCharIC() ); } return std::equal( str1.begin(), str1.end(), str2.begin()); } /*Check whether one string contains the other*/ static bool StrContains( const std::string & str1, const std::string & str2, bool IgnoreCase){ std::string::const_iterator iter ; if (IgnoreCase) { iter = std::search( str1.begin(), str1.end(), str2.begin(), str2.end(), CompareCharIC() ); } else { iter = std::search( str1.begin(), str1.end(), str2.begin(), str2.end()); } return ( iter != str1.end() ); } std::string StringExpression::toStdStringWithParam(const std::string& varstr) const { std::string strlist ; for (auto iter = terms.begin(); iter != terms.end(); ++iter ) strlist += *iter + " "; if(!strlist.empty()) strlist.resize(strlist.size()-1); //strlist.pop_back(); // pops the last ",". c++11 is needed for pop_back() switch(Op) { case ContainsAllStrings: return varstr + " CONTAINS ALL "+strlist ; case ContainsAnyStrings: if(terms.size() == 1) return varstr + " CONTAINS "+strlist ; else return varstr + " CONTAINS ONE OF "+strlist ; case EqualsString: if(terms.size() == 1) return varstr + " IS "+strlist ; else return varstr + " IS ONE OF "+strlist ; default: return "" ; } } bool StringExpression :: evalStr ( const std::string &str ){ std::list::iterator iter; switch (Op) { case ContainsAllStrings: for ( iter = terms.begin(); iter != terms.end(); ++iter ) { if ( StrContains (str, *iter, IgnoreCase) == false ){ return false; } } return true; break; case ContainsAnyStrings: for ( iter = terms.begin(); iter != terms.end(); ++iter ) { if ( StrContains (str,*iter, IgnoreCase) == true ) { return true; } } break; case EqualsString: for ( iter = terms.begin(); iter != terms.end(); ++iter ) { if ( StrEquals (str,*iter, IgnoreCase) == true ) { return true; } } break; default: return false; } return false; } /************************************************************************* * linearization code *************************************************************************/ void CompoundExpression::linearize(LinearizedExpression& e) const { e._tokens.push_back(LinearizedExpression::EXPR_COMP) ; e._ints.push_back(Op) ; Lexp->linearize(e) ; Rexp->linearize(e) ; } void StringExpression::linearize(LinearizedExpression& e) const { e._ints.push_back(Op) ; e._ints.push_back(IgnoreCase) ; e._ints.push_back(terms.size()) ; for(std::list::const_iterator it(terms.begin());it!=terms.end();++it) e._strings.push_back(*it) ; } Expression *LinearizedExpression::toExpr(const LinearizedExpression& e) { int i=0,j=0,k=0 ; return toExpr(e,i,j,k) ; } void LinearizedExpression::readStringExpr(const LinearizedExpression& e,int& n_ints,int& n_strings,std::list& strings,bool& b,StringOperator& op) { op = static_cast(e._ints[n_ints++]) ; b = e._ints[n_ints++] ; int n = e._ints[n_ints++] ; strings.clear() ; for(int i=0;i::const_iterator i = this->_strings.begin(); i != this->_strings.end(); ++i) { str += *i; str += " "; } return str; } Expression *LinearizedExpression::toExpr(const LinearizedExpression& e,int& n_tok,int& n_ints,int& n_strings) { LinearizedExpression::token tok = static_cast(e._tokens[n_tok++]) ; switch(tok) { case EXPR_DATE: { RelOperator op = static_cast(e._ints[n_ints++]) ; int lv = e._ints[n_ints++] ; int hv = e._ints[n_ints++] ; return new DateExpression(op,lv,hv) ; } case EXPR_POP: { RelOperator op = static_cast(e._ints[n_ints++]) ; int lv = e._ints[n_ints++] ; int hv = e._ints[n_ints++] ; return new PopExpression(op,lv,hv) ; } case EXPR_SIZE: { RelOperator op = static_cast(e._ints[n_ints++]) ; int lv = e._ints[n_ints++] ; int hv = e._ints[n_ints++] ; return new SizeExpression(op,lv,hv) ; } case EXPR_HASH: { std::list strings ; StringOperator op ; bool b ; readStringExpr(e,n_ints,n_strings,strings,b,op) ; return new HashExpression(op,strings) ; } case EXPR_NAME: { std::list strings ; StringOperator op ; bool b ; readStringExpr(e,n_ints,n_strings,strings,b,op) ; return new NameExpression(op,strings,b) ; } case EXPR_PATH: { std::list strings ; StringOperator op ; bool b ; readStringExpr(e,n_ints,n_strings,strings,b,op) ; return new ExtExpression(op,strings,b) ; } case EXPR_EXT: { std::list strings ; StringOperator op ; bool b ; readStringExpr(e,n_ints,n_strings,strings,b,op) ; return new ExtExpression(op,strings,b) ; } case EXPR_COMP: { LogicalOperator op = static_cast(e._ints[n_ints++]) ; Expression *e1 = toExpr(e,n_tok,n_ints,n_strings) ; Expression *e2 = toExpr(e,n_tok,n_ints,n_strings) ; return new CompoundExpression(op,e1,e2) ; } case EXPR_SIZE_MB: { RelOperator op = static_cast(e._ints[n_ints++]) ; int lv = e._ints[n_ints++] ; int hv = e._ints[n_ints++] ; return new SizeExpressionMB(op,lv,hv) ; } default: std::cerr << "No expression match the current value " << tok << std::endl ; return NULL ; } } }