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
27namespace aapt {
28
29template <typename Derived>
30void BaseValue<Derived>::accept(RawValueVisitor* visitor) {
31    visitor->visit(static_cast<Derived*>(this));
32}
33
34template <typename Derived>
35void BaseItem<Derived>::accept(RawValueVisitor* visitor) {
36    visitor->visit(static_cast<Derived*>(this));
37}
38
39RawString::RawString(const StringPool::Ref& ref) : value(ref) {
40}
41
42RawString* RawString::clone(StringPool* newPool) const {
43    RawString* rs = new RawString(newPool->makeRef(*value));
44    rs->mComment = mComment;
45    rs->mSource = mSource;
46    return rs;
47}
48
49bool RawString::flatten(android::Res_value* outValue) const {
50    outValue->dataType = android::Res_value::TYPE_STRING;
51    outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
52    return true;
53}
54
55void RawString::print(std::ostream* out) const {
56    *out << "(raw string) " << *value;
57}
58
59Reference::Reference() : referenceType(Reference::Type::kResource) {
60}
61
62Reference::Reference(const ResourceNameRef& n, Type t) :
63        name(n.toResourceName()), referenceType(t) {
64}
65
66Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
67}
68
69bool Reference::flatten(android::Res_value* outValue) const {
70    outValue->dataType = (referenceType == Reference::Type::kResource) ?
71            android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE;
72    outValue->data = util::hostToDevice32(id ? id.value().id : 0);
73    return true;
74}
75
76Reference* Reference::clone(StringPool* /*newPool*/) const {
77    return new Reference(*this);
78}
79
80void Reference::print(std::ostream* out) const {
81    *out << "(reference) ";
82    if (referenceType == Reference::Type::kResource) {
83        *out << "@";
84        if (privateReference) {
85            *out << "*";
86        }
87    } else {
88        *out << "?";
89    }
90
91    if (name) {
92        *out << name.value();
93    }
94
95    if (id && !Res_INTERNALID(id.value().id)) {
96        *out << " " << id.value();
97    }
98}
99
100bool Id::flatten(android::Res_value* out) const {
101    out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
102    out->data = util::hostToDevice32(0);
103    return true;
104}
105
106Id* Id::clone(StringPool* /*newPool*/) const {
107    return new Id(*this);
108}
109
110void Id::print(std::ostream* out) const {
111    *out << "(id)";
112}
113
114String::String(const StringPool::Ref& ref) : value(ref), mTranslateable(true) {
115}
116
117void String::setTranslateable(bool val) {
118    mTranslateable = val;
119}
120
121bool String::isTranslateable() const {
122    return mTranslateable;
123}
124
125bool String::flatten(android::Res_value* outValue) const {
126    // Verify that our StringPool index is within encode-able limits.
127    if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
128        return false;
129    }
130
131    outValue->dataType = android::Res_value::TYPE_STRING;
132    outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
133    return true;
134}
135
136String* String::clone(StringPool* newPool) const {
137    String* str = new String(newPool->makeRef(*value));
138    str->mComment = mComment;
139    str->mSource = mSource;
140    return str;
141}
142
143void String::print(std::ostream* out) const {
144    *out << "(string) \"" << *value << "\"";
145}
146
147StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref), mTranslateable(true) {
148}
149
150void StyledString::setTranslateable(bool val) {
151    mTranslateable = val;
152}
153
154bool StyledString::isTranslateable() const {
155    return mTranslateable;
156}
157
158bool StyledString::flatten(android::Res_value* outValue) const {
159    if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
160        return false;
161    }
162
163    outValue->dataType = android::Res_value::TYPE_STRING;
164    outValue->data = util::hostToDevice32(static_cast<uint32_t>(value.getIndex()));
165    return true;
166}
167
168StyledString* StyledString::clone(StringPool* newPool) const {
169    StyledString* str = new StyledString(newPool->makeRef(value));
170    str->mComment = mComment;
171    str->mSource = mSource;
172    return str;
173}
174
175void StyledString::print(std::ostream* out) const {
176    *out << "(styled string) \"" << *value->str << "\"";
177}
178
179FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
180}
181
182bool FileReference::flatten(android::Res_value* outValue) const {
183    if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
184        return false;
185    }
186
187    outValue->dataType = android::Res_value::TYPE_STRING;
188    outValue->data = util::hostToDevice32(static_cast<uint32_t>(path.getIndex()));
189    return true;
190}
191
192FileReference* FileReference::clone(StringPool* newPool) const {
193    FileReference* fr = new FileReference(newPool->makeRef(*path));
194    fr->file = file;
195    fr->mComment = mComment;
196    fr->mSource = mSource;
197    return fr;
198}
199
200void FileReference::print(std::ostream* out) const {
201    *out << "(file) " << *path;
202}
203
204BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
205}
206
207BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
208    value.dataType = dataType;
209    value.data = data;
210}
211
212bool BinaryPrimitive::flatten(android::Res_value* outValue) const {
213    outValue->dataType = value.dataType;
214    outValue->data = util::hostToDevice32(value.data);
215    return true;
216}
217
218BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const {
219    return new BinaryPrimitive(*this);
220}
221
222void BinaryPrimitive::print(std::ostream* out) const {
223    switch (value.dataType) {
224        case android::Res_value::TYPE_NULL:
225            *out << "(null)";
226            break;
227        case android::Res_value::TYPE_INT_DEC:
228            *out << "(integer) " << static_cast<int32_t>(value.data);
229            break;
230        case android::Res_value::TYPE_INT_HEX:
231            *out << "(integer) " << std::hex << value.data << std::dec;
232            break;
233        case android::Res_value::TYPE_INT_BOOLEAN:
234            *out << "(boolean) " << (value.data != 0 ? "true" : "false");
235            break;
236        case android::Res_value::TYPE_INT_COLOR_ARGB8:
237        case android::Res_value::TYPE_INT_COLOR_RGB8:
238        case android::Res_value::TYPE_INT_COLOR_ARGB4:
239        case android::Res_value::TYPE_INT_COLOR_RGB4:
240            *out << "(color) #" << std::hex << value.data << std::dec;
241            break;
242        default:
243            *out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x"
244                 << std::hex << value.data << std::dec;
245            break;
246    }
247}
248
249Attribute::Attribute(bool w, uint32_t t) :
250        typeMask(t),
251        minInt(std::numeric_limits<int32_t>::min()),
252        maxInt(std::numeric_limits<int32_t>::max()) {
253    mWeak = w;
254}
255
256Attribute* Attribute::clone(StringPool* /*newPool*/) const {
257    return new Attribute(*this);
258}
259
260void Attribute::printMask(std::ostream* out) const {
261    if (typeMask == android::ResTable_map::TYPE_ANY) {
262        *out << "any";
263        return;
264    }
265
266    bool set = false;
267    if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
268        if (!set) {
269            set = true;
270        } else {
271            *out << "|";
272        }
273        *out << "reference";
274    }
275
276    if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
277        if (!set) {
278            set = true;
279        } else {
280            *out << "|";
281        }
282        *out << "string";
283    }
284
285    if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
286        if (!set) {
287            set = true;
288        } else {
289            *out << "|";
290        }
291        *out << "integer";
292    }
293
294    if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
295        if (!set) {
296            set = true;
297        } else {
298            *out << "|";
299        }
300        *out << "boolean";
301    }
302
303    if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
304        if (!set) {
305            set = true;
306        } else {
307            *out << "|";
308        }
309        *out << "color";
310    }
311
312    if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
313        if (!set) {
314            set = true;
315        } else {
316            *out << "|";
317        }
318        *out << "float";
319    }
320
321    if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
322        if (!set) {
323            set = true;
324        } else {
325            *out << "|";
326        }
327        *out << "dimension";
328    }
329
330    if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
331        if (!set) {
332            set = true;
333        } else {
334            *out << "|";
335        }
336        *out << "fraction";
337    }
338
339    if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
340        if (!set) {
341            set = true;
342        } else {
343            *out << "|";
344        }
345        *out << "enum";
346    }
347
348    if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
349        if (!set) {
350            set = true;
351        } else {
352            *out << "|";
353        }
354        *out << "flags";
355    }
356}
357
358void Attribute::print(std::ostream* out) const {
359    *out << "(attr) ";
360    printMask(out);
361
362    if (!symbols.empty()) {
363        *out << " ["
364            << util::joiner(symbols.begin(), symbols.end(), ", ")
365            << "]";
366    }
367
368    if (isWeak()) {
369        *out << " [weak]";
370    }
371}
372
373static void buildAttributeMismatchMessage(DiagMessage* msg, const Attribute* attr,
374                                          const Item* value) {
375    *msg << "expected";
376    if (attr->typeMask & android::ResTable_map::TYPE_BOOLEAN) {
377        *msg << " boolean";
378    }
379
380    if (attr->typeMask & android::ResTable_map::TYPE_COLOR) {
381        *msg << " color";
382    }
383
384    if (attr->typeMask & android::ResTable_map::TYPE_DIMENSION) {
385        *msg << " dimension";
386    }
387
388    if (attr->typeMask & android::ResTable_map::TYPE_ENUM) {
389        *msg << " enum";
390    }
391
392    if (attr->typeMask & android::ResTable_map::TYPE_FLAGS) {
393        *msg << " flags";
394    }
395
396    if (attr->typeMask & android::ResTable_map::TYPE_FLOAT) {
397        *msg << " float";
398    }
399
400    if (attr->typeMask & android::ResTable_map::TYPE_FRACTION) {
401        *msg << " fraction";
402    }
403
404    if (attr->typeMask & android::ResTable_map::TYPE_INTEGER) {
405        *msg << " integer";
406    }
407
408    if (attr->typeMask & android::ResTable_map::TYPE_REFERENCE) {
409        *msg << " reference";
410    }
411
412    if (attr->typeMask & android::ResTable_map::TYPE_STRING) {
413        *msg << " string";
414    }
415
416    *msg << " but got " << *value;
417}
418
419bool Attribute::matches(const Item* item, DiagMessage* outMsg) const {
420    android::Res_value val = {};
421    item->flatten(&val);
422
423    // Always allow references.
424    const uint32_t mask = typeMask | android::ResTable_map::TYPE_REFERENCE;
425    if (!(mask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) {
426        if (outMsg) {
427            buildAttributeMismatchMessage(outMsg, this, item);
428        }
429        return false;
430
431    } else if (ResourceUtils::androidTypeToAttributeTypeMask(val.dataType) &
432            android::ResTable_map::TYPE_INTEGER) {
433        if (static_cast<int32_t>(util::deviceToHost32(val.data)) < minInt) {
434            if (outMsg) {
435                *outMsg << *item << " is less than minimum integer " << minInt;
436            }
437            return false;
438        } else if (static_cast<int32_t>(util::deviceToHost32(val.data)) > maxInt) {
439            if (outMsg) {
440                *outMsg << *item << " is greater than maximum integer " << maxInt;
441            }
442            return false;
443        }
444    }
445    return true;
446}
447
448Style* Style::clone(StringPool* newPool) const {
449    Style* style = new Style();
450    style->parent = parent;
451    style->parentInferred = parentInferred;
452    style->mComment = mComment;
453    style->mSource = mSource;
454    for (auto& entry : entries) {
455        style->entries.push_back(Entry{
456                entry.key,
457                std::unique_ptr<Item>(entry.value->clone(newPool))
458        });
459    }
460    return style;
461}
462
463void Style::print(std::ostream* out) const {
464    *out << "(style) ";
465    if (parent && parent.value().name) {
466        if (parent.value().privateReference) {
467            *out << "*";
468        }
469        *out << parent.value().name.value();
470    }
471    *out << " ["
472        << util::joiner(entries.begin(), entries.end(), ", ")
473        << "]";
474}
475
476static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
477    if (value.key.name) {
478        out << value.key.name.value();
479    } else {
480        out << "???";
481    }
482    out << " = ";
483    value.value->print(&out);
484    return out;
485}
486
487Array* Array::clone(StringPool* newPool) const {
488    Array* array = new Array();
489    array->mComment = mComment;
490    array->mSource = mSource;
491    for (auto& item : items) {
492        array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool)));
493    }
494    return array;
495}
496
497void Array::print(std::ostream* out) const {
498    *out << "(array) ["
499        << util::joiner(items.begin(), items.end(), ", ")
500        << "]";
501}
502
503Plural* Plural::clone(StringPool* newPool) const {
504    Plural* p = new Plural();
505    p->mComment = mComment;
506    p->mSource = mSource;
507    const size_t count = values.size();
508    for (size_t i = 0; i < count; i++) {
509        if (values[i]) {
510            p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool));
511        }
512    }
513    return p;
514}
515
516void Plural::print(std::ostream* out) const {
517    *out << "(plural)";
518}
519
520static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
521    return out << *item;
522}
523
524Styleable* Styleable::clone(StringPool* /*newPool*/) const {
525    return new Styleable(*this);
526}
527
528void Styleable::print(std::ostream* out) const {
529    *out << "(styleable) " << " ["
530        << util::joiner(entries.begin(), entries.end(), ", ")
531        << "]";
532}
533
534} // namespace aapt
535