• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "ResourceUtils.h"
18 
19 #include <sstream>
20 
21 #include "androidfw/ResourceTypes.h"
22 #include "androidfw/ResourceUtils.h"
23 
24 #include "NameMangler.h"
25 #include "SdkConstants.h"
26 #include "flatten/ResourceTypeExtensions.h"
27 #include "util/Files.h"
28 #include "util/Util.h"
29 
30 using android::StringPiece;
31 using android::StringPiece16;
32 
33 namespace aapt {
34 namespace ResourceUtils {
35 
ToResourceName(const android::ResTable::resource_name & name_in)36 Maybe<ResourceName> ToResourceName(
37     const android::ResTable::resource_name& name_in) {
38   ResourceName name_out;
39   if (!name_in.package) {
40     return {};
41   }
42 
43   name_out.package =
44       util::Utf16ToUtf8(StringPiece16(name_in.package, name_in.packageLen));
45 
46   const ResourceType* type;
47   if (name_in.type) {
48     type = ParseResourceType(
49         util::Utf16ToUtf8(StringPiece16(name_in.type, name_in.typeLen)));
50   } else if (name_in.type8) {
51     type = ParseResourceType(StringPiece(name_in.type8, name_in.typeLen));
52   } else {
53     return {};
54   }
55 
56   if (!type) {
57     return {};
58   }
59 
60   name_out.type = *type;
61 
62   if (name_in.name) {
63     name_out.entry =
64         util::Utf16ToUtf8(StringPiece16(name_in.name, name_in.nameLen));
65   } else if (name_in.name8) {
66     name_out.entry.assign(name_in.name8, name_in.nameLen);
67   } else {
68     return {};
69   }
70   return name_out;
71 }
72 
ParseResourceName(const StringPiece & str,ResourceNameRef * out_ref,bool * out_private)73 bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref,
74                        bool* out_private) {
75   if (str.empty()) {
76     return false;
77   }
78 
79   size_t offset = 0;
80   bool priv = false;
81   if (str.data()[0] == '*') {
82     priv = true;
83     offset = 1;
84   }
85 
86   StringPiece package;
87   StringPiece type;
88   StringPiece entry;
89   if (!android::ExtractResourceName(str.substr(offset, str.size() - offset), &package, &type,
90                                     &entry)) {
91     return false;
92   }
93 
94   const ResourceType* parsed_type = ParseResourceType(type);
95   if (!parsed_type) {
96     return false;
97   }
98 
99   if (entry.empty()) {
100     return false;
101   }
102 
103   if (out_ref) {
104     out_ref->package = package;
105     out_ref->type = *parsed_type;
106     out_ref->entry = entry;
107   }
108 
109   if (out_private) {
110     *out_private = priv;
111   }
112   return true;
113 }
114 
ParseReference(const StringPiece & str,ResourceNameRef * out_ref,bool * out_create,bool * out_private)115 bool ParseReference(const StringPiece& str, ResourceNameRef* out_ref,
116                     bool* out_create, bool* out_private) {
117   StringPiece trimmed_str(util::TrimWhitespace(str));
118   if (trimmed_str.empty()) {
119     return false;
120   }
121 
122   bool create = false;
123   bool priv = false;
124   if (trimmed_str.data()[0] == '@') {
125     size_t offset = 1;
126     if (trimmed_str.data()[1] == '+') {
127       create = true;
128       offset += 1;
129     }
130 
131     ResourceNameRef name;
132     if (!ParseResourceName(
133             trimmed_str.substr(offset, trimmed_str.size() - offset), &name,
134             &priv)) {
135       return false;
136     }
137 
138     if (create && priv) {
139       return false;
140     }
141 
142     if (create && name.type != ResourceType::kId) {
143       return false;
144     }
145 
146     if (out_ref) {
147       *out_ref = name;
148     }
149 
150     if (out_create) {
151       *out_create = create;
152     }
153 
154     if (out_private) {
155       *out_private = priv;
156     }
157     return true;
158   }
159   return false;
160 }
161 
IsReference(const StringPiece & str)162 bool IsReference(const StringPiece& str) {
163   return ParseReference(str, nullptr, nullptr, nullptr);
164 }
165 
ParseAttributeReference(const StringPiece & str,ResourceNameRef * out_ref)166 bool ParseAttributeReference(const StringPiece& str, ResourceNameRef* out_ref) {
167   StringPiece trimmed_str(util::TrimWhitespace(str));
168   if (trimmed_str.empty()) {
169     return false;
170   }
171 
172   if (*trimmed_str.data() == '?') {
173     StringPiece package;
174     StringPiece type;
175     StringPiece entry;
176     if (!android::ExtractResourceName(trimmed_str.substr(1, trimmed_str.size() - 1), &package,
177                                       &type, &entry)) {
178       return false;
179     }
180 
181     if (!type.empty() && type != "attr") {
182       return false;
183     }
184 
185     if (entry.empty()) {
186       return false;
187     }
188 
189     if (out_ref) {
190       out_ref->package = package;
191       out_ref->type = ResourceType::kAttr;
192       out_ref->entry = entry;
193     }
194     return true;
195   }
196   return false;
197 }
198 
IsAttributeReference(const StringPiece & str)199 bool IsAttributeReference(const StringPiece& str) {
200   return ParseAttributeReference(str, nullptr);
201 }
202 
203 /*
204  * Style parent's are a bit different. We accept the following formats:
205  *
206  * @[[*]package:][style/]<entry>
207  * ?[[*]package:]style/<entry>
208  * <[*]package>:[style/]<entry>
209  * [[*]package:style/]<entry>
210  */
ParseStyleParentReference(const StringPiece & str,std::string * out_error)211 Maybe<Reference> ParseStyleParentReference(const StringPiece& str,
212                                            std::string* out_error) {
213   if (str.empty()) {
214     return {};
215   }
216 
217   StringPiece name = str;
218 
219   bool has_leading_identifiers = false;
220   bool private_ref = false;
221 
222   // Skip over these identifiers. A style's parent is a normal reference.
223   if (name.data()[0] == '@' || name.data()[0] == '?') {
224     has_leading_identifiers = true;
225     name = name.substr(1, name.size() - 1);
226   }
227 
228   if (name.data()[0] == '*') {
229     private_ref = true;
230     name = name.substr(1, name.size() - 1);
231   }
232 
233   ResourceNameRef ref;
234   ref.type = ResourceType::kStyle;
235 
236   StringPiece type_str;
237   android::ExtractResourceName(name, &ref.package, &type_str, &ref.entry);
238   if (!type_str.empty()) {
239     // If we have a type, make sure it is a Style.
240     const ResourceType* parsed_type = ParseResourceType(type_str);
241     if (!parsed_type || *parsed_type != ResourceType::kStyle) {
242       std::stringstream err;
243       err << "invalid resource type '" << type_str << "' for parent of style";
244       *out_error = err.str();
245       return {};
246     }
247   }
248 
249   if (!has_leading_identifiers && ref.package.empty() && !type_str.empty()) {
250     std::stringstream err;
251     err << "invalid parent reference '" << str << "'";
252     *out_error = err.str();
253     return {};
254   }
255 
256   Reference result(ref);
257   result.private_reference = private_ref;
258   return result;
259 }
260 
ParseXmlAttributeName(const StringPiece & str)261 Maybe<Reference> ParseXmlAttributeName(const StringPiece& str) {
262   StringPiece trimmed_str = util::TrimWhitespace(str);
263   const char* start = trimmed_str.data();
264   const char* const end = start + trimmed_str.size();
265   const char* p = start;
266 
267   Reference ref;
268   if (p != end && *p == '*') {
269     ref.private_reference = true;
270     start++;
271     p++;
272   }
273 
274   StringPiece package;
275   StringPiece name;
276   while (p != end) {
277     if (*p == ':') {
278       package = StringPiece(start, p - start);
279       name = StringPiece(p + 1, end - (p + 1));
280       break;
281     }
282     p++;
283   }
284 
285   ref.name = ResourceName(package, ResourceType::kAttr, name.empty() ? trimmed_str : name);
286   return Maybe<Reference>(std::move(ref));
287 }
288 
TryParseReference(const StringPiece & str,bool * out_create)289 std::unique_ptr<Reference> TryParseReference(const StringPiece& str,
290                                              bool* out_create) {
291   ResourceNameRef ref;
292   bool private_ref = false;
293   if (ParseReference(str, &ref, out_create, &private_ref)) {
294     std::unique_ptr<Reference> value = util::make_unique<Reference>(ref);
295     value->private_reference = private_ref;
296     return value;
297   }
298 
299   if (ParseAttributeReference(str, &ref)) {
300     if (out_create) {
301       *out_create = false;
302     }
303     return util::make_unique<Reference>(ref, Reference::Type::kAttribute);
304   }
305   return {};
306 }
307 
TryParseNullOrEmpty(const StringPiece & str)308 std::unique_ptr<Item> TryParseNullOrEmpty(const StringPiece& str) {
309   const StringPiece trimmed_str(util::TrimWhitespace(str));
310   if (trimmed_str == "@null") {
311     return MakeNull();
312   } else if (trimmed_str == "@empty") {
313     return MakeEmpty();
314   }
315   return {};
316 }
317 
MakeNull()318 std::unique_ptr<Reference> MakeNull() {
319   // TYPE_NULL with data set to 0 is interpreted by the runtime as an error.
320   // Instead we set the data type to TYPE_REFERENCE with a value of 0.
321   return util::make_unique<Reference>();
322 }
323 
MakeEmpty()324 std::unique_ptr<BinaryPrimitive> MakeEmpty() {
325   return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_NULL,
326                                             android::Res_value::DATA_NULL_EMPTY);
327 }
328 
TryParseEnumSymbol(const Attribute * enum_attr,const StringPiece & str)329 std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr,
330                                                     const StringPiece& str) {
331   StringPiece trimmed_str(util::TrimWhitespace(str));
332   for (const Attribute::Symbol& symbol : enum_attr->symbols) {
333     // Enum symbols are stored as @package:id/symbol resources,
334     // so we need to match against the 'entry' part of the identifier.
335     const ResourceName& enum_symbol_resource_name = symbol.symbol.name.value();
336     if (trimmed_str == enum_symbol_resource_name.entry) {
337       android::Res_value value = {};
338       value.dataType = android::Res_value::TYPE_INT_DEC;
339       value.data = symbol.value;
340       return util::make_unique<BinaryPrimitive>(value);
341     }
342   }
343   return {};
344 }
345 
TryParseFlagSymbol(const Attribute * flag_attr,const StringPiece & str)346 std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* flag_attr,
347                                                     const StringPiece& str) {
348   android::Res_value flags = {};
349   flags.dataType = android::Res_value::TYPE_INT_HEX;
350   flags.data = 0u;
351 
352   if (util::TrimWhitespace(str).empty()) {
353     // Empty string is a valid flag (0).
354     return util::make_unique<BinaryPrimitive>(flags);
355   }
356 
357   for (StringPiece part : util::Tokenize(str, '|')) {
358     StringPiece trimmed_part = util::TrimWhitespace(part);
359 
360     bool flag_set = false;
361     for (const Attribute::Symbol& symbol : flag_attr->symbols) {
362       // Flag symbols are stored as @package:id/symbol resources,
363       // so we need to match against the 'entry' part of the identifier.
364       const ResourceName& flag_symbol_resource_name =
365           symbol.symbol.name.value();
366       if (trimmed_part == flag_symbol_resource_name.entry) {
367         flags.data |= symbol.value;
368         flag_set = true;
369         break;
370       }
371     }
372 
373     if (!flag_set) {
374       return {};
375     }
376   }
377   return util::make_unique<BinaryPrimitive>(flags);
378 }
379 
ParseHex(char c,bool * out_error)380 static uint32_t ParseHex(char c, bool* out_error) {
381   if (c >= '0' && c <= '9') {
382     return c - '0';
383   } else if (c >= 'a' && c <= 'f') {
384     return c - 'a' + 0xa;
385   } else if (c >= 'A' && c <= 'F') {
386     return c - 'A' + 0xa;
387   } else {
388     *out_error = true;
389     return 0xffffffffu;
390   }
391 }
392 
TryParseColor(const StringPiece & str)393 std::unique_ptr<BinaryPrimitive> TryParseColor(const StringPiece& str) {
394   StringPiece color_str(util::TrimWhitespace(str));
395   const char* start = color_str.data();
396   const size_t len = color_str.size();
397   if (len == 0 || start[0] != '#') {
398     return {};
399   }
400 
401   android::Res_value value = {};
402   bool error = false;
403   if (len == 4) {
404     value.dataType = android::Res_value::TYPE_INT_COLOR_RGB4;
405     value.data = 0xff000000u;
406     value.data |= ParseHex(start[1], &error) << 20;
407     value.data |= ParseHex(start[1], &error) << 16;
408     value.data |= ParseHex(start[2], &error) << 12;
409     value.data |= ParseHex(start[2], &error) << 8;
410     value.data |= ParseHex(start[3], &error) << 4;
411     value.data |= ParseHex(start[3], &error);
412   } else if (len == 5) {
413     value.dataType = android::Res_value::TYPE_INT_COLOR_ARGB4;
414     value.data |= ParseHex(start[1], &error) << 28;
415     value.data |= ParseHex(start[1], &error) << 24;
416     value.data |= ParseHex(start[2], &error) << 20;
417     value.data |= ParseHex(start[2], &error) << 16;
418     value.data |= ParseHex(start[3], &error) << 12;
419     value.data |= ParseHex(start[3], &error) << 8;
420     value.data |= ParseHex(start[4], &error) << 4;
421     value.data |= ParseHex(start[4], &error);
422   } else if (len == 7) {
423     value.dataType = android::Res_value::TYPE_INT_COLOR_RGB8;
424     value.data = 0xff000000u;
425     value.data |= ParseHex(start[1], &error) << 20;
426     value.data |= ParseHex(start[2], &error) << 16;
427     value.data |= ParseHex(start[3], &error) << 12;
428     value.data |= ParseHex(start[4], &error) << 8;
429     value.data |= ParseHex(start[5], &error) << 4;
430     value.data |= ParseHex(start[6], &error);
431   } else if (len == 9) {
432     value.dataType = android::Res_value::TYPE_INT_COLOR_ARGB8;
433     value.data |= ParseHex(start[1], &error) << 28;
434     value.data |= ParseHex(start[2], &error) << 24;
435     value.data |= ParseHex(start[3], &error) << 20;
436     value.data |= ParseHex(start[4], &error) << 16;
437     value.data |= ParseHex(start[5], &error) << 12;
438     value.data |= ParseHex(start[6], &error) << 8;
439     value.data |= ParseHex(start[7], &error) << 4;
440     value.data |= ParseHex(start[8], &error);
441   } else {
442     return {};
443   }
444   return error ? std::unique_ptr<BinaryPrimitive>()
445                : util::make_unique<BinaryPrimitive>(value);
446 }
447 
ParseBool(const StringPiece & str)448 Maybe<bool> ParseBool(const StringPiece& str) {
449   StringPiece trimmed_str(util::TrimWhitespace(str));
450   if (trimmed_str == "true" || trimmed_str == "TRUE" || trimmed_str == "True") {
451     return Maybe<bool>(true);
452   } else if (trimmed_str == "false" || trimmed_str == "FALSE" ||
453              trimmed_str == "False") {
454     return Maybe<bool>(false);
455   }
456   return {};
457 }
458 
ParseInt(const StringPiece & str)459 Maybe<uint32_t> ParseInt(const StringPiece& str) {
460   std::u16string str16 = util::Utf8ToUtf16(str);
461   android::Res_value value;
462   if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
463     return value.data;
464   }
465   return {};
466 }
467 
ParseResourceId(const StringPiece & str)468 Maybe<ResourceId> ParseResourceId(const StringPiece& str) {
469   StringPiece trimmed_str(util::TrimWhitespace(str));
470 
471   std::u16string str16 = util::Utf8ToUtf16(trimmed_str);
472   android::Res_value value;
473   if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
474     if (value.dataType == android::Res_value::TYPE_INT_HEX) {
475       ResourceId id(value.data);
476       if (id.is_valid_dynamic()) {
477         return id;
478       }
479     }
480   }
481   return {};
482 }
483 
ParseSdkVersion(const StringPiece & str)484 Maybe<int> ParseSdkVersion(const StringPiece& str) {
485   StringPiece trimmed_str(util::TrimWhitespace(str));
486 
487   std::u16string str16 = util::Utf8ToUtf16(trimmed_str);
488   android::Res_value value;
489   if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
490     return static_cast<int>(value.data);
491   }
492 
493   // Try parsing the code name.
494   std::pair<StringPiece, int> entry = GetDevelopmentSdkCodeNameAndVersion();
495   if (entry.first == trimmed_str) {
496     return entry.second;
497   }
498   return {};
499 }
500 
TryParseBool(const StringPiece & str)501 std::unique_ptr<BinaryPrimitive> TryParseBool(const StringPiece& str) {
502   if (Maybe<bool> maybe_result = ParseBool(str)) {
503     const uint32_t data = maybe_result.value() ? 0xffffffffu : 0u;
504     return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, data);
505   }
506   return {};
507 }
508 
MakeBool(bool val)509 std::unique_ptr<BinaryPrimitive> MakeBool(bool val) {
510   return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN,
511                                             val ? 0xffffffffu : 0u);
512 }
513 
TryParseInt(const StringPiece & str)514 std::unique_ptr<BinaryPrimitive> TryParseInt(const StringPiece& str) {
515   std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str));
516   android::Res_value value;
517   if (!android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
518     return {};
519   }
520   return util::make_unique<BinaryPrimitive>(value);
521 }
522 
TryParseFloat(const StringPiece & str)523 std::unique_ptr<BinaryPrimitive> TryParseFloat(const StringPiece& str) {
524   std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str));
525   android::Res_value value;
526   if (!android::ResTable::stringToFloat(str16.data(), str16.size(), &value)) {
527     return {};
528   }
529   return util::make_unique<BinaryPrimitive>(value);
530 }
531 
AndroidTypeToAttributeTypeMask(uint16_t type)532 uint32_t AndroidTypeToAttributeTypeMask(uint16_t type) {
533   switch (type) {
534     case android::Res_value::TYPE_NULL:
535     case android::Res_value::TYPE_REFERENCE:
536     case android::Res_value::TYPE_ATTRIBUTE:
537     case android::Res_value::TYPE_DYNAMIC_REFERENCE:
538     case android::Res_value::TYPE_DYNAMIC_ATTRIBUTE:
539       return android::ResTable_map::TYPE_REFERENCE;
540 
541     case android::Res_value::TYPE_STRING:
542       return android::ResTable_map::TYPE_STRING;
543 
544     case android::Res_value::TYPE_FLOAT:
545       return android::ResTable_map::TYPE_FLOAT;
546 
547     case android::Res_value::TYPE_DIMENSION:
548       return android::ResTable_map::TYPE_DIMENSION;
549 
550     case android::Res_value::TYPE_FRACTION:
551       return android::ResTable_map::TYPE_FRACTION;
552 
553     case android::Res_value::TYPE_INT_DEC:
554     case android::Res_value::TYPE_INT_HEX:
555       return android::ResTable_map::TYPE_INTEGER |
556              android::ResTable_map::TYPE_ENUM |
557              android::ResTable_map::TYPE_FLAGS;
558 
559     case android::Res_value::TYPE_INT_BOOLEAN:
560       return android::ResTable_map::TYPE_BOOLEAN;
561 
562     case android::Res_value::TYPE_INT_COLOR_ARGB8:
563     case android::Res_value::TYPE_INT_COLOR_RGB8:
564     case android::Res_value::TYPE_INT_COLOR_ARGB4:
565     case android::Res_value::TYPE_INT_COLOR_RGB4:
566       return android::ResTable_map::TYPE_COLOR;
567 
568     default:
569       return 0;
570   };
571 }
572 
TryParseItemForAttribute(const StringPiece & value,uint32_t type_mask,const std::function<void (const ResourceName &)> & on_create_reference)573 std::unique_ptr<Item> TryParseItemForAttribute(
574     const StringPiece& value, uint32_t type_mask,
575     const std::function<void(const ResourceName&)>& on_create_reference) {
576   using android::ResTable_map;
577 
578   auto null_or_empty = TryParseNullOrEmpty(value);
579   if (null_or_empty) {
580     return null_or_empty;
581   }
582 
583   bool create = false;
584   auto reference = TryParseReference(value, &create);
585   if (reference) {
586     if (create && on_create_reference) {
587       on_create_reference(reference->name.value());
588     }
589     return std::move(reference);
590   }
591 
592   if (type_mask & ResTable_map::TYPE_COLOR) {
593     // Try parsing this as a color.
594     auto color = TryParseColor(value);
595     if (color) {
596       return std::move(color);
597     }
598   }
599 
600   if (type_mask & ResTable_map::TYPE_BOOLEAN) {
601     // Try parsing this as a boolean.
602     auto boolean = TryParseBool(value);
603     if (boolean) {
604       return std::move(boolean);
605     }
606   }
607 
608   if (type_mask & ResTable_map::TYPE_INTEGER) {
609     // Try parsing this as an integer.
610     auto integer = TryParseInt(value);
611     if (integer) {
612       return std::move(integer);
613     }
614   }
615 
616   const uint32_t float_mask =
617       ResTable_map::TYPE_FLOAT | ResTable_map::TYPE_DIMENSION | ResTable_map::TYPE_FRACTION;
618   if (type_mask & float_mask) {
619     // Try parsing this as a float.
620     auto floating_point = TryParseFloat(value);
621     if (floating_point) {
622       if (type_mask & AndroidTypeToAttributeTypeMask(floating_point->value.dataType)) {
623         return std::move(floating_point);
624       }
625     }
626   }
627   return {};
628 }
629 
630 /**
631  * We successively try to parse the string as a resource type that the Attribute
632  * allows.
633  */
TryParseItemForAttribute(const StringPiece & str,const Attribute * attr,const std::function<void (const ResourceName &)> & on_create_reference)634 std::unique_ptr<Item> TryParseItemForAttribute(
635     const StringPiece& str, const Attribute* attr,
636     const std::function<void(const ResourceName&)>& on_create_reference) {
637   using android::ResTable_map;
638 
639   const uint32_t type_mask = attr->type_mask;
640   auto value = TryParseItemForAttribute(str, type_mask, on_create_reference);
641   if (value) {
642     return value;
643   }
644 
645   if (type_mask & ResTable_map::TYPE_ENUM) {
646     // Try parsing this as an enum.
647     auto enum_value = TryParseEnumSymbol(attr, str);
648     if (enum_value) {
649       return std::move(enum_value);
650     }
651   }
652 
653   if (type_mask & ResTable_map::TYPE_FLAGS) {
654     // Try parsing this as a flag.
655     auto flag_value = TryParseFlagSymbol(attr, str);
656     if (flag_value) {
657       return std::move(flag_value);
658     }
659   }
660   return {};
661 }
662 
BuildResourceFileName(const ResourceFile & res_file,const NameMangler * mangler)663 std::string BuildResourceFileName(const ResourceFile& res_file, const NameMangler* mangler) {
664   std::stringstream out;
665   out << "res/" << res_file.name.type;
666   if (res_file.config != ConfigDescription{}) {
667     out << "-" << res_file.config;
668   }
669   out << "/";
670 
671   if (mangler && mangler->ShouldMangle(res_file.name.package)) {
672     out << NameMangler::MangleEntry(res_file.name.package, res_file.name.entry);
673   } else {
674     out << res_file.name.entry;
675   }
676   out << file::GetExtension(res_file.source.path);
677   return out.str();
678 }
679 
ParseBinaryResValue(const ResourceType & type,const ConfigDescription & config,const android::ResStringPool & src_pool,const android::Res_value & res_value,StringPool * dst_pool)680 std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const ConfigDescription& config,
681                                           const android::ResStringPool& src_pool,
682                                           const android::Res_value& res_value,
683                                           StringPool* dst_pool) {
684   if (type == ResourceType::kId) {
685     return util::make_unique<Id>();
686   }
687 
688   const uint32_t data = util::DeviceToHost32(res_value.data);
689   switch (res_value.dataType) {
690     case android::Res_value::TYPE_STRING: {
691       const std::string str = util::GetString(src_pool, data);
692       const android::ResStringPool_span* spans = src_pool.styleAt(data);
693 
694       // Check if the string has a valid style associated with it.
695       if (spans != nullptr && spans->name.index != android::ResStringPool_span::END) {
696         StyleString style_str = {str};
697         while (spans->name.index != android::ResStringPool_span::END) {
698           style_str.spans.push_back(Span{util::GetString(src_pool, spans->name.index),
699                                          spans->firstChar, spans->lastChar});
700           spans++;
701         }
702         return util::make_unique<StyledString>(dst_pool->MakeRef(
703             style_str, StringPool::Context(StringPool::Context::kNormalPriority, config)));
704       } else {
705         if (type != ResourceType::kString && util::StartsWith(str, "res/")) {
706           // This must be a FileReference.
707           return util::make_unique<FileReference>(dst_pool->MakeRef(
708               str, StringPool::Context(StringPool::Context::kHighPriority, config)));
709         }
710 
711         // There are no styles associated with this string, so treat it as a simple string.
712         return util::make_unique<String>(dst_pool->MakeRef(str, StringPool::Context(config)));
713       }
714     } break;
715 
716     case android::Res_value::TYPE_REFERENCE:
717     case android::Res_value::TYPE_ATTRIBUTE:
718     case android::Res_value::TYPE_DYNAMIC_REFERENCE:
719     case android::Res_value::TYPE_DYNAMIC_ATTRIBUTE: {
720       Reference::Type ref_type = Reference::Type::kResource;
721       if (res_value.dataType == android::Res_value::TYPE_ATTRIBUTE ||
722           res_value.dataType == android::Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
723         ref_type = Reference::Type::kAttribute;
724       }
725 
726       if (data == 0u) {
727         // A reference of 0, must be the magic @null reference.
728         return util::make_unique<Reference>();
729       }
730 
731       // This is a normal reference.
732       return util::make_unique<Reference>(data, ref_type);
733     } break;
734   }
735 
736   // Treat this as a raw binary primitive.
737   return util::make_unique<BinaryPrimitive>(res_value);
738 }
739 
740 }  // namespace ResourceUtils
741 }  // namespace aapt
742