2010-05-21 03:13:36 +02:00
|
|
|
// Copyright (c) 2010, Amar Takhar <verm@aegisub.org>
|
|
|
|
//
|
|
|
|
// Permission to use, copy, modify, and distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
|
|
// copyright notice and this permission notice appear in all copies.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
|
|
|
|
/// @file option_visit.cpp
|
|
|
|
/// @brief Cajun JSON visitor to load config values.
|
|
|
|
/// @see option_visit.h
|
|
|
|
/// @ingroup libaegisub
|
|
|
|
|
|
|
|
#ifndef LAGI_PRE
|
2011-07-27 00:25:21 +02:00
|
|
|
#include <cmath>
|
2010-05-23 08:58:11 +02:00
|
|
|
#include <memory>
|
2010-05-21 03:13:36 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <libaegisub/colour.h>
|
2011-07-15 06:04:34 +02:00
|
|
|
#include <libaegisub/option_value.h>
|
2010-05-21 03:13:36 +02:00
|
|
|
#include "option_visit.h"
|
|
|
|
|
|
|
|
namespace agi {
|
|
|
|
|
2011-07-15 06:04:34 +02:00
|
|
|
ConfigVisitor::ConfigVisitor(OptionValueMap &val, const std::string &member_name)
|
|
|
|
: values(val)
|
2011-10-11 02:06:34 +02:00
|
|
|
, name(member_name)
|
2011-07-15 06:04:34 +02:00
|
|
|
{
|
2010-05-21 03:13:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigVisitor::Visit(const json::Object& object) {
|
2011-10-17 23:59:35 +02:00
|
|
|
json::Object::const_iterator index(object.begin()), index_end(object.end());
|
2010-05-21 03:13:36 +02:00
|
|
|
|
2011-10-11 02:06:34 +02:00
|
|
|
if (!name.empty())
|
|
|
|
name += "/";
|
|
|
|
|
2010-05-21 03:13:36 +02:00
|
|
|
for (; index != index_end; ++index) {
|
2011-10-18 00:00:28 +02:00
|
|
|
ConfigVisitor config_visitor(values, name + index->first);
|
|
|
|
index->second.Accept(config_visitor);
|
2010-05-21 03:13:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-04 20:42:40 +01:00
|
|
|
template<class T>
|
|
|
|
static inline T convert_unknown(json::UnknownElement const& ue) {
|
|
|
|
return ue;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
inline int64_t convert_unknown(json::UnknownElement const& ue) {
|
|
|
|
return (int64_t)(double)ue;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class OptionValueType, class ValueType>
|
|
|
|
static OptionValue *read_array(json::Array const& src, std::string const& array_type, std::string const& name, void (OptionValueType::*set_list)(const std::vector<ValueType>&)) {
|
|
|
|
std::vector<ValueType> arr;
|
|
|
|
arr.reserve(src.size());
|
|
|
|
|
|
|
|
for (json::Array::const_iterator it = src.begin(); it != src.end(); ++it) {
|
|
|
|
json::Object const& obj = *it;
|
|
|
|
|
|
|
|
if (obj.size() != 1)
|
|
|
|
throw OptionJsonValueArray("Invalid array member");
|
|
|
|
if (obj.begin()->first != array_type)
|
|
|
|
throw OptionJsonValueArray("Attempt to insert value into array of wrong type");
|
|
|
|
|
|
|
|
arr.push_back(convert_unknown<ValueType>(obj.begin()->second));
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionValueType *ret = new OptionValueType(name);
|
|
|
|
(ret->*set_list)(arr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-05-21 03:13:36 +02:00
|
|
|
void ConfigVisitor::Visit(const json::Array& array) {
|
2011-11-04 20:42:40 +01:00
|
|
|
if (array.empty())
|
|
|
|
throw OptionJsonValueArray("Cannot infer the type of an empty array");
|
|
|
|
|
|
|
|
json::Object const& front = array.front();
|
|
|
|
if (front.size() != 1)
|
|
|
|
throw OptionJsonValueArray("Invalid array member");
|
|
|
|
|
|
|
|
const std::string& array_type = front.begin()->first;
|
|
|
|
|
|
|
|
if (array_type == "string")
|
|
|
|
AddOptionValue(read_array(array, array_type, name, &OptionValueListString::SetListString));
|
|
|
|
else if (array_type == "int")
|
|
|
|
AddOptionValue(read_array(array, array_type, name, &OptionValueListInt::SetListInt));
|
|
|
|
else if (array_type == "double")
|
|
|
|
AddOptionValue(read_array(array, array_type, name, &OptionValueListDouble::SetListDouble));
|
|
|
|
else if (array_type == "bool")
|
|
|
|
AddOptionValue(read_array(array, array_type, name, &OptionValueListBool::SetListBool));
|
|
|
|
else if (array_type == "colour")
|
|
|
|
AddOptionValue(read_array(array, array_type, name, &OptionValueListColour::SetListColour));
|
|
|
|
else
|
|
|
|
throw OptionJsonValueArray("Array type not handled");
|
2010-05-21 03:13:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ConfigVisitor::Visit(const json::Number& number) {
|
2011-10-17 23:59:59 +02:00
|
|
|
if (int64_t(number) == ceil(number)) {
|
2011-10-18 00:00:28 +02:00
|
|
|
AddOptionValue(new OptionValueInt(name, int64_t(number)));
|
2010-05-21 03:13:36 +02:00
|
|
|
} else {
|
2011-10-18 00:00:28 +02:00
|
|
|
AddOptionValue(new OptionValueDouble(name, number));
|
2010-05-21 03:13:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigVisitor::Visit(const json::String& string) {
|
2011-10-17 23:59:59 +02:00
|
|
|
if (string.find("rgb(") == 0) {
|
2011-10-18 00:00:28 +02:00
|
|
|
AddOptionValue(new OptionValueColour(name, string));
|
2010-05-21 03:13:36 +02:00
|
|
|
} else {
|
2011-10-18 00:00:28 +02:00
|
|
|
AddOptionValue(new OptionValueString(name, string));
|
2010-05-21 03:13:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigVisitor::Visit(const json::Boolean& boolean) {
|
2011-10-18 00:00:28 +02:00
|
|
|
AddOptionValue(new OptionValueBool(name, boolean));
|
2010-05-21 03:13:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigVisitor::Visit(const json::Null& null) {
|
|
|
|
throw OptionJsonValueNull("Attempt to read null value");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConfigVisitor::AddOptionValue(OptionValue* opt) {
|
|
|
|
OptionValue *opt_cur;
|
|
|
|
|
|
|
|
OptionValueMap::iterator index;
|
|
|
|
|
2011-10-11 02:06:34 +02:00
|
|
|
if ((index = values.find(name)) != values.end()) {
|
2010-05-21 03:13:36 +02:00
|
|
|
opt_cur = index->second;
|
|
|
|
} else {
|
2011-10-11 02:06:34 +02:00
|
|
|
values.insert(OptionValuePair(name, opt));
|
2010-05-21 03:13:36 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-23 08:58:11 +02:00
|
|
|
// Ensure than opt is deleted at the end of this function even if the Set
|
|
|
|
// method throws
|
|
|
|
std::auto_ptr<OptionValue> auto_opt(opt);
|
|
|
|
|
2010-05-21 03:13:36 +02:00
|
|
|
int type = opt_cur->GetType();
|
|
|
|
switch (type) {
|
|
|
|
case OptionValue::Type_String:
|
|
|
|
opt_cur->SetString(opt->GetString());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OptionValue::Type_Int:
|
|
|
|
opt_cur->SetInt(opt->GetInt());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OptionValue::Type_Double:
|
|
|
|
opt_cur->SetDouble(opt->GetDouble());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OptionValue::Type_Colour:
|
|
|
|
opt_cur->SetColour(opt->GetColour());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OptionValue::Type_Bool:
|
|
|
|
opt_cur->SetBool(opt->GetBool());
|
|
|
|
break;
|
|
|
|
|
2011-11-04 20:42:31 +01:00
|
|
|
case OptionValue::Type_List_String:
|
|
|
|
opt_cur->SetListString(opt->GetListString());
|
2010-05-21 03:13:36 +02:00
|
|
|
break;
|
|
|
|
|
2011-11-04 20:42:31 +01:00
|
|
|
case OptionValue::Type_List_Int:
|
|
|
|
opt_cur->SetListInt(opt->GetListInt());
|
2010-05-21 03:13:36 +02:00
|
|
|
break;
|
|
|
|
|
2011-11-04 20:42:31 +01:00
|
|
|
case OptionValue::Type_List_Double:
|
|
|
|
opt_cur->SetListDouble(opt->GetListDouble());
|
2010-05-21 03:13:36 +02:00
|
|
|
break;
|
|
|
|
|
2011-11-04 20:42:31 +01:00
|
|
|
case OptionValue::Type_List_Colour:
|
|
|
|
opt_cur->SetListColour(opt->GetListColour());
|
2010-05-21 03:13:36 +02:00
|
|
|
break;
|
|
|
|
|
2011-11-04 20:42:31 +01:00
|
|
|
case OptionValue::Type_List_Bool:
|
|
|
|
opt_cur->SetListBool(opt->GetListBool());
|
2010-05-21 03:13:36 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace agi
|