/* 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 << "type().name << ")" << ">"; var = ss.str().c_str(); return true; } case Variant::Type::FUNCTION: { // Print function pointer address Variant::functionType obj = var.asFunction(); std::stringstream ss; ss << ""; var = ss.str().c_str(); return true; } default: break; } } // No conversion possible, assign default value and log error logger.error(msgUnexpectedType(var.getType(), Variant::Type::STRING)); var = ""; return false; } }