diff options
author | Eino-Ville Talvala <etalvala@google.com> | 2018-11-15 15:49:02 -0800 |
---|---|---|
committer | Eino-Ville Talvala <etalvala@google.com> | 2018-11-15 16:07:24 -0800 |
commit | 09f199a694ef5b956cabc368e40ab5ca11c64044 (patch) | |
tree | 456d184a3817c8b6524a90fc2da60893a2fc1895 /internal/xmpmeta/xml/deserializer_impl.cc | |
parent | 2d25fc4f6a7e7453f877958a2f3f59b6cc588ca4 (diff) | |
download | dynamic_depth-09f199a694ef5b956cabc368e40ab5ca11c64044.tar.gz |
Initial commit of libdynamic_depth
Dynamic depth is a standard for embedding depth maps and
other similar extensions into standard image files like JPEG.
Test: m libdynamic_depth
Bug: 109735087
Bug: 119211681
Change-Id: I0103b7d47e60dc8e3a3b277456903d76f727926f
Diffstat (limited to 'internal/xmpmeta/xml/deserializer_impl.cc')
-rw-r--r-- | internal/xmpmeta/xml/deserializer_impl.cc | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/internal/xmpmeta/xml/deserializer_impl.cc b/internal/xmpmeta/xml/deserializer_impl.cc new file mode 100644 index 0000000..6214a0c --- /dev/null +++ b/internal/xmpmeta/xml/deserializer_impl.cc @@ -0,0 +1,321 @@ +#include "xmpmeta/xml/deserializer_impl.h" + +#include <algorithm> + +#include "base/integral_types.h" +#include "android-base/logging.h" +#include "strings/numbers.h" +#include "xmpmeta/base64.h" +#include "xmpmeta/xml/const.h" +#include "xmpmeta/xml/search.h" +#include "xmpmeta/xml/utils.h" +#include "xmpmeta/xmp_parser.h" + +namespace photos_editing_formats { +namespace xml { +namespace { + +// Converts a string to a boolean value if bool_str is one of "false" or "true", +// regardless of letter casing. +bool BoolStringToBool(const string& bool_str, bool* value) { + string bool_str_lower = bool_str; + std::transform(bool_str_lower.begin(), bool_str_lower.end(), + bool_str_lower.begin(), ::tolower); + if (bool_str_lower == "true") { + *value = true; + return true; + } + if (bool_str_lower == "false") { + *value = false; + return true; + } + return false; +} + +// Search for an rdf:Seq node, if it hasn't already been set. +// parent_name is the name of the rdf:Seq node's parent. +xmlNodePtr FindSeqNode(const xmlNodePtr node, const string& prefix, + const string& parent_name) { + xmlNodePtr parent_node = + DepthFirstSearch(node, prefix.data(), parent_name.data()); + if (parent_node == nullptr) { + LOG(WARNING) << "Node " << parent_name << " not found"; + return nullptr; + } + return GetFirstSeqElement(parent_node); +} + +// Extracts the specified string attribute. +bool GetStringProperty(const xmlNodePtr node, const string& prefix, + const string& property, string* value) { + const xmlDocPtr doc = node->doc; + for (const _xmlAttr* attribute = node->properties; attribute != nullptr; + attribute = attribute->next) { + // If prefix is not empty, then the attribute's namespace must not be null. + if (((attribute->ns && !prefix.empty() && + strcmp(FromXmlChar(attribute->ns->prefix), prefix.data()) == 0) || + prefix.empty()) && + strcmp(FromXmlChar(attribute->name), property.data()) == 0) { + xmlChar* attribute_string = + xmlNodeListGetString(doc, attribute->children, 1); + *value = FromXmlChar(attribute_string); + xmlFree(attribute_string); + return true; + } + } + LOG(WARNING) << "Could not find string attribute: " << property; + return false; +} + +// Reads the contents of a node. +// E.g. <prefix:node_name>Contents Here</prefix:node_name> +bool ReadNodeContent(const xmlNodePtr node, const string& prefix, + const string& node_name, string* value) { + auto* element = DepthFirstSearch(node, prefix.data(), node_name.data()); + if (element == nullptr) { + return false; + } + if (!prefix.empty() && + (element->ns == nullptr || element->ns->prefix == nullptr || + strcmp(FromXmlChar(element->ns->prefix), prefix.data()) != 0)) { + return false; + } + xmlChar* node_content = xmlNodeGetContent(element); + *value = FromXmlChar(node_content); + free(node_content); + return true; +} + +// Reads the string value of a property from the given XML node. +bool ReadStringProperty(const xmlNodePtr node, const string& prefix, + const string& property, string* value) { + if (node == nullptr) { + return false; + } + if (property.empty()) { + LOG(ERROR) << "Property not given"; + return false; + } + + // Try parsing in the format <Node ... Prefix:Property="Value"/> + bool success = GetStringProperty(node, prefix, property, value); + if (!success) { + // Try parsing in the format <Prefix:Property>Value</Prefix:Property> + success = ReadNodeContent(node, prefix, property, value); + } + return success; +} + +// Same as ReadStringProperty, but applies base-64 decoding to the output. +bool ReadBase64Property(const xmlNodePtr node, const string& prefix, + const string& property, string* value) { + string base64_data; + if (!ReadStringProperty(node, prefix, property, &base64_data)) { + return false; + } + return DecodeBase64(base64_data, value); +} + +} // namespace + +DeserializerImpl::DeserializerImpl(const xmlNodePtr node) + : node_(node), list_node_(nullptr) {} + +// Public methods. +std::unique_ptr<Deserializer> DeserializerImpl::CreateDeserializer( + const string& prefix, const string& child_name) const { + if (child_name.empty()) { + LOG(ERROR) << "Child name is empty"; + return nullptr; + } + xmlNodePtr child_node = + DepthFirstSearch(node_, prefix.data(), child_name.data()); + if (child_node == nullptr) { + return nullptr; + } + return std::unique_ptr<Deserializer>( + new DeserializerImpl(child_node)); // NOLINT +} + +std::unique_ptr<Deserializer> +DeserializerImpl::CreateDeserializerFromListElementAt(const string& prefix, + const string& list_name, + int index) const { + if (index < 0) { + LOG(ERROR) << "Index must be greater than or equal to zero"; + return nullptr; + } + + if (list_name.empty()) { + LOG(ERROR) << "Parent name cannot be empty"; + return nullptr; + } + // Search for an rdf:Seq node, if the name of list_node_ doesn't match + // the given parent name. + // Ensures thread safety. + const xmlNodePtr list_node = [&] { + std::lock_guard<std::mutex> lock(mtx_); + if (list_node_ == nullptr || + string(FromXmlChar(list_node_->name)) != list_name) { + list_node_ = DepthFirstSearch(node_, prefix.data(), list_name.data()); + } + return list_node_; + }(); + if (list_node == nullptr) { + return nullptr; + } + + xmlNodePtr seq_node = GetFirstSeqElement(list_node); + if (seq_node == nullptr) { + LOG(ERROR) << "No rdf:Seq node found on " << list_name; + return nullptr; + } + xmlNodePtr li_node = GetElementAt(seq_node, index); + if (li_node == nullptr) { + return nullptr; + } + // Return a new Deserializer with the current rdf:li node and the current + // node name. + return std::unique_ptr<Deserializer>( + new DeserializerImpl(li_node)); // NOLINT +} + +bool DeserializerImpl::ParseBase64(const string& prefix, const string& name, + string* value) const { + return ReadBase64Property(node_, prefix, name, value); +} + +bool DeserializerImpl::ParseIntArrayBase64(const string& prefix, + const string& name, + std::vector<int>* values) const { + string base64_data; + if (!ReadStringProperty(node_, prefix, name, &base64_data)) { + return false; + } + return DecodeIntArrayBase64(base64_data, values); +} + +bool DeserializerImpl::ParseFloatArrayBase64(const string& prefix, + const string& name, + std::vector<float>* values) const { + string base64_data; + if (!ReadStringProperty(node_, prefix, name, &base64_data)) { + return false; + } + return DecodeFloatArrayBase64(base64_data, values); +} + +bool DeserializerImpl::ParseDoubleArrayBase64( + const string& prefix, const string& name, + std::vector<double>* values) const { + string base64_data; + if (!ReadStringProperty(node_, prefix, name, &base64_data)) { + return false; + } + return DecodeDoubleArrayBase64(base64_data, values); +} + +bool DeserializerImpl::ParseBoolean(const string& prefix, const string& name, + bool* value) const { + string string_value; + if (!ReadStringProperty(node_, prefix, name, &string_value)) { + return false; + } + return BoolStringToBool(string_value, value); +} + +bool DeserializerImpl::ParseDouble(const string& prefix, const string& name, + double* value) const { + string string_value; + if (!ReadStringProperty(node_, prefix, name, &string_value)) { + return false; + } + *value = std::stod(string_value); + return true; +} + +bool DeserializerImpl::ParseInt(const string& prefix, const string& name, + int* value) const { + string string_value; + if (!ReadStringProperty(node_, prefix, name, &string_value)) { + return false; + } + *value = std::stoi(string_value); // NOLINT + return true; +} + +bool DeserializerImpl::ParseFloat(const string& prefix, const string& name, + float* value) const { + string string_value; + if (!ReadStringProperty(node_, prefix, name, &string_value)) { + return false; + } + *value = std::stof(string_value); + return true; +} + +bool DeserializerImpl::ParseLong(const string& prefix, const string& name, + int64* value) const { + string string_value; + if (!ReadStringProperty(node_, prefix, name, &string_value)) { + return false; + } + *value = std::stol(string_value); + return true; +} + +bool DeserializerImpl::ParseString(const string& prefix, const string& name, + string* value) const { + return ReadStringProperty(node_, prefix, name, value); +} + +bool DeserializerImpl::ParseIntArray(const string& prefix, + const string& list_name, + std::vector<int>* values) const { + xmlNodePtr seq_node = FindSeqNode(node_, prefix, list_name); + if (seq_node == nullptr) { + return false; + } + values->clear(); + int i = 0; + for (xmlNodePtr li_node = GetElementAt(seq_node, 0); li_node != nullptr; + li_node = GetElementAt(seq_node, ++i)) { + string value = GetLiNodeContent(li_node); + for (int i = 0; i < value.size(); ++i) { + if (!isdigit(value[i])) { + LOG(ERROR) << "Could not parse rdf:li node value to an integer"; + return false; + } + } + int int_value = std::atoi(value.c_str()); // NOLINT + values->push_back(int_value); + } + + return true; +} + +bool DeserializerImpl::ParseDoubleArray(const string& prefix, + const string& list_name, + std::vector<double>* values) const { + xmlNodePtr seq_node = FindSeqNode(node_, prefix, list_name); + if (seq_node == nullptr) { + return false; + } + values->clear(); + int i = 0; + for (xmlNodePtr li_node = GetElementAt(seq_node, 0); li_node != nullptr; + li_node = GetElementAt(seq_node, ++i)) { + double double_value; + if (!dynamic_depth::strings::safe_strtod(GetLiNodeContent(li_node), + &double_value)) { + LOG(ERROR) << "Could not parse rdf:li node value to a double"; + return false; + } + values->push_back(double_value); + } + + return true; +} + +} // namespace xml +} // namespace photos_editing_formats |