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.
SerializerImpl(const std::unordered_map<string,xmlNsPtr> & namespaces,xmlNodePtr node)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
SerializeNamespaces()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
FromDataAndSerializeNamespaces(const std::unordered_map<string,xmlNsPtr> & namespaces,xmlNodePtr node)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.
CreateSerializer(const string & node_ns_name,const string & node_name) const57 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
CreateItemSerializer(const string & prefix,const string & item_name) const77 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
CreateListSerializer(const string & prefix,const string & list_name) const105 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
WriteBoolProperty(const string & prefix,const string & name,bool value) const129 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
WriteProperty(const string & prefix,const string & name,const string & value) const135 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
WriteIntArray(const string & prefix,const string & array_name,const std::vector<int> & values) const158 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
WriteDoubleArray(const string & prefix,const string & array_name,const std::vector<double> & values) const202 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