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