1 #include "xmpmeta/xml/deserializer_impl.h"
2
3 #include <algorithm>
4
5 #include "base/integral_types.h"
6 #include "android-base/logging.h"
7 #include "strings/numbers.h"
8 #include "xmpmeta/base64.h"
9 #include "xmpmeta/xml/const.h"
10 #include "xmpmeta/xml/search.h"
11 #include "xmpmeta/xml/utils.h"
12 #include "xmpmeta/xmp_parser.h"
13
14 namespace dynamic_depth {
15 namespace xmpmeta {
16 namespace xml {
17 namespace {
18
19 // Converts a string to a boolean value if bool_str is one of "false" or "true",
20 // regardless of letter casing.
BoolStringToBool(const string & bool_str,bool * value)21 bool BoolStringToBool(const string& bool_str, bool* value) {
22 string bool_str_lower = bool_str;
23 std::transform(bool_str_lower.begin(), bool_str_lower.end(),
24 bool_str_lower.begin(), ::tolower);
25 if (bool_str_lower == "true") {
26 *value = true;
27 return true;
28 }
29 if (bool_str_lower == "false") {
30 *value = false;
31 return true;
32 }
33 return false;
34 }
35
36 // Search for an rdf:Seq node, if it hasn't already been set.
37 // parent_name is the name of the rdf:Seq node's parent.
FindSeqNode(const xmlNodePtr node,const string & prefix,const string & parent_name)38 xmlNodePtr FindSeqNode(const xmlNodePtr node, const string& prefix,
39 const string& parent_name) {
40 xmlNodePtr parent_node =
41 DepthFirstSearch(node, prefix.data(), parent_name.data());
42 if (parent_node == nullptr) {
43 LOG(WARNING) << "Node " << parent_name << " not found";
44 return nullptr;
45 }
46 return GetFirstSeqElement(parent_node);
47 }
48
49 // Extracts the specified string attribute.
GetStringProperty(const xmlNodePtr node,const string & prefix,const string & property,string * value)50 bool GetStringProperty(const xmlNodePtr node, const string& prefix,
51 const string& property, string* value) {
52 const xmlDocPtr doc = node->doc;
53 for (const _xmlAttr* attribute = node->properties; attribute != nullptr;
54 attribute = attribute->next) {
55 // If prefix is not empty, then the attribute's namespace must not be null.
56 if (((attribute->ns && !prefix.empty() &&
57 strcmp(FromXmlChar(attribute->ns->prefix), prefix.data()) == 0) ||
58 prefix.empty()) &&
59 strcmp(FromXmlChar(attribute->name), property.data()) == 0) {
60 xmlChar* attribute_string =
61 xmlNodeListGetString(doc, attribute->children, 1);
62 *value = FromXmlChar(attribute_string);
63 xmlFree(attribute_string);
64 return true;
65 }
66 }
67 return false;
68 }
69
70 // Reads the contents of a node.
71 // E.g. <prefix:node_name>Contents Here</prefix:node_name>
ReadNodeContent(const xmlNodePtr node,const string & prefix,const string & node_name,string * value)72 bool ReadNodeContent(const xmlNodePtr node, const string& prefix,
73 const string& node_name, string* value) {
74 auto* element = DepthFirstSearch(node, prefix.data(), node_name.data());
75 if (element == nullptr) {
76 return false;
77 }
78 if (!prefix.empty() &&
79 (element->ns == nullptr || element->ns->prefix == nullptr ||
80 strcmp(FromXmlChar(element->ns->prefix), prefix.data()) != 0)) {
81 return false;
82 }
83 xmlChar* node_content = xmlNodeGetContent(element);
84 *value = FromXmlChar(node_content);
85 free(node_content);
86 return true;
87 }
88
89 // Reads the string value of a property from the given XML node.
ReadStringProperty(const xmlNodePtr node,const string & prefix,const string & property,string * value)90 bool ReadStringProperty(const xmlNodePtr node, const string& prefix,
91 const string& property, string* value) {
92 if (node == nullptr) {
93 return false;
94 }
95 if (property.empty()) {
96 LOG(ERROR) << "Property not given";
97 return false;
98 }
99
100 // Try parsing in the format <Node ... Prefix:Property="Value"/>
101 bool success = GetStringProperty(node, prefix, property, value);
102 if (!success) {
103 // Try parsing in the format <Prefix:Property>Value</Prefix:Property>
104 success = ReadNodeContent(node, prefix, property, value);
105 }
106 return success;
107 }
108
109 // Same as ReadStringProperty, but applies base-64 decoding to the output.
ReadBase64Property(const xmlNodePtr node,const string & prefix,const string & property,string * value)110 bool ReadBase64Property(const xmlNodePtr node, const string& prefix,
111 const string& property, string* value) {
112 string base64_data;
113 if (!ReadStringProperty(node, prefix, property, &base64_data)) {
114 return false;
115 }
116 return DecodeBase64(base64_data, value);
117 }
118
119 } // namespace
120
DeserializerImpl(const xmlNodePtr node)121 DeserializerImpl::DeserializerImpl(const xmlNodePtr node)
122 : node_(node), list_node_(nullptr) {}
123
124 // Public methods.
CreateDeserializer(const string & prefix,const string & child_name) const125 std::unique_ptr<Deserializer> DeserializerImpl::CreateDeserializer(
126 const string& prefix, const string& child_name) const {
127 if (child_name.empty()) {
128 LOG(ERROR) << "Child name is empty";
129 return nullptr;
130 }
131 xmlNodePtr child_node =
132 DepthFirstSearch(node_, prefix.data(), child_name.data());
133 if (child_node == nullptr) {
134 return nullptr;
135 }
136 return std::unique_ptr<Deserializer>(
137 new DeserializerImpl(child_node)); // NOLINT
138 }
139
140 std::unique_ptr<Deserializer>
CreateDeserializerFromListElementAt(const string & prefix,const string & list_name,int index) const141 DeserializerImpl::CreateDeserializerFromListElementAt(const string& prefix,
142 const string& list_name,
143 int index) const {
144 if (index < 0) {
145 LOG(ERROR) << "Index must be greater than or equal to zero";
146 return nullptr;
147 }
148
149 if (list_name.empty()) {
150 LOG(ERROR) << "Parent name cannot be empty";
151 return nullptr;
152 }
153 // Search for an rdf:Seq node, if the name of list_node_ doesn't match
154 // the given parent name.
155 // Ensures thread safety.
156 const xmlNodePtr list_node = [&] {
157 std::lock_guard<std::mutex> lock(mtx_);
158 if (list_node_ == nullptr ||
159 string(FromXmlChar(list_node_->name)) != list_name) {
160 list_node_ = DepthFirstSearch(node_, prefix.data(), list_name.data());
161 }
162 return list_node_;
163 }();
164 if (list_node == nullptr) {
165 return nullptr;
166 }
167
168 xmlNodePtr seq_node = GetFirstSeqElement(list_node);
169 if (seq_node == nullptr) {
170 LOG(ERROR) << "No rdf:Seq node found on " << list_name;
171 return nullptr;
172 }
173 xmlNodePtr li_node = GetElementAt(seq_node, index);
174 if (li_node == nullptr) {
175 return nullptr;
176 }
177 // Return a new Deserializer with the current rdf:li node and the current
178 // node name.
179 return std::unique_ptr<Deserializer>(
180 new DeserializerImpl(li_node)); // NOLINT
181 }
182
ParseBase64(const string & prefix,const string & name,string * value) const183 bool DeserializerImpl::ParseBase64(const string& prefix, const string& name,
184 string* value) const {
185 return ReadBase64Property(node_, prefix, name, value);
186 }
187
ParseIntArrayBase64(const string & prefix,const string & name,std::vector<int> * values) const188 bool DeserializerImpl::ParseIntArrayBase64(const string& prefix,
189 const string& name,
190 std::vector<int>* values) const {
191 string base64_data;
192 if (!ReadStringProperty(node_, prefix, name, &base64_data)) {
193 return false;
194 }
195 return DecodeIntArrayBase64(base64_data, values);
196 }
197
ParseFloatArrayBase64(const string & prefix,const string & name,std::vector<float> * values) const198 bool DeserializerImpl::ParseFloatArrayBase64(const string& prefix,
199 const string& name,
200 std::vector<float>* values) const {
201 string base64_data;
202 if (!ReadStringProperty(node_, prefix, name, &base64_data)) {
203 return false;
204 }
205 return DecodeFloatArrayBase64(base64_data, values);
206 }
207
ParseDoubleArrayBase64(const string & prefix,const string & name,std::vector<double> * values) const208 bool DeserializerImpl::ParseDoubleArrayBase64(
209 const string& prefix, const string& name,
210 std::vector<double>* values) const {
211 string base64_data;
212 if (!ReadStringProperty(node_, prefix, name, &base64_data)) {
213 return false;
214 }
215 return DecodeDoubleArrayBase64(base64_data, values);
216 }
217
ParseBoolean(const string & prefix,const string & name,bool * value) const218 bool DeserializerImpl::ParseBoolean(const string& prefix, const string& name,
219 bool* value) const {
220 string string_value;
221 if (!ReadStringProperty(node_, prefix, name, &string_value)) {
222 return false;
223 }
224 return BoolStringToBool(string_value, value);
225 }
226
ParseDouble(const string & prefix,const string & name,double * value) const227 bool DeserializerImpl::ParseDouble(const string& prefix, const string& name,
228 double* value) const {
229 string string_value;
230 if (!ReadStringProperty(node_, prefix, name, &string_value)) {
231 return false;
232 }
233 *value = std::stod(string_value);
234 return true;
235 }
236
ParseInt(const string & prefix,const string & name,int * value) const237 bool DeserializerImpl::ParseInt(const string& prefix, const string& name,
238 int* value) const {
239 string string_value;
240 if (!ReadStringProperty(node_, prefix, name, &string_value)) {
241 return false;
242 }
243 *value = std::stoi(string_value); // NOLINT
244 return true;
245 }
246
ParseFloat(const string & prefix,const string & name,float * value) const247 bool DeserializerImpl::ParseFloat(const string& prefix, const string& name,
248 float* value) const {
249 string string_value;
250 if (!ReadStringProperty(node_, prefix, name, &string_value)) {
251 return false;
252 }
253 *value = std::stof(string_value);
254 return true;
255 }
256
ParseLong(const string & prefix,const string & name,int64 * value) const257 bool DeserializerImpl::ParseLong(const string& prefix, const string& name,
258 int64* value) const {
259 string string_value;
260 if (!ReadStringProperty(node_, prefix, name, &string_value)) {
261 return false;
262 }
263 *value = std::stol(string_value);
264 return true;
265 }
266
ParseString(const string & prefix,const string & name,string * value) const267 bool DeserializerImpl::ParseString(const string& prefix, const string& name,
268 string* value) const {
269 return ReadStringProperty(node_, prefix, name, value);
270 }
271
ParseIntArray(const string & prefix,const string & list_name,std::vector<int> * values) const272 bool DeserializerImpl::ParseIntArray(const string& prefix,
273 const string& list_name,
274 std::vector<int>* values) const {
275 xmlNodePtr seq_node = FindSeqNode(node_, prefix, list_name);
276 if (seq_node == nullptr) {
277 return false;
278 }
279 values->clear();
280 int i = 0;
281 for (xmlNodePtr li_node = GetElementAt(seq_node, 0); li_node != nullptr;
282 li_node = GetElementAt(seq_node, ++i)) {
283 string value = GetLiNodeContent(li_node);
284 for (int i = 0; i < value.size(); ++i) {
285 if (!isdigit(value[i])) {
286 LOG(ERROR) << "Could not parse rdf:li node value to an integer";
287 return false;
288 }
289 }
290 int int_value = std::atoi(value.c_str()); // NOLINT
291 values->push_back(int_value);
292 }
293
294 return true;
295 }
296
ParseDoubleArray(const string & prefix,const string & list_name,std::vector<double> * values) const297 bool DeserializerImpl::ParseDoubleArray(const string& prefix,
298 const string& list_name,
299 std::vector<double>* values) const {
300 xmlNodePtr seq_node = FindSeqNode(node_, prefix, list_name);
301 if (seq_node == nullptr) {
302 return false;
303 }
304 values->clear();
305 int i = 0;
306 for (xmlNodePtr li_node = GetElementAt(seq_node, 0); li_node != nullptr;
307 li_node = GetElementAt(seq_node, ++i)) {
308 double double_value;
309 if (!dynamic_depth::strings::safe_strtod(GetLiNodeContent(li_node),
310 &double_value)) {
311 LOG(ERROR) << "Could not parse rdf:li node value to a double";
312 return false;
313 }
314 values->push_back(double_value);
315 }
316
317 return true;
318 }
319
320 } // namespace xml
321 } // namespace xmpmeta
322 } // namespace dynamic_depth
323