#include "xmpmeta/xml/serializer_impl.h" #include #include "base/integral_types.h" #include "android-base/logging.h" #include "strings/numbers.h" #include "xmpmeta/xml/const.h" #include "xmpmeta/xml/utils.h" namespace dynamic_depth { namespace xmpmeta { namespace xml { // Methods specific to SerializerImpl. SerializerImpl::SerializerImpl( const std::unordered_map& namespaces, xmlNodePtr node) : node_(node), namespaces_(namespaces) { CHECK(node_ != nullptr) << "Node cannot be null"; CHECK(node_->name != nullptr) << "Name in the XML node cannot be null"; } bool SerializerImpl::SerializeNamespaces() { if (namespaces_.empty()) { return true; } if (node_->ns == nullptr && !namespaces_.empty()) { return false; } // Check that the namespaces all have hrefs and that there is a value // for the key node_name. // Set the namespaces in the root node. xmlNsPtr node_ns = node_->ns; for (const auto& entry : namespaces_) { CHECK(entry.second->href != nullptr) << "Namespace href cannot be null"; if (node_ns != nullptr) { node_ns->next = entry.second; } node_ns = entry.second; } return true; } std::unique_ptr SerializerImpl::FromDataAndSerializeNamespaces( const std::unordered_map& namespaces, xmlNodePtr node) { std::unique_ptr serializer = std::unique_ptr( // NOLINT new SerializerImpl(namespaces, node)); // NOLINT if (!serializer->SerializeNamespaces()) { LOG(ERROR) << "Could not serialize namespaces"; return nullptr; } return serializer; } // Implemented methods. std::unique_ptr SerializerImpl::CreateSerializer( const string& node_ns_name, const string& node_name) const { if (node_name.empty()) { LOG(ERROR) << "Node name is empty"; return nullptr; } if (namespaces_.count(node_ns_name) == 0 && !node_ns_name.empty()) { LOG(ERROR) << "Prefix " << node_ns_name << " not found in prefix list"; return nullptr; } xmlNodePtr new_node = xmlNewNode(node_ns_name.empty() ? nullptr : namespaces_.at(node_ns_name), ToXmlChar(node_name.data())); xmlAddChild(node_, new_node); return std::unique_ptr( new SerializerImpl(namespaces_, new_node)); // NOLINT } std::unique_ptr SerializerImpl::CreateItemSerializer( const string& prefix, const string& item_name) const { if (namespaces_.count(XmlConst::RdfPrefix()) == 0 || namespaces_.at(XmlConst::RdfPrefix()) == nullptr) { LOG(ERROR) << "No RDF prefix namespace found"; return nullptr; } if (!prefix.empty() && !namespaces_.count(prefix)) { LOG(ERROR) << "No namespace found for " << prefix; return nullptr; } if (strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name)) != 0) { LOG(ERROR) << "No rdf:Seq node for serializing this item"; return nullptr; } xmlNsPtr rdf_prefix_ns = namespaces_.at(string(XmlConst::RdfPrefix())); xmlNodePtr li_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfLi())); xmlNodePtr new_node = xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix), ToXmlChar(item_name.data())); xmlSetNs(li_node, rdf_prefix_ns); xmlAddChild(node_, li_node); xmlAddChild(li_node, new_node); return std::unique_ptr( new SerializerImpl(namespaces_, new_node)); // NOLINT } std::unique_ptr SerializerImpl::CreateListSerializer( const string& prefix, const string& list_name) const { if (namespaces_.count(XmlConst::RdfPrefix()) == 0 || namespaces_.at(XmlConst::RdfPrefix()) == nullptr) { LOG(ERROR) << "No RDF prefix namespace found"; return nullptr; } if (!prefix.empty() && !namespaces_.count(prefix)) { LOG(ERROR) << "No namespace found for " << prefix; return nullptr; } xmlNodePtr list_node = xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix), ToXmlChar(list_name.data())); xmlNsPtr rdf_prefix_ns = namespaces_.at(string(XmlConst::RdfPrefix())); xmlNodePtr seq_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfSeq())); xmlSetNs(seq_node, rdf_prefix_ns); xmlAddChild(list_node, seq_node); xmlAddChild(node_, list_node); return std::unique_ptr( new SerializerImpl(namespaces_, seq_node)); // NOLINT } bool SerializerImpl::WriteBoolProperty(const string& prefix, const string& name, bool value) const { const string& bool_str = (value ? "true" : "false"); return WriteProperty(prefix, name, bool_str); } bool SerializerImpl::WriteProperty(const string& prefix, const string& name, const string& value) const { if (!strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name))) { LOG(ERROR) << "Cannot write a property on an rdf:Seq node"; return false; } if (name.empty()) { LOG(ERROR) << "Property name is empty"; return false; } // Check that prefix has a corresponding namespace href. if (!prefix.empty() && namespaces_.count(prefix) == 0) { LOG(ERROR) << "No namespace found for prefix " << prefix; return false; } // Serialize the property in the format Prefix:Name="Value". xmlSetNsProp(node_, prefix.empty() ? nullptr : namespaces_.at(prefix), ToXmlChar(name.data()), ToXmlChar(value.data())); return true; } bool SerializerImpl::WriteIntArray(const string& prefix, const string& array_name, const std::vector& values) const { if (!strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name))) { LOG(ERROR) << "Cannot write a property on an rdf:Seq node"; return false; } if (values.empty()) { LOG(WARNING) << "No values to write"; return false; } if (namespaces_.count(XmlConst::RdfPrefix()) == 0 || namespaces_.at(XmlConst::RdfPrefix()) == nullptr) { LOG(ERROR) << "No RDF prefix found"; return false; } if (!prefix.empty() && !namespaces_.count(prefix)) { LOG(ERROR) << "No namespace found for " << prefix; return false; } if (array_name.empty()) { LOG(ERROR) << "Parent name cannot be empty"; return false; } xmlNodePtr array_parent_node = xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix), ToXmlChar(array_name.data())); xmlAddChild(node_, array_parent_node); xmlNsPtr rdf_prefix_ns = namespaces_.at(XmlConst::RdfPrefix()); xmlNodePtr seq_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfSeq())); xmlSetNs(seq_node, rdf_prefix_ns); xmlAddChild(array_parent_node, seq_node); for (int value : values) { xmlNodePtr li_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfLi())); xmlSetNs(li_node, rdf_prefix_ns); xmlAddChild(seq_node, li_node); xmlNodeSetContent(li_node, ToXmlChar(std::to_string(value).c_str())); } return true; } bool SerializerImpl::WriteDoubleArray(const string& prefix, const string& array_name, const std::vector& values) const { if (!strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name))) { LOG(ERROR) << "Cannot write a property on an rdf:Seq node"; return false; } if (values.empty()) { LOG(WARNING) << "No values to write"; return false; } if (namespaces_.count(XmlConst::RdfPrefix()) == 0 || namespaces_.at(XmlConst::RdfPrefix()) == nullptr) { LOG(ERROR) << "No RDF prefix found"; return false; } if (!prefix.empty() && !namespaces_.count(prefix)) { LOG(ERROR) << "No namespace found for " << prefix; return false; } if (array_name.empty()) { LOG(ERROR) << "Parent name cannot be empty"; return false; } xmlNodePtr array_parent_node = xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix), ToXmlChar(array_name.data())); xmlAddChild(node_, array_parent_node); xmlNsPtr rdf_prefix_ns = namespaces_.at(XmlConst::RdfPrefix()); xmlNodePtr seq_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfSeq())); xmlSetNs(seq_node, rdf_prefix_ns); xmlAddChild(array_parent_node, seq_node); for (float value : values) { xmlNodePtr li_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfLi())); xmlSetNs(li_node, rdf_prefix_ns); xmlAddChild(seq_node, li_node); xmlNodeSetContent( li_node, ToXmlChar(dynamic_depth::strings::SimpleFtoa(value).c_str())); } return true; } } // namespace xml } // namespace xmpmeta } // namespace dynamic_depth