• 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 "Resource.h"
18 #include "ResourceUtils.h"
19 #include "ResourceValues.h"
20 #include "ValueVisitor.h"
21 #include "io/File.h"
22 #include "util/Util.h"
23 
24 #include <androidfw/ResourceTypes.h>
25 #include <limits>
26 
27 namespace aapt {
28 
29 template <typename Derived>
accept(RawValueVisitor * visitor)30 void BaseValue<Derived>::accept(RawValueVisitor* visitor) {
31     visitor->visit(static_cast<Derived*>(this));
32 }
33 
34 template <typename Derived>
accept(RawValueVisitor * visitor)35 void BaseItem<Derived>::accept(RawValueVisitor* visitor) {
36     visitor->visit(static_cast<Derived*>(this));
37 }
38 
RawString(const StringPool::Ref & ref)39 RawString::RawString(const StringPool::Ref& ref) : value(ref) {
40 }
41 
equals(const Value * value) const42 bool RawString::equals(const Value* value) const {
43     const RawString* other = valueCast<RawString>(value);
44     if (!other) {
45         return false;
46     }
47     return *this->value == *other->value;
48 }
49 
clone(StringPool * newPool) const50 RawString* RawString::clone(StringPool* newPool) const {
51     RawString* rs = new RawString(newPool->makeRef(*value));
52     rs->mComment = mComment;
53     rs->mSource = mSource;
54     return rs;
55 }
56 
flatten(android::Res_value * outValue) const57 bool RawString::flatten(android::Res_value* outValue) const {
58     outValue->dataType = android::Res_value::TYPE_STRING;
59     outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
60     return true;
61 }
62 
print(std::ostream * out) const63 void RawString::print(std::ostream* out) const {
64     *out << "(raw string) " << *value;
65 }
66 
Reference()67 Reference::Reference() : referenceType(Reference::Type::kResource) {
68 }
69 
Reference(const ResourceNameRef & n,Type t)70 Reference::Reference(const ResourceNameRef& n, Type t) :
71         name(n.toResourceName()), referenceType(t) {
72 }
73 
Reference(const ResourceId & i,Type type)74 Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
75 }
76 
equals(const Value * value) const77 bool Reference::equals(const Value* value) const {
78     const Reference* other = valueCast<Reference>(value);
79     if (!other) {
80         return false;
81     }
82     return referenceType == other->referenceType && privateReference == other->privateReference &&
83             id == other->id && name == other->name;
84 }
85 
flatten(android::Res_value * outValue) const86 bool Reference::flatten(android::Res_value* outValue) const {
87     outValue->dataType = (referenceType == Reference::Type::kResource) ?
88             android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE;
89     outValue->data = util::hostToDevice32(id ? id.value().id : 0);
90     return true;
91 }
92 
clone(StringPool *) const93 Reference* Reference::clone(StringPool* /*newPool*/) const {
94     return new Reference(*this);
95 }
96 
print(std::ostream * out) const97 void Reference::print(std::ostream* out) const {
98     *out << "(reference) ";
99     if (referenceType == Reference::Type::kResource) {
100         *out << "@";
101         if (privateReference) {
102             *out << "*";
103         }
104     } else {
105         *out << "?";
106     }
107 
108     if (name) {
109         *out << name.value();
110     }
111 
112     if (id && !Res_INTERNALID(id.value().id)) {
113         *out << " " << id.value();
114     }
115 }
116 
equals(const Value * value) const117 bool Id::equals(const Value* value) const {
118     return valueCast<Id>(value) != nullptr;
119 }
120 
flatten(android::Res_value * out) const121 bool Id::flatten(android::Res_value* out) const {
122     out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
123     out->data = util::hostToDevice32(0);
124     return true;
125 }
126 
clone(StringPool *) const127 Id* Id::clone(StringPool* /*newPool*/) const {
128     return new Id(*this);
129 }
130 
print(std::ostream * out) const131 void Id::print(std::ostream* out) const {
132     *out << "(id)";
133 }
134 
String(const StringPool::Ref & ref)135 String::String(const StringPool::Ref& ref) : value(ref) {
136 }
137 
equals(const Value * value) const138 bool String::equals(const Value* value) const {
139     const String* other = valueCast<String>(value);
140     if (!other) {
141         return false;
142     }
143     return *this->value == *other->value;
144 }
145 
flatten(android::Res_value * outValue) const146 bool String::flatten(android::Res_value* outValue) const {
147     // Verify that our StringPool index is within encode-able limits.
148     if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
149         return false;
150     }
151 
152     outValue->dataType = android::Res_value::TYPE_STRING;
153     outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
154     return true;
155 }
156 
clone(StringPool * newPool) const157 String* String::clone(StringPool* newPool) const {
158     String* str = new String(newPool->makeRef(*value));
159     str->mComment = mComment;
160     str->mSource = mSource;
161     return str;
162 }
163 
print(std::ostream * out) const164 void String::print(std::ostream* out) const {
165     *out << "(string) \"" << *value << "\"";
166 }
167 
StyledString(const StringPool::StyleRef & ref)168 StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
169 }
170 
equals(const Value * value) const171 bool StyledString::equals(const Value* value) const {
172     const StyledString* other = valueCast<StyledString>(value);
173     if (!other) {
174         return false;
175     }
176 
177     if (*this->value->str == *other->value->str) {
178         const std::vector<StringPool::Span>& spansA = this->value->spans;
179         const std::vector<StringPool::Span>& spansB = other->value->spans;
180         return std::equal(spansA.begin(), spansA.end(), spansB.begin(),
181                           [](const StringPool::Span& a, const StringPool::Span& b) -> bool {
182             return *a.name == *b.name && a.firstChar == b.firstChar && a.lastChar == b.lastChar;
183         });
184     }
185     return false;
186 }
187 
flatten(android::Res_value * outValue) const188 bool StyledString::flatten(android::Res_value* outValue) const {
189     if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
190         return false;
191     }
192 
193     outValue->dataType = android::Res_value::TYPE_STRING;
194     outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
195     return true;
196 }
197 
clone(StringPool * newPool) const198 StyledString* StyledString::clone(StringPool* newPool) const {
199     StyledString* str = new StyledString(newPool->makeRef(value));
200     str->mComment = mComment;
201     str->mSource = mSource;
202     return str;
203 }
204 
print(std::ostream * out) const205 void StyledString::print(std::ostream* out) const {
206     *out << "(styled string) \"" << *value->str << "\"";
207     for (const StringPool::Span& span : value->spans) {
208         *out << " "<< *span.name << ":" << span.firstChar << "," << span.lastChar;
209     }
210 }
211 
FileReference(const StringPool::Ref & _path)212 FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
213 }
214 
equals(const Value * value) const215 bool FileReference::equals(const Value* value) const {
216     const FileReference* other = valueCast<FileReference>(value);
217     if (!other) {
218         return false;
219     }
220     return *path == *other->path;
221 }
222 
flatten(android::Res_value * outValue) const223 bool FileReference::flatten(android::Res_value* outValue) const {
224     if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
225         return false;
226     }
227 
228     outValue->dataType = android::Res_value::TYPE_STRING;
229     outValue->data = util::hostToDevice32(static_cast<uint32_t>(path.getIndex()));
230     return true;
231 }
232 
clone(StringPool * newPool) const233 FileReference* FileReference::clone(StringPool* newPool) const {
234     FileReference* fr = new FileReference(newPool->makeRef(*path));
235     fr->file = file;
236     fr->mComment = mComment;
237     fr->mSource = mSource;
238     return fr;
239 }
240 
print(std::ostream * out) const241 void FileReference::print(std::ostream* out) const {
242     *out << "(file) " << *path;
243 }
244 
BinaryPrimitive(const android::Res_value & val)245 BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
246 }
247 
BinaryPrimitive(uint8_t dataType,uint32_t data)248 BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
249     value.dataType = dataType;
250     value.data = data;
251 }
252 
equals(const Value * value) const253 bool BinaryPrimitive::equals(const Value* value) const {
254     const BinaryPrimitive* other = valueCast<BinaryPrimitive>(value);
255     if (!other) {
256         return false;
257     }
258     return this->value.dataType == other->value.dataType && this->value.data == other->value.data;
259 }
260 
flatten(android::Res_value * outValue) const261 bool BinaryPrimitive::flatten(android::Res_value* outValue) const {
262     outValue->dataType = value.dataType;
263     outValue->data = util::hostToDevice32(value.data);
264     return true;
265 }
266 
clone(StringPool *) const267 BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const {
268     return new BinaryPrimitive(*this);
269 }
270 
print(std::ostream * out) const271 void BinaryPrimitive::print(std::ostream* out) const {
272     switch (value.dataType) {
273         case android::Res_value::TYPE_NULL:
274             *out << "(null)";
275             break;
276         case android::Res_value::TYPE_INT_DEC:
277             *out << "(integer) " << static_cast<int32_t>(value.data);
278             break;
279         case android::Res_value::TYPE_INT_HEX:
280             *out << "(integer) 0x" << std::hex << value.data << std::dec;
281             break;
282         case android::Res_value::TYPE_INT_BOOLEAN:
283             *out << "(boolean) " << (value.data != 0 ? "true" : "false");
284             break;
285         case android::Res_value::TYPE_INT_COLOR_ARGB8:
286         case android::Res_value::TYPE_INT_COLOR_RGB8:
287         case android::Res_value::TYPE_INT_COLOR_ARGB4:
288         case android::Res_value::TYPE_INT_COLOR_RGB4:
289             *out << "(color) #" << std::hex << value.data << std::dec;
290             break;
291         default:
292             *out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x"
293                  << std::hex << value.data << std::dec;
294             break;
295     }
296 }
297 
Attribute(bool w,uint32_t t)298 Attribute::Attribute(bool w, uint32_t t) :
299         typeMask(t),
300         minInt(std::numeric_limits<int32_t>::min()),
301         maxInt(std::numeric_limits<int32_t>::max()) {
302     mWeak = w;
303 }
304 
equals(const Value * value) const305 bool Attribute::equals(const Value* value) const {
306     const Attribute* other = valueCast<Attribute>(value);
307     if (!other) {
308         return false;
309     }
310 
311     return this->typeMask == other->typeMask && this->minInt == other->minInt &&
312             this->maxInt == other->maxInt &&
313             std::equal(this->symbols.begin(), this->symbols.end(),
314                        other->symbols.begin(),
315                        [](const Symbol& a, const Symbol& b) -> bool {
316         return a.symbol.equals(&b.symbol) && a.value == b.value;
317     });
318 }
319 
clone(StringPool *) const320 Attribute* Attribute::clone(StringPool* /*newPool*/) const {
321     return new Attribute(*this);
322 }
323 
printMask(std::ostream * out) const324 void Attribute::printMask(std::ostream* out) const {
325     if (typeMask == android::ResTable_map::TYPE_ANY) {
326         *out << "any";
327         return;
328     }
329 
330     bool set = false;
331     if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
332         if (!set) {
333             set = true;
334         } else {
335             *out << "|";
336         }
337         *out << "reference";
338     }
339 
340     if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
341         if (!set) {
342             set = true;
343         } else {
344             *out << "|";
345         }
346         *out << "string";
347     }
348 
349     if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
350         if (!set) {
351             set = true;
352         } else {
353             *out << "|";
354         }
355         *out << "integer";
356     }
357 
358     if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
359         if (!set) {
360             set = true;
361         } else {
362             *out << "|";
363         }
364         *out << "boolean";
365     }
366 
367     if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
368         if (!set) {
369             set = true;
370         } else {
371             *out << "|";
372         }
373         *out << "color";
374     }
375 
376     if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
377         if (!set) {
378             set = true;
379         } else {
380             *out << "|";
381         }
382         *out << "float";
383     }
384 
385     if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
386         if (!set) {
387             set = true;
388         } else {
389             *out << "|";
390         }
391         *out << "dimension";
392     }
393 
394     if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
395         if (!set) {
396             set = true;
397         } else {
398             *out << "|";
399         }
400         *out << "fraction";
401     }
402 
403     if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
404         if (!set) {
405             set = true;
406         } else {
407             *out << "|";
408         }
409         *out << "enum";
410     }
411 
412     if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
413         if (!set) {
414             set = true;
415         } else {
416             *out << "|";
417         }
418         *out << "flags";
419     }
420 }
421 
print(std::ostream * out) const422 void Attribute::print(std::ostream* out) const {
423     *out << "(attr) ";
424     printMask(out);
425 
426     if (!symbols.empty()) {
427         *out << " ["
428             << util::joiner(symbols.begin(), symbols.end(), ", ")
429             << "]";
430     }
431 
432     if (minInt != std::numeric_limits<int32_t>::min()) {
433         *out << " min=" << minInt;
434     }
435 
436     if (maxInt != std::numeric_limits<int32_t>::max()) {
437         *out << " max=" << maxInt;
438     }
439 
440     if (isWeak()) {
441         *out << " [weak]";
442     }
443 }
444 
buildAttributeMismatchMessage(DiagMessage * msg,const Attribute * attr,const Item * value)445 static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr,
446                                           const Item* value) {
447     *msg << "expected";
448     if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) {
449         *msg << " boolean";
450     }
451 
452     if (attr->typeMask & android::ResTable_map::TYPE_COLOR) {
453         *msg << " color";
454     }
455 
456     if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) {
457         *msg << " dimension";
458     }
459 
460     if (attr->typeMask & android::ResTable_map::TYPE_ENUM) {
461         *msg << " enum";
462     }
463 
464     if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) {
465         *msg << " flags";
466     }
467 
468     if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) {
469         *msg << " float";
470     }
471 
472     if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) {
473         *msg << " fraction";
474     }
475 
476     if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) {
477         *msg << " integer";
478     }
479 
480     if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) {
481         *msg << " reference";
482     }
483 
484     if (attr->typeMask & android::ResTable_map::TYPE_STRING) {
485         *msg << " string";
486     }
487 
488     *msg << " but got " << *value;
489 }
490 
matches(const Item * item,DiagMessage * outMsg) const491 bool Attribute::matches(const Item* item, DiagMessage* outMsg) const {
492     android::Res_value val = {};
493     item->flatten(&val);
494 
495     // Always allow references.
496     const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE;
497     if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) {
498         if (outMsg) {
499             buildAttributeMismatchMessage(outMsg, this, item);
500         }
501         return false;
502 
503     } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) &
504             android::ResTable_map::TYPE_INTEGER) {
505         if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) {
506             if (outMsg) {
507                 *outMsg << *item << " is less than minimum integer " << minInt;
508             }
509             return false;
510         } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) {
511             if (outMsg) {
512                 *outMsg << *item << " is greater than maximum integer " << maxInt;
513             }
514             return false;
515         }
516     }
517     return true;
518 }
519 
equals(const Value * value) const520 bool Style::equals(const Value* value) const {
521     const Style* other = valueCast<Style>(value);
522     if (!other) {
523         return false;
524     }
525     if (bool(parent) != bool(other->parent) ||
526             (parent && other->parent && !parent.value().equals(&other->parent.value()))) {
527         return false;
528     }
529     return std::equal(entries.begin(), entries.end(), other->entries.begin(),
530                       [](const Entry& a, const Entry& b) -> bool {
531         return a.key.equals(&b.key) && a.value->equals(b.value.get());
532     });
533 }
534 
clone(StringPool * newPool) const535 Style* Style::clone(StringPool* newPool) const {
536     Style* style = new Style();
537     style->parent = parent;
538     style->parentInferred = parentInferred;
539     style->mComment = mComment;
540     style->mSource = mSource;
541     for (auto& entry : entries) {
542         style->entries.push_back(Entry{
543                 entry.key,
544                 std::unique_ptr<Item>(entry.value->clone(newPool))
545         });
546     }
547     return style;
548 }
549 
print(std::ostream * out) const550 void Style::print(std::ostream* out) const {
551     *out << "(style) ";
552     if (parent && parent.value().name) {
553         if (parent.value().privateReference) {
554             *out << "*";
555         }
556         *out << parent.value().name.value();
557     }
558     *out << " ["
559         << util::joiner(entries.begin(), entries.end(), ", ")
560         << "]";
561 }
562 
operator <<(::std::ostream & out,const Style::Entry & value)563 static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
564     if (value.key.name) {
565         out << value.key.name.value();
566     } else {
567         out << "???";
568     }
569     out << " = ";
570     value.value->print(&out);
571     return out;
572 }
573 
equals(const Value * value) const574 bool Array::equals(const Value* value) const {
575     const Array* other = valueCast<Array>(value);
576     if (!other) {
577         return false;
578     }
579 
580     return std::equal(items.begin(), items.end(), other->items.begin(),
581                       [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
582         return a->equals(b.get());
583     });
584 }
585 
clone(StringPool * newPool) const586 Array* Array::clone(StringPool* newPool) const {
587     Array* array = new Array();
588     array->mComment = mComment;
589     array->mSource = mSource;
590     for (auto& item : items) {
591         array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool)));
592     }
593     return array;
594 }
595 
print(std::ostream * out) const596 void Array::print(std::ostream* out) const {
597     *out << "(array) ["
598         << util::joiner(items.begin(), items.end(), ", ")
599         << "]";
600 }
601 
equals(const Value * value) const602 bool Plural::equals(const Value* value) const {
603     const Plural* other = valueCast<Plural>(value);
604     if (!other) {
605         return false;
606     }
607 
608     return std::equal(values.begin(), values.end(), other->values.begin(),
609                       [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
610         if (bool(a) != bool(b)) {
611             return false;
612         }
613         return bool(a) == bool(b) || a->equals(b.get());
614     });
615 }
616 
clone(StringPool * newPool) const617 Plural* Plural::clone(StringPool* newPool) const {
618     Plural* p = new Plural();
619     p->mComment = mComment;
620     p->mSource = mSource;
621     const size_t count = values.size();
622     for (size_t i = 0; i < count; i++) {
623         if (values[i]) {
624             p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool));
625         }
626     }
627     return p;
628 }
629 
print(std::ostream * out) const630 void Plural::print(std::ostream* out) const {
631     *out << "(plural)";
632     if (values[Zero]) {
633         *out << " zero=" << *values[Zero];
634     }
635 
636     if (values[One]) {
637         *out << " one=" << *values[One];
638     }
639 
640     if (values[Two]) {
641         *out << " two=" << *values[Two];
642     }
643 
644     if (values[Few]) {
645         *out << " few=" << *values[Few];
646     }
647 
648     if (values[Many]) {
649         *out << " many=" << *values[Many];
650     }
651 }
652 
operator <<(::std::ostream & out,const std::unique_ptr<Item> & item)653 static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
654     return out << *item;
655 }
656 
equals(const Value * value) const657 bool Styleable::equals(const Value* value) const {
658     const Styleable* other = valueCast<Styleable>(value);
659     if (!other) {
660         return false;
661     }
662     return std::equal(entries.begin(), entries.end(), other->entries.begin(),
663                       [](const Reference& a, const Reference& b) -> bool {
664         return a.equals(&b);
665     });
666 }
667 
clone(StringPool *) const668 Styleable* Styleable::clone(StringPool* /*newPool*/) const {
669     return new Styleable(*this);
670 }
671 
print(std::ostream * out) const672 void Styleable::print(std::ostream* out) const {
673     *out << "(styleable) " << " ["
674         << util::joiner(entries.begin(), entries.end(), ", ")
675         << "]";
676 }
677 
678 } // namespace aapt
679