summaryrefslogtreecommitdiff
path: root/src/core/common/VariantConverter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/common/VariantConverter.cpp')
-rw-r--r--src/core/common/VariantConverter.cpp255
1 files changed, 255 insertions, 0 deletions
diff --git a/src/core/common/VariantConverter.cpp b/src/core/common/VariantConverter.cpp
new file mode 100644
index 0000000..f9d465e
--- /dev/null
+++ b/src/core/common/VariantConverter.cpp
@@ -0,0 +1,255 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <string>
+#include <sstream>
+
+#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 << "<object " << obj.get() << " (" << obj->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 << "<function " << obj.get() << ">";
+ 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;
+}
+}
+