/*
Ousía
Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include "Logger.hpp"
#include "Number.hpp"
#include "Rtti.hpp"
#include "Variant.hpp"
#include "VariantConverter.hpp"
#include "VariantWriter.hpp"
namespace ousia {
static std::string msgUnexpectedType(Variant::Type actualType,
Variant::Type requestedType)
{
return std::string("Cannot convert ") + Variant::getTypeName(actualType) +
std::string(" to ") + Variant::getTypeName(requestedType);
}
bool VariantConverter::toBool(Variant &var, Logger &logger, Mode mode)
{
// Perform safe conversions
const Variant::Type type = var.getType();
switch (type) {
case Variant::Type::BOOL:
// No conversion needed if "var" already is a boolean
return true;
default:
break;
}
// Perform potentially dangerous conversions in the "ALL" mode
if (mode == Mode::ALL) {
switch (var.getType()) {
case Variant::Type::NULLPTR:
var = false;
return true;
case Variant::Type::INT:
var = var.asInt() != 0;
return true;
case Variant::Type::DOUBLE:
var = var.asDouble() != 0.0;
return true;
default:
var = true;
return true;
}
}
// No conversion possible, assign default value and log error
logger.error(msgUnexpectedType(var.getType(), Variant::Type::BOOL));
var = false;
return false;
}
bool VariantConverter::toInt(Variant &var, Logger &logger, Mode mode)
{
// Perform safe conversions
const Variant::Type type = var.getType();
switch (type) {
case Variant::Type::INT:
// No conversion needed if "var" already is an integer
return true;
default:
break;
}
// Perform all potentially dangerous conversions in the "ALL" mode
if (mode == Mode::ALL) {
switch (type) {
case Variant::Type::NULLPTR:
var = 0;
return true;
case Variant::Type::BOOL:
var = var.asBool() ? 1 : 0;
return true;
case Variant::Type::DOUBLE:
var = (Variant::intType)var.asDouble();
return true;
case Variant::Type::STRING:
case Variant::Type::MAGIC: {
Number n;
n.parse(var.asString(), logger);
if (n.isInt()) {
var = (Variant::intType)n.intValue();
} else {
var = (Variant::doubleType)n.doubleValue();
}
return true;
}
case Variant::Type::ARRAY: {
try {
// JavaScript behaviour when converting arrays to doubles
const Variant::arrayType &a = var.asArray();
var = (a.size() == 1) ? a[0].toInt() : 0.0;
return true;
}
catch (LoggableException ex) {
logger.log(ex);
}
}
default:
break;
}
}
// No conversion possible, assign default value and log error
logger.error(msgUnexpectedType(var.getType(), Variant::Type::INT));
var = 0;
return false;
}
bool VariantConverter::toDouble(Variant &var, Logger &logger, Mode mode)
{
// Perform safe conversions
const Variant::Type type = var.getType();
switch (type) {
case Variant::Type::DOUBLE:
// No conversion needed if "var" already is a double
return true;
case Variant::Type::INT:
// Converting integers to doubles is safe
var = (Variant::doubleType)var.asInt();
return true;
default:
break;
}
// Perform all potentially dangerous conversions in the "ALL" mode
if (mode == Mode::ALL) {
switch (type) {
case Variant::Type::NULLPTR:
var = 0.0;
return true;
case Variant::Type::BOOL:
var = var.asBool() ? 1.0 : 0.0;
return true;
case Variant::Type::STRING:
case Variant::Type::MAGIC: {
Number n;
n.parse(var.asString(), logger);
var = (Variant::doubleType)n.doubleValue();
return true;
}
case Variant::Type::ARRAY: {
try {
// JavaScript behaviour when converting arrays to doubles
const Variant::arrayType &a = var.asArray();
var = (a.size() == 1) ? a[0].toDouble() : 0.0;
return true;
}
catch (LoggableException ex) {
logger.log(ex);
}
}
default:
break;
}
}
// No conversion possible, assign default value and log error
logger.error(msgUnexpectedType(var.getType(), Variant::Type::DOUBLE));
var = 0.0;
return false;
}
bool VariantConverter::toString(Variant &var, Logger &logger, Mode mode)
{
// Perform safe conversions (all these operations are considered "lossless")
const Variant::Type type = var.getType();
switch (type) {
case Variant::Type::NULLPTR:
var = "null";
return true;
case Variant::Type::BOOL:
var = var.asBool() ? "true" : "false";
return true;
case Variant::Type::INT: {
std::stringstream ss;
ss << var.asInt();
var = ss.str().c_str();
return true;
}
case Variant::Type::DOUBLE: {
std::stringstream ss;
ss << var.asDouble();
var = ss.str().c_str();
return true;
}
case Variant::Type::MAGIC:
case Variant::Type::STRING:
// No conversion needed if "var" already is a string (or a magic
// string value)
return true;
default:
break;
}
// Perform lossy conversions
if (mode == Mode::ALL) {
switch (type) {
case Variant::Type::ARRAY:
case Variant::Type::MAP: {
std::stringstream ss;
VariantWriter::writeJson(var, ss, false);
var = ss.str().c_str();
return true;
}
case Variant::Type::OBJECT: {
// Print object address and type
Variant::objectType obj = var.asObject();
std::stringstream ss;
ss << "