|
Packit |
a4aae4 |
// -*- mode: c++; c-basic-offset:4 -*-
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
|
|
Packit |
a4aae4 |
// Access Protocol.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Copyright (c) 2011 OPeNDAP, Inc.
|
|
Packit |
a4aae4 |
// Author: James Gallagher <jgallagher@opendap.org>
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is free software; you can redistribute it and/or
|
|
Packit |
a4aae4 |
// modify it under the terms of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License as published by the Free Software Foundation; either
|
|
Packit |
a4aae4 |
// version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is distributed in the hope that it will be useful,
|
|
Packit |
a4aae4 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a4aae4 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
a4aae4 |
// Lesser General Public License for more details.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You should have received a copy of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License along with this library; if not, write to the Free Software
|
|
Packit |
a4aae4 |
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <iostream>
|
|
Packit |
a4aae4 |
#include <vector>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
//#define DODS_DEBUG
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "Keywords2.h"
|
|
Packit |
a4aae4 |
#include "Error.h"
|
|
Packit |
a4aae4 |
#include "escaping.h"
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
using namespace std;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Keywords::Keywords()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Load known keywords and their allowed values
|
|
Packit |
a4aae4 |
vector<string> v1(7);
|
|
Packit |
a4aae4 |
v1[0] = "2"; v1[1] = "2.0"; v1[2] = "3.2"; v1[3] = "3.3"; v1[4] = "3.4";
|
|
Packit |
a4aae4 |
v1[5] = "4"; v1[6] = "4.0";
|
|
Packit |
a4aae4 |
value_set_t vs = value_set_t(v1.begin(), v1.end());
|
|
Packit |
a4aae4 |
d_known_keywords["dap"] = vs;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
vector<string> v2(4);
|
|
Packit |
a4aae4 |
v2[0] = "md5"; v2[1] = "MD5"; v2[2] = "sha1"; v2[3] = "SHA1";
|
|
Packit |
a4aae4 |
value_set_t vs2 = value_set_t(v2.begin(), v2.end());
|
|
Packit |
a4aae4 |
d_known_keywords["checksum"] = vs2;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Keywords::~Keywords()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Static function to parse the keyword notation.
|
|
Packit |
a4aae4 |
* @param kw the keyword clause '<word> ( <value> )'
|
|
Packit |
a4aae4 |
* @param word (result) the word
|
|
Packit |
a4aae4 |
* @param value (result) the value
|
|
Packit |
a4aae4 |
* @return True if the parse was successful (word and value contain useful
|
|
Packit |
a4aae4 |
* results) and False otherwise.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
static bool f_parse_keyword(const string &kw, string &word, string &value)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
word = "";
|
|
Packit |
a4aae4 |
value = "";
|
|
Packit |
a4aae4 |
string::size_type i = kw.find('(');
|
|
Packit |
a4aae4 |
if (i == string::npos)
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
word = kw.substr(0, i);
|
|
Packit |
a4aae4 |
string::size_type j = kw.find(')');
|
|
Packit |
a4aae4 |
if (j == string::npos)
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
++i; // Move past the opening paren
|
|
Packit |
a4aae4 |
value = kw.substr(i, j-i);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return (!word.empty() && !value.empty());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Add the keyword to the set of keywords that apply to this request.
|
|
Packit |
a4aae4 |
* @note Should call m_is_valid_keyword first.
|
|
Packit |
a4aae4 |
* @param word The keyword/function name
|
|
Packit |
a4aae4 |
* @param value The keyword/function value
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void Keywords::m_add_keyword(const keyword &word, const keyword_value &value)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
d_parsed_keywords[word] = value;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Is the string a valid keyword clause? Assumption: the word and value have
|
|
Packit |
a4aae4 |
* already been successfully parsed.
|
|
Packit |
a4aae4 |
* @param word The keyword/function name
|
|
Packit |
a4aae4 |
* @param value The keyword/function value
|
|
Packit |
a4aae4 |
* @return True if the string is valid keyword and the value is one of the
|
|
Packit |
a4aae4 |
* allowed values.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool Keywords::m_is_valid_keyword(const keyword &word, const keyword_value &value) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
map<keyword, value_set_t>::const_iterator ci = d_known_keywords.find(word);
|
|
Packit |
a4aae4 |
if (ci == d_known_keywords.end())
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
value_set_t vs = ci->second;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (vs.find(value) == vs.end())
|
|
Packit |
a4aae4 |
throw Error("Bad value passed to the keyword/function: " + word);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Is the word one of the known keywords for this version of libdap?
|
|
Packit |
a4aae4 |
* @param s As a string, including the value
|
|
Packit |
a4aae4 |
* @return true if the keyword is known
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool Keywords::is_known_keyword(const string &word) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_known_keywords.count(word) == 1;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Get a list of the strings that make up the set of current keywords for
|
|
Packit |
a4aae4 |
* this request.
|
|
Packit |
a4aae4 |
* @return The list of keywords as a list of string objects.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
list<Keywords::keyword> Keywords::get_keywords() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
list<keyword> kws;
|
|
Packit |
a4aae4 |
map<keyword, keyword_value>::const_iterator i;
|
|
Packit |
a4aae4 |
for (i = d_parsed_keywords.begin(); i != d_parsed_keywords.end(); ++i)
|
|
Packit |
a4aae4 |
kws.push_front((*i).first);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return kws;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Lookup a keyword_kind and return true if it has been set for this request,
|
|
Packit |
a4aae4 |
* otherwise return false.
|
|
Packit |
a4aae4 |
* @param kw Keyword
|
|
Packit |
a4aae4 |
* @return true if the keyword is set.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool Keywords::has_keyword(const keyword &kw) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_parsed_keywords.count(kw) == 1;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Look at the parsed keywords for the value associated with a given keyword.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param k
|
|
Packit |
a4aae4 |
* @return The value
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
Keywords::keyword_value Keywords::get_keyword_value(const keyword &kw) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (d_known_keywords.find(kw) == d_known_keywords.end())
|
|
Packit |
a4aae4 |
throw Error("Keyword not known (" + kw + ")");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return d_parsed_keywords.find(kw)->second;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Parse the constraint expression, removing all keywords. As a side effect,
|
|
Packit |
a4aae4 |
* return the remaining CE.
|
|
Packit |
a4aae4 |
* @param ce
|
|
Packit |
a4aae4 |
* @return The CE stripped of all recognized keywords.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
string Keywords::parse_keywords(const string &ce)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Get the whole CE
|
|
Packit |
a4aae4 |
string projection = www2id(ce, "%", "%20");
|
|
Packit |
a4aae4 |
string selection = "";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Separate the selection part (which follows/includes the first '&')
|
|
Packit |
a4aae4 |
string::size_type amp = projection.find('&';;
|
|
Packit |
a4aae4 |
if (amp != string::npos) {
|
|
Packit |
a4aae4 |
selection = projection.substr(amp);
|
|
Packit |
a4aae4 |
projection = projection.substr(0, amp);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Extract keywords; add to the Keywords keywords. For this, scan for
|
|
Packit |
a4aae4 |
// a known set of keywords and assume that anything else is part of the
|
|
Packit |
a4aae4 |
// projection and should be left alone. Keywords must come before variables
|
|
Packit |
a4aae4 |
// The 'projection' string will look like: '' or 'dap4.0' or 'dap4.0,u,v'
|
|
Packit |
a4aae4 |
while (!projection.empty()) {
|
|
Packit |
a4aae4 |
string::size_type i = projection.find(',');
|
|
Packit |
a4aae4 |
string next_word = projection.substr(0, i);
|
|
Packit |
a4aae4 |
string word, value;
|
|
Packit |
a4aae4 |
if (f_parse_keyword(next_word, word, value)
|
|
Packit |
a4aae4 |
&& m_is_valid_keyword(word, value)) {
|
|
Packit |
a4aae4 |
m_add_keyword(word, value);
|
|
Packit |
a4aae4 |
if (i != string::npos)
|
|
Packit |
a4aae4 |
projection = projection.substr(i + 1);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
projection = "";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
break; // exit on first non-keyword
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// The CE is whatever is left after removing the keywords
|
|
Packit |
a4aae4 |
return projection + selection;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
}
|