* limitations under the License.
*/
+#include "json-utils.h"
#include <bundle.h>
#include <bundle_internal.h>
#include "common/logger.h"
#include "common/picojson.h"
-#include "json-utils.h"
+#include <algorithm>
-namespace common {
+namespace {
+using Octet = unsigned char;
-PlatformResult JsonToBundle(const picojson::object& json, bundle* bundle_data) {
+bool IsOctet(double value) {
+ return 0 <= value && value <= 255;
+}
+
+int BundleAddString(const std::string& key, const picojson::value& value, bundle* bundle_data) {
ScopeLogger();
- for (const auto& entry: json) {
- int ret = bundle_add(bundle_data, entry.first.c_str(), entry.second.serialize().c_str());
- if (BUNDLE_ERROR_NONE != ret) {
- return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error occured during json to bundle conversion",
- ("bundle_add() returned error code: %d, error msg: %s", ret, get_error_message(ret)));
- }
+ return bundle_add_str(bundle_data, key.c_str(), value.get<std::string>().c_str());
+}
+
+std::vector<Octet> JsonArrayToByteStream(const picojson::array& jarray) {
+ ScopeLogger();
+ std::vector<Octet> bytes;
+ bytes.reserve(jarray.size());
+
+ for (const auto& elem : jarray) {
+ bytes.push_back(static_cast<Octet>(elem.get<double>()));
}
- return PlatformResult(ErrorCode::NO_ERROR);
+
+ return bytes;
}
-PlatformResult BundleToJson(bundle* bundle_data, picojson::object* json) {
- picojson::array array_data;
- bundle_foreach(bundle_data, BundleJsonIterator, &array_data);
+int BundleAddByteStream(const std::string& key, const picojson::value& value, bundle* bundle_data) {
+ ScopeLogger();
+ const picojson::array& jarray = value.get<picojson::array>();
+ auto bytes = JsonArrayToByteStream(jarray);
+ return bundle_add_byte(bundle_data, key.c_str(), bytes.data(), bytes.size());
+}
- for (auto& elem: array_data) {
- (*json)[elem.get("key").get<std::string>()] = elem.get("value");
- }
+int BundleAddStringArray(const std::string& key, const picojson::value& value,
+ bundle* bundle_data) {
+ ScopeLogger();
+ const auto& jarray = value.get<picojson::array>();
+
+ std::vector<const char*> cstrings;
+ cstrings.reserve(jarray.size());
- return PlatformResult(ErrorCode::NO_ERROR);
+ for (const auto& elem : jarray) {
+ cstrings.push_back(elem.get<std::string>().c_str());
+ }
+
+ return bundle_add_str_array(bundle_data, key.c_str(), cstrings.data(), cstrings.size());
}
-PlatformResult JsonToBundle(const picojson::array& json, bundle* bundle_data) {
+int BundleAddByteStreamArray(const std::string& key, const picojson::value& value, bundle* bundle_data) {
ScopeLogger();
- for (const auto& item: json) {
- if (!item.is<picojson::object>()) {
- return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Invalid json structure",
- ("item.is<picojson::object>() returned false"));
- }
- const auto& json = item.get<picojson::object>();
+ const auto& jarray = value.get<picojson::array>();
- if (json.find("key") == json.end()) {
- return LogAndCreateResult(ErrorCode::VALIDATION_ERR, "Key attribute is missing",
- ("Key attribute not found in json object."));
- }
- if (!json.at("key").is<std::string>()) {
- return LogAndCreateResult(ErrorCode::VALIDATION_ERR, "Key attribute needs to have string type",
- ("Key attribute is not a string. Key value: %s", json.at("key").serialize().c_str()));
+ std::vector<std::vector<Octet>> bytes_array;
+ bytes_array.reserve(jarray.size());
+
+ for (const auto& elem : jarray) {
+ bytes_array.push_back(JsonArrayToByteStream(elem.get<picojson::array>()));
+ }
+
+ int ret = bundle_add_byte_array(bundle_data, key.c_str(), nullptr, bytes_array.size());
+ if (BUNDLE_ERROR_NONE != ret) {
+ return ret;
+ }
+
+ for (unsigned int idx = 0; idx < bytes_array.size(); ++idx) {
+ ret = bundle_set_byte_array_element(bundle_data, key.c_str(), idx, bytes_array[idx].data(),
+ bytes_array[idx].size());
+
+ if (BUNDLE_ERROR_NONE != ret) {
+ return ret;
}
- std::string key = json.at("key").get<std::string>();
+ }
+
+ return BUNDLE_ERROR_NONE;
+}
- if (json.find("value") == json.end()) {
- return LogAndCreateResult(ErrorCode::VALIDATION_ERR, "Value attribute is missing",
- ("Value attribute not found in json object."));
+template <typename Type>
+bool JsonValueTypeCheck(const picojson::value& value) {
+ return value.is<Type>();
+}
+
+template <>
+bool JsonValueTypeCheck<Octet>(const picojson::value& value) {
+ return JsonValueTypeCheck<double>(value) && IsOctet(value.get<double>());
+}
+
+bundle_type GetBundleType(const picojson::value& value) {
+ ScopeLogger();
+ if (JsonValueTypeCheck<std::string>(value)) return BUNDLE_TYPE_STR;
+
+ if (!JsonValueTypeCheck<picojson::array>(value)) return BUNDLE_TYPE_ANY;
+ const auto& jarray = value.get<picojson::array>();
+
+ if (std::all_of(jarray.begin(), jarray.end(), JsonValueTypeCheck<std::string>)) {
+ return BUNDLE_TYPE_STR_ARRAY;
+ }
+
+ if (std::all_of(jarray.begin(), jarray.end(), JsonValueTypeCheck<Octet>)) {
+ return BUNDLE_TYPE_BYTE;
+ }
+
+ for (const auto& elem : jarray) {
+ if (!elem.is<picojson::array>()) {
+ return BUNDLE_TYPE_ANY;
}
- if (!json.at("value").is<std::string>()) {
- return LogAndCreateResult(ErrorCode::VALIDATION_ERR, "Value attribute needs to have string type",
- ("Value attribute is not a string. Value: %s", json.at("value").serialize().c_str()));
+
+ const auto& subarray = elem.get<picojson::array>();
+ if (!std::all_of(subarray.begin(), subarray.end(), JsonValueTypeCheck<Octet>)) {
+ return BUNDLE_TYPE_ANY;
}
- std::string value = json.at("value").get<std::string>();
+ }
+
+ return BUNDLE_TYPE_BYTE_ARRAY;
+}
+
+int BundleAdd(const std::string& key, const picojson::value& value, bundle* bundle_data) {
+ ScopeLogger();
+ switch (GetBundleType(value)) {
+ case BUNDLE_TYPE_STR:
+ return BundleAddString(key, value, bundle_data);
+ case BUNDLE_TYPE_STR_ARRAY:
+ return BundleAddStringArray(key, value, bundle_data);
+ case BUNDLE_TYPE_BYTE:
+ return BundleAddByteStream(key, value, bundle_data);
+ case BUNDLE_TYPE_BYTE_ARRAY:
+ return BundleAddByteStreamArray(key, value, bundle_data);
+ default:
+ LoggerE("Unsupported bundle value type.");
+ return BUNDLE_ERROR_INVALID_PARAMETER;
+ }
+ return BUNDLE_ERROR_NONE;
+}
- int ret = bundle_add(bundle_data, key.c_str(), value.c_str());
+} // namespace
+
+namespace common {
+
+PlatformResult JsonToBundle(const picojson::object& json, bundle* bundle_data) {
+ ScopeLogger();
+ for (const auto& property : json) {
+ int ret = BundleAdd(property.first, property.second, bundle_data);
if (BUNDLE_ERROR_NONE != ret) {
- return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Error occured during json to bundle conversion",
- ("bundle_add() returned error code: %d, error msg: %s", ret, get_error_message(ret)));
+ LoggerE("BundleAdd failed with error message: %s", get_error_message(ret));
+ return PlatformResult(ErrorCode::UNKNOWN_ERR);
}
}
return PlatformResult(ErrorCode::NO_ERROR);
}
+PlatformResult BundleToJson(bundle* bundle_data, picojson::object* json) {
+ ScopeLogger();
+ picojson::array array_data;
+ bundle_foreach(bundle_data, BundleJsonIterator, &array_data);
+
+ for (auto& elem : array_data) {
+ (*json)[elem.get("key").get<std::string>()] = elem.get("value");
+ }
+
+ return PlatformResult(ErrorCode::NO_ERROR);
+}
+
void BundleJsonIterator(const char* key, const int type, const bundle_keyval_t* kv, void* d) {
ScopeLogger();
array->push_back(picojson::value(o));
}
-} // namespace common
-
+} // namespace common
// Tizen API Specification:
// https://developer.tizen.org/dev-guide/2.3.0/org.tizen.mobile.web.device.apireference/tizen/tizen.html
-
// WebAPIException and WebAPIError definition moved to src/utils/utils_api.js
// for compliance reasons. You can find more info there.
});
};
exports.SimpleCoordinates.prototype.constructor = exports.SimpleCoordinates;
+
+
+function forEachOwnProperty(obj, callback) {
+ for (var prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ callback(prop, obj[prop]);
+ }
+ }
+}
+
+var BundleValueType = {
+ STRING: 'STRING',
+ STRING_ARRAY: 'STRING_ARRAY',
+ BYTES: 'BYTES',
+ BYTES_ARRAY: 'BYTES_ARRAY'
+};
+exports.BundleValueType = BundleValueType;
+
+function getValueType(value) {
+ if (xwalk.utils.type.isString(value)) {
+ return BundleValueType.STRING;
+ }
+ if (xwalk.utils.type.isStringArray(value)) {
+ return BundleValueType.STRING_ARRAY;
+ }
+ if (xwalk.utils.type.isByteStream(value)) {
+ return BundleValueType.BYTES;
+ }
+ if (xwalk.utils.type.isByteStreamArray(value)) {
+ return BundleValueType.BYTES_ARRAY;
+ }
+}
+
+exports.Bundle = function(json) {
+ xwalk.utils.validator.isConstructorCall(this, exports.Bundle);
+ this.data = {};
+
+ if (xwalk.utils.validator.isObject(json)) {
+ forEachOwnProperty(
+ json,
+ function(key, value) {
+ this.set(key, value);
+ }.bind(this)
+ );
+ }
+};
+exports.Bundle.prototype.constructor = exports.Bundle;
+
+exports.Bundle.prototype.set = function(key, value) {
+ if (undefined === getValueType(value)) {
+ value = xwalk.utils.converter.toString(value);
+ }
+ this.data[key] = value;
+};
+
+exports.Bundle.prototype.get = function(key) {
+ if (!this.data.hasOwnProperty(key)) {
+ throw new WebAPIException(WebAPIException.NOT_FOUND_ERR);
+ }
+ return this.data[key];
+};
+
+exports.Bundle.prototype.typeOf = function(key) {
+ if (!this.data.hasOwnProperty(key)) {
+ throw new WebAPIException(WebAPIException.NOT_FOUND_ERR);
+ }
+ return getValueType(this.data[key]);
+};
+
+exports.Bundle.prototype.forEach = function(callback) {
+ forEachOwnProperty(
+ this.data,
+ function(key, value) {
+ callback(key, value, this.typeOf(key));
+ }.bind(this)
+ );
+};
+
+exports.Bundle.prototype.toJSON = function() {
+ var json = {};
+ this.forEach(function(key, value) {
+ json[key] = value;
+ });
+ return json;
+};
+
+exports.Bundle.prototype.toString = function() {
+ return JSON.stringify(this.data);
+};
+