1 #include "xmpmeta/xml/serializer_impl.h" 2 3 #include <libxml/tree.h> 4 5 #include "base/integral_types.h" 6 #include "android-base/logging.h" 7 #include "strings/numbers.h" 8 #include "xmpmeta/xml/const.h" 9 #include "xmpmeta/xml/utils.h" 10 11 namespace dynamic_depth { 12 namespace xmpmeta { 13 namespace xml { 14 15 // Methods specific to SerializerImpl. 16 SerializerImpl::SerializerImpl( 17 const std::unordered_map<string, xmlNsPtr>& namespaces, xmlNodePtr node) 18 : node_(node), namespaces_(namespaces) { 19 CHECK(node_ != nullptr) << "Node cannot be null"; 20 CHECK(node_->name != nullptr) << "Name in the XML node cannot be null"; 21 } 22 23 bool SerializerImpl::SerializeNamespaces() { 24 if (namespaces_.empty()) { 25 return true; 26 } 27 if (node_->ns == nullptr && !namespaces_.empty()) { 28 return false; 29 } 30 // Check that the namespaces all have hrefs and that there is a value 31 // for the key node_name. 32 // Set the namespaces in the root node. 33 xmlNsPtr node_ns = node_->ns; 34 for (const auto& entry : namespaces_) { 35 CHECK(entry.second->href != nullptr) << "Namespace href cannot be null"; 36 if (node_ns != nullptr) { 37 node_ns->next = entry.second; 38 } 39 node_ns = entry.second; 40 } 41 return true; 42 } 43 44 std::unique_ptr<SerializerImpl> SerializerImpl::FromDataAndSerializeNamespaces( 45 const std::unordered_map<string, xmlNsPtr>& namespaces, xmlNodePtr node) { 46 std::unique_ptr<SerializerImpl> serializer = 47 std::unique_ptr<SerializerImpl>( // NOLINT 48 new SerializerImpl(namespaces, node)); // NOLINT 49 if (!serializer->SerializeNamespaces()) { 50 LOG(ERROR) << "Could not serialize namespaces"; 51 return nullptr; 52 } 53 return serializer; 54 } 55 56 // Implemented methods. 57 std::unique_ptr<Serializer> SerializerImpl::CreateSerializer( 58 const string& node_ns_name, const string& node_name) const { 59 if (node_name.empty()) { 60 LOG(ERROR) << "Node name is empty"; 61 return nullptr; 62 } 63 64 if (namespaces_.count(node_ns_name) == 0 && !node_ns_name.empty()) { 65 LOG(ERROR) << "Prefix " << node_ns_name << " not found in prefix list"; 66 return nullptr; 67 } 68 69 xmlNodePtr new_node = 70 xmlNewNode(node_ns_name.empty() ? nullptr : namespaces_.at(node_ns_name), 71 ToXmlChar(node_name.data())); 72 xmlAddChild(node_, new_node); 73 return std::unique_ptr<Serializer>( 74 new SerializerImpl(namespaces_, new_node)); // NOLINT 75 } 76 77 std::unique_ptr<Serializer> SerializerImpl::CreateItemSerializer( 78 const string& prefix, const string& item_name) const { 79 if (namespaces_.count(XmlConst::RdfPrefix()) == 0 || 80 namespaces_.at(XmlConst::RdfPrefix()) == nullptr) { 81 LOG(ERROR) << "No RDF prefix namespace found"; 82 return nullptr; 83 } 84 if (!prefix.empty() && !namespaces_.count(prefix)) { 85 LOG(ERROR) << "No namespace found for " << prefix; 86 return nullptr; 87 } 88 if (strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name)) != 0) { 89 LOG(ERROR) << "No rdf:Seq node for serializing this item"; 90 return nullptr; 91 } 92 93 xmlNsPtr rdf_prefix_ns = namespaces_.at(string(XmlConst::RdfPrefix())); 94 xmlNodePtr li_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfLi())); 95 xmlNodePtr new_node = 96 xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix), 97 ToXmlChar(item_name.data())); 98 xmlSetNs(li_node, rdf_prefix_ns); 99 xmlAddChild(node_, li_node); 100 xmlAddChild(li_node, new_node); 101 return std::unique_ptr<Serializer>( 102 new SerializerImpl(namespaces_, new_node)); // NOLINT 103 } 104 105 std::unique_ptr<Serializer> SerializerImpl::CreateListSerializer( 106 const string& prefix, const string& list_name) const { 107 if (namespaces_.count(XmlConst::RdfPrefix()) == 0 || 108 namespaces_.at(XmlConst::RdfPrefix()) == nullptr) { 109 LOG(ERROR) << "No RDF prefix namespace found"; 110 return nullptr; 111 } 112 if (!prefix.empty() && !namespaces_.count(prefix)) { 113 LOG(ERROR) << "No namespace found for " << prefix; 114 return nullptr; 115 } 116 117 xmlNodePtr list_node = 118 xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix), 119 ToXmlChar(list_name.data())); 120 xmlNsPtr rdf_prefix_ns = namespaces_.at(string(XmlConst::RdfPrefix())); 121 xmlNodePtr seq_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfSeq())); 122 xmlSetNs(seq_node, rdf_prefix_ns); 123 xmlAddChild(list_node, seq_node); 124 xmlAddChild(node_, list_node); 125 return std::unique_ptr<Serializer>( 126 new SerializerImpl(namespaces_, seq_node)); // NOLINT 127 } 128 129 bool SerializerImpl::WriteBoolProperty(const string& prefix, const string& name, 130 bool value) const { 131 const string& bool_str = (value ? "true" : "false"); 132 return WriteProperty(prefix, name, bool_str); 133 } 134 135 bool SerializerImpl::WriteProperty(const string& prefix, const string& name, 136 const string& value) const { 137 if (!strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name))) { 138 LOG(ERROR) << "Cannot write a property on an rdf:Seq node"; 139 return false; 140 } 141 if (name.empty()) { 142 LOG(ERROR) << "Property name is empty"; 143 return false; 144 } 145 146 // Check that prefix has a corresponding namespace href. 147 if (!prefix.empty() && namespaces_.count(prefix) == 0) { 148 LOG(ERROR) << "No namespace found for prefix " << prefix; 149 return false; 150 } 151 152 // Serialize the property in the format Prefix:Name="Value". 153 xmlSetNsProp(node_, prefix.empty() ? nullptr : namespaces_.at(prefix), 154 ToXmlChar(name.data()), ToXmlChar(value.data())); 155 return true; 156 } 157 158 bool SerializerImpl::WriteIntArray(const string& prefix, 159 const string& array_name, 160 const std::vector<int>& values) const { 161 if (!strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name))) { 162 LOG(ERROR) << "Cannot write a property on an rdf:Seq node"; 163 return false; 164 } 165 if (values.empty()) { 166 LOG(WARNING) << "No values to write"; 167 return false; 168 } 169 if (namespaces_.count(XmlConst::RdfPrefix()) == 0 || 170 namespaces_.at(XmlConst::RdfPrefix()) == nullptr) { 171 LOG(ERROR) << "No RDF prefix found"; 172 return false; 173 } 174 if (!prefix.empty() && !namespaces_.count(prefix)) { 175 LOG(ERROR) << "No namespace found for " << prefix; 176 return false; 177 } 178 if (array_name.empty()) { 179 LOG(ERROR) << "Parent name cannot be empty"; 180 return false; 181 } 182 183 xmlNodePtr array_parent_node = 184 xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix), 185 ToXmlChar(array_name.data())); 186 xmlAddChild(node_, array_parent_node); 187 188 xmlNsPtr rdf_prefix_ns = namespaces_.at(XmlConst::RdfPrefix()); 189 xmlNodePtr seq_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfSeq())); 190 xmlSetNs(seq_node, rdf_prefix_ns); 191 xmlAddChild(array_parent_node, seq_node); 192 for (int value : values) { 193 xmlNodePtr li_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfLi())); 194 xmlSetNs(li_node, rdf_prefix_ns); 195 xmlAddChild(seq_node, li_node); 196 xmlNodeSetContent(li_node, ToXmlChar(std::to_string(value).c_str())); 197 } 198 199 return true; 200 } 201 202 bool SerializerImpl::WriteDoubleArray(const string& prefix, 203 const string& array_name, 204 const std::vector<double>& values) const { 205 if (!strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name))) { 206 LOG(ERROR) << "Cannot write a property on an rdf:Seq node"; 207 return false; 208 } 209 if (values.empty()) { 210 LOG(WARNING) << "No values to write"; 211 return false; 212 } 213 if (namespaces_.count(XmlConst::RdfPrefix()) == 0 || 214 namespaces_.at(XmlConst::RdfPrefix()) == nullptr) { 215 LOG(ERROR) << "No RDF prefix found"; 216 return false; 217 } 218 if (!prefix.empty() && !namespaces_.count(prefix)) { 219 LOG(ERROR) << "No namespace found for " << prefix; 220 return false; 221 } 222 if (array_name.empty()) { 223 LOG(ERROR) << "Parent name cannot be empty"; 224 return false; 225 } 226 227 xmlNodePtr array_parent_node = 228 xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix), 229 ToXmlChar(array_name.data())); 230 xmlAddChild(node_, array_parent_node); 231 232 xmlNsPtr rdf_prefix_ns = namespaces_.at(XmlConst::RdfPrefix()); 233 xmlNodePtr seq_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfSeq())); 234 xmlSetNs(seq_node, rdf_prefix_ns); 235 xmlAddChild(array_parent_node, seq_node); 236 for (float value : values) { 237 xmlNodePtr li_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfLi())); 238 xmlSetNs(li_node, rdf_prefix_ns); 239 xmlAddChild(seq_node, li_node); 240 xmlNodeSetContent( 241 li_node, ToXmlChar(dynamic_depth::strings::SimpleFtoa(value).c_str())); 242 } 243 244 return true; 245 } 246 247 } // namespace xml 248 } // namespace xmpmeta 249 } // namespace dynamic_depth 250