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 "ResourceTypeExtensions.h"
19 #include "ResourceValues.h"
20 #include "Util.h"
21 
22 #include <androidfw/ResourceTypes.h>
23 #include <limits>
24 
25 namespace aapt {
26 
isItem() const27 bool Value::isItem() const {
28     return false;
29 }
30 
isWeak() const31 bool Value::isWeak() const {
32     return false;
33 }
34 
isItem() const35 bool Item::isItem() const {
36     return true;
37 }
38 
RawString(const StringPool::Ref & ref)39 RawString::RawString(const StringPool::Ref& ref) : value(ref) {
40 }
41 
clone(StringPool * newPool) const42 RawString* RawString::clone(StringPool* newPool) const {
43     return new RawString(newPool->makeRef(*value));
44 }
45 
flatten(android::Res_value & outValue) const46 bool RawString::flatten(android::Res_value& outValue) const {
47     outValue.dataType = ExtendedTypes::TYPE_RAW_STRING;
48     outValue.data = static_cast<uint32_t>(value.getIndex());
49     return true;
50 }
51 
print(std::ostream & out) const52 void RawString::print(std::ostream& out) const {
53     out << "(raw string) " << *value;
54 }
55 
Reference()56 Reference::Reference() : referenceType(Reference::Type::kResource) {
57 }
58 
Reference(const ResourceNameRef & n,Type t)59 Reference::Reference(const ResourceNameRef& n, Type t) :
60         name(n.toResourceName()), referenceType(t) {
61 }
62 
Reference(const ResourceId & i,Type type)63 Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
64 }
65 
flatten(android::Res_value & outValue) const66 bool Reference::flatten(android::Res_value& outValue) const {
67     outValue.dataType = (referenceType == Reference::Type::kResource)
68         ? android::Res_value::TYPE_REFERENCE
69         : android::Res_value::TYPE_ATTRIBUTE;
70     outValue.data = id.id;
71     return true;
72 }
73 
clone(StringPool *) const74 Reference* Reference::clone(StringPool* /*newPool*/) const {
75     Reference* ref = new Reference();
76     ref->referenceType = referenceType;
77     ref->name = name;
78     ref->id = id;
79     return ref;
80 }
81 
print(std::ostream & out) const82 void Reference::print(std::ostream& out) const {
83     out << "(reference) ";
84     if (referenceType == Reference::Type::kResource) {
85         out << "@";
86     } else {
87         out << "?";
88     }
89 
90     if (name.isValid()) {
91         out << name;
92     }
93 
94     if (id.isValid() || Res_INTERNALID(id.id)) {
95         out << " " << id;
96     }
97 }
98 
isWeak() const99 bool Id::isWeak() const {
100     return true;
101 }
102 
flatten(android::Res_value & out) const103 bool Id::flatten(android::Res_value& out) const {
104     out.dataType = android::Res_value::TYPE_INT_BOOLEAN;
105     out.data = 0;
106     return true;
107 }
108 
clone(StringPool *) const109 Id* Id::clone(StringPool* /*newPool*/) const {
110     return new Id();
111 }
112 
print(std::ostream & out) const113 void Id::print(std::ostream& out) const {
114     out << "(id)";
115 }
116 
String(const StringPool::Ref & ref)117 String::String(const StringPool::Ref& ref) : value(ref) {
118 }
119 
flatten(android::Res_value & outValue) const120 bool String::flatten(android::Res_value& outValue) const {
121     // Verify that our StringPool index is within encodeable limits.
122     if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
123         return false;
124     }
125 
126     outValue.dataType = android::Res_value::TYPE_STRING;
127     outValue.data = static_cast<uint32_t>(value.getIndex());
128     return true;
129 }
130 
clone(StringPool * newPool) const131 String* String::clone(StringPool* newPool) const {
132     return new String(newPool->makeRef(*value));
133 }
134 
print(std::ostream & out) const135 void String::print(std::ostream& out) const {
136     out << "(string) \"" << *value << "\"";
137 }
138 
StyledString(const StringPool::StyleRef & ref)139 StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
140 }
141 
flatten(android::Res_value & outValue) const142 bool StyledString::flatten(android::Res_value& outValue) const {
143     if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
144         return false;
145     }
146 
147     outValue.dataType = android::Res_value::TYPE_STRING;
148     outValue.data = static_cast<uint32_t>(value.getIndex());
149     return true;
150 }
151 
clone(StringPool * newPool) const152 StyledString* StyledString::clone(StringPool* newPool) const {
153     return new StyledString(newPool->makeRef(value));
154 }
155 
print(std::ostream & out) const156 void StyledString::print(std::ostream& out) const {
157     out << "(styled string) \"" << *value->str << "\"";
158 }
159 
FileReference(const StringPool::Ref & _path)160 FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
161 }
162 
flatten(android::Res_value & outValue) const163 bool FileReference::flatten(android::Res_value& outValue) const {
164     if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
165         return false;
166     }
167 
168     outValue.dataType = android::Res_value::TYPE_STRING;
169     outValue.data = static_cast<uint32_t>(path.getIndex());
170     return true;
171 }
172 
clone(StringPool * newPool) const173 FileReference* FileReference::clone(StringPool* newPool) const {
174     return new FileReference(newPool->makeRef(*path));
175 }
176 
print(std::ostream & out) const177 void FileReference::print(std::ostream& out) const {
178     out << "(file) " << *path;
179 }
180 
BinaryPrimitive(const android::Res_value & val)181 BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
182 }
183 
flatten(android::Res_value & outValue) const184 bool BinaryPrimitive::flatten(android::Res_value& outValue) const {
185     outValue = value;
186     return true;
187 }
188 
clone(StringPool *) const189 BinaryPrimitive* BinaryPrimitive::clone(StringPool* /*newPool*/) const {
190     return new BinaryPrimitive(value);
191 }
192 
print(std::ostream & out) const193 void BinaryPrimitive::print(std::ostream& out) const {
194     switch (value.dataType) {
195         case android::Res_value::TYPE_NULL:
196             out << "(null)";
197             break;
198         case android::Res_value::TYPE_INT_DEC:
199             out << "(integer) " << value.data;
200             break;
201         case android::Res_value::TYPE_INT_HEX:
202             out << "(integer) " << std::hex << value.data << std::dec;
203             break;
204         case android::Res_value::TYPE_INT_BOOLEAN:
205             out << "(boolean) " << (value.data != 0 ? "true" : "false");
206             break;
207         case android::Res_value::TYPE_INT_COLOR_ARGB8:
208         case android::Res_value::TYPE_INT_COLOR_RGB8:
209         case android::Res_value::TYPE_INT_COLOR_ARGB4:
210         case android::Res_value::TYPE_INT_COLOR_RGB4:
211             out << "(color) #" << std::hex << value.data << std::dec;
212             break;
213         default:
214             out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x"
215                 << std::hex << value.data << std::dec;
216             break;
217     }
218 }
219 
Attribute(bool w,uint32_t t)220 Attribute::Attribute(bool w, uint32_t t) : weak(w), typeMask(t) {
221 }
222 
isWeak() const223 bool Attribute::isWeak() const {
224     return weak;
225 }
226 
clone(StringPool *) const227 Attribute* Attribute::clone(StringPool* /*newPool*/) const {
228     Attribute* attr = new Attribute(weak);
229     attr->typeMask = typeMask;
230     std::copy(symbols.begin(), symbols.end(), std::back_inserter(attr->symbols));
231     return attr;
232 }
233 
printMask(std::ostream & out) const234 void Attribute::printMask(std::ostream& out) const {
235     if (typeMask == android::ResTable_map::TYPE_ANY) {
236         out << "any";
237         return;
238     }
239 
240     bool set = false;
241     if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
242         if (!set) {
243             set = true;
244         } else {
245             out << "|";
246         }
247         out << "reference";
248     }
249 
250     if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
251         if (!set) {
252             set = true;
253         } else {
254             out << "|";
255         }
256         out << "string";
257     }
258 
259     if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
260         if (!set) {
261             set = true;
262         } else {
263             out << "|";
264         }
265         out << "integer";
266     }
267 
268     if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
269         if (!set) {
270             set = true;
271         } else {
272             out << "|";
273         }
274         out << "boolean";
275     }
276 
277     if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
278         if (!set) {
279             set = true;
280         } else {
281             out << "|";
282         }
283         out << "color";
284     }
285 
286     if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
287         if (!set) {
288             set = true;
289         } else {
290             out << "|";
291         }
292         out << "float";
293     }
294 
295     if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
296         if (!set) {
297             set = true;
298         } else {
299             out << "|";
300         }
301         out << "dimension";
302     }
303 
304     if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
305         if (!set) {
306             set = true;
307         } else {
308             out << "|";
309         }
310         out << "fraction";
311     }
312 
313     if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
314         if (!set) {
315             set = true;
316         } else {
317             out << "|";
318         }
319         out << "enum";
320     }
321 
322     if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
323         if (!set) {
324             set = true;
325         } else {
326             out << "|";
327         }
328         out << "flags";
329     }
330 }
331 
print(std::ostream & out) const332 void Attribute::print(std::ostream& out) const {
333     out << "(attr) ";
334     printMask(out);
335 
336     out << " ["
337         << util::joiner(symbols.begin(), symbols.end(), ", ")
338         << "]";
339 
340     if (weak) {
341         out << " [weak]";
342     }
343 }
344 
clone(StringPool * newPool) const345 Style* Style::clone(StringPool* newPool) const {
346     Style* style = new Style();
347     style->parent = parent;
348     style->parentInferred = parentInferred;
349     for (auto& entry : entries) {
350         style->entries.push_back(Entry{
351                 entry.key,
352                 std::unique_ptr<Item>(entry.value->clone(newPool))
353         });
354     }
355     return style;
356 }
357 
print(std::ostream & out) const358 void Style::print(std::ostream& out) const {
359     out << "(style) ";
360     if (!parent.name.entry.empty()) {
361         out << parent.name;
362     }
363     out << " ["
364         << util::joiner(entries.begin(), entries.end(), ", ")
365         << "]";
366 }
367 
operator <<(::std::ostream & out,const Style::Entry & value)368 static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
369     out << value.key.name << " = ";
370     value.value->print(out);
371     return out;
372 }
373 
clone(StringPool * newPool) const374 Array* Array::clone(StringPool* newPool) const {
375     Array* array = new Array();
376     for (auto& item : items) {
377         array->items.emplace_back(std::unique_ptr<Item>(item->clone(newPool)));
378     }
379     return array;
380 }
381 
print(std::ostream & out) const382 void Array::print(std::ostream& out) const {
383     out << "(array) ["
384         << util::joiner(items.begin(), items.end(), ", ")
385         << "]";
386 }
387 
clone(StringPool * newPool) const388 Plural* Plural::clone(StringPool* newPool) const {
389     Plural* p = new Plural();
390     const size_t count = values.size();
391     for (size_t i = 0; i < count; i++) {
392         if (values[i]) {
393             p->values[i] = std::unique_ptr<Item>(values[i]->clone(newPool));
394         }
395     }
396     return p;
397 }
398 
print(std::ostream & out) const399 void Plural::print(std::ostream& out) const {
400     out << "(plural)";
401 }
402 
operator <<(::std::ostream & out,const std::unique_ptr<Item> & item)403 static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
404     return out << *item;
405 }
406 
clone(StringPool *) const407 Styleable* Styleable::clone(StringPool* /*newPool*/) const {
408     Styleable* styleable = new Styleable();
409     std::copy(entries.begin(), entries.end(), std::back_inserter(styleable->entries));
410     return styleable;
411 }
412 
print(std::ostream & out) const413 void Styleable::print(std::ostream& out) const {
414     out << "(styleable) " << " ["
415         << util::joiner(entries.begin(), entries.end(), ", ")
416         << "]";
417 }
418 
419 } // namespace aapt
420