blob: d76210ee5d712232624e75179e86453852675f0f [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include "AddressParser.h"
#include "qpid/framing/Uuid.h"
#include <boost/format.hpp>
namespace qpid {
namespace messaging {
using namespace qpid::types;
AddressParser::AddressParser(const std::string& s) : input(s), current(0) {}
bool AddressParser::error(const std::string& message)
{
throw MalformedAddress((boost::format("%1%, character %2% of %3%") % message % current % input).str());
}
bool AddressParser::parse(Address& address)
{
std::string name;
if (readName(name)) {
if (name.find('#') == 0) name = qpid::framing::Uuid(true).str() + name;
address.setName(name);
if (readChar('/')) {
std::string subject;
readSubject(subject);
address.setSubject(subject);
}
if (readChar(';')) {
Variant options = Variant::Map();
if (readMap(options)) {
address.setOptions(options.asMap());
}
}
//skip trailing whitespace
while (!eos() && iswhitespace()) ++current;
return eos() || error("Unexpected chars in address: " + input.substr(current));
} else {
return input.empty() || error("Expected name");
}
}
bool AddressParser::parseMap(Variant::Map& map)
{
if (readChar('{')) {
readMapEntries(map);
return readChar('}') || error("Unmatched '{'!");
} else {
return false;
}
}
bool AddressParser::parseList(Variant::List& list)
{
if (readChar('[')) {
readListItems(list);
return readChar(']') || error("Unmatched '['!");
} else {
return false;
}
}
bool AddressParser::readList(Variant& value)
{
if (readChar('[')) {
value = Variant::List();
readListItems(value.asList());
return readChar(']') || error("Unmatched '['!");
} else {
return false;
}
}
void AddressParser::readListItems(Variant::List& list)
{
Variant item;
while (readValueIfExists(item)) {
list.push_back(item);
if (!readChar(',')) break;
}
}
bool AddressParser::readMap(Variant& value)
{
if (readChar('{')) {
value = Variant::Map();
readMapEntries(value.asMap());
return readChar('}') || error("Unmatched '{'!");
} else {
return false;
}
}
void AddressParser::readMapEntries(Variant::Map& map)
{
while (readKeyValuePair(map) && readChar(',')) {}
}
bool AddressParser::readKeyValuePair(Variant::Map& map)
{
std::string key;
Variant value;
if (readKey(key)) {
if (readChar(':') && readValue(value)) {
map[key] = value;
return true;
} else {
return error("Bad key-value pair, expected ':'");
}
} else {
return false;
}
}
bool AddressParser::readKey(std::string& key)
{
return readWord(key) || readQuotedString(key);
}
bool AddressParser::readValue(Variant& value)
{
return readValueIfExists(value) || error("Expected value");
}
bool AddressParser::readValueIfExists(Variant& value)
{
return readSimpleValue(value) || readQuotedValue(value) ||
readMap(value) || readList(value);
}
bool AddressParser::readString(std::string& value, char delimiter)
{
if (readChar(delimiter)) {
std::string::size_type start = current;
while (!eos()) {
if (input.at(current) == delimiter) {
if (current > start) {
value = input.substr(start, current - start);
} else {
value = "";
}
++current;
return true;
} else {
++current;
}
}
return error("Unmatched delimiter");
} else {
return false;
}
}
bool AddressParser::readName(std::string& name)
{
return readQuotedString(name) || readWord(name, "/;");
}
bool AddressParser::readSubject(std::string& subject)
{
return readQuotedString(subject) || readWord(subject, ";");
}
bool AddressParser::readQuotedString(std::string& s)
{
return readString(s, '"') || readString(s, '\'');
}
bool AddressParser::readQuotedValue(Variant& value)
{
std::string s;
if (readQuotedString(s)) {
value = s;
return true;
} else {
return false;
}
}
bool AddressParser::readSimpleValue(Variant& value)
{
std::string s;
if (readWord(s)) {
value.parse(s);
if (value.getType() == VAR_STRING) value.setEncoding("utf8");
return true;
} else {
return false;
}
}
bool AddressParser::readWord(std::string& value, const std::string& delims)
{
//skip leading whitespace
while (!eos() && iswhitespace()) ++current;
//read any number of non-whitespace, non-reserved chars into value
std::string::size_type start = current;
while (!eos() && !iswhitespace() && !in(delims)) ++current;
if (current > start) {
value = input.substr(start, current - start);
return true;
} else {
return false;
}
}
bool AddressParser::readChar(char c)
{
while (!eos()) {
if (iswhitespace()) {
++current;
} else if (input.at(current) == c) {
++current;
return true;
} else {
return false;
}
}
return false;
}
bool AddressParser::iswhitespace()
{
return ::isspace(input.at(current));
}
bool AddressParser::isreserved()
{
return in(RESERVED);
}
bool AddressParser::in(const std::string& chars)
{
return chars.find(input.at(current)) != std::string::npos;
}
bool AddressParser::eos()
{
return current >= input.size();
}
const std::string AddressParser::RESERVED = "\'\"{}[],:/";
}} // namespace qpid::messaging