• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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