blob: 546b6078ddb0e04a711f27dc79ea8d22a0bca34d [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
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
Adam Lesinskib54ef102016-10-21 13:38:42 -070017#include "unflatten/BinaryResourceParser.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070018#include "ResourceTable.h"
19#include "ResourceUtils.h"
20#include "ResourceValues.h"
21#include "Source.h"
22#include "ValueVisitor.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070023#include "unflatten/ResChunkPullParser.h"
24#include "util/Util.h"
25
Adam Lesinskib54ef102016-10-21 13:38:42 -070026#include <android-base/macros.h>
Adam Lesinski1ab598f2015-08-14 14:26:04 -070027#include <androidfw/ResourceTypes.h>
28#include <androidfw/TypeWrappers.h>
Adam Lesinski803c7c82016-04-06 16:09:43 -070029#include <algorithm>
Adam Lesinski1ab598f2015-08-14 14:26:04 -070030#include <map>
31#include <string>
32
33namespace aapt {
34
35using namespace android;
36
Adam Lesinski59e04c62016-02-04 15:59:23 -080037namespace {
38
Adam Lesinski1ab598f2015-08-14 14:26:04 -070039/*
40 * Visitor that converts a reference's resource ID to a resource name,
41 * given a mapping from resource ID to resource name.
42 */
43class ReferenceIdToNameVisitor : public ValueVisitor {
Adam Lesinskib54ef102016-10-21 13:38:42 -070044 private:
45 const std::map<ResourceId, ResourceName>* mMapping;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070046
Adam Lesinskib54ef102016-10-21 13:38:42 -070047 public:
48 using ValueVisitor::visit;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070049
Adam Lesinskib54ef102016-10-21 13:38:42 -070050 explicit ReferenceIdToNameVisitor(
51 const std::map<ResourceId, ResourceName>* mapping)
52 : mMapping(mapping) {
53 assert(mMapping);
54 }
55
56 void visit(Reference* reference) override {
57 if (!reference->id || !reference->id.value().isValid()) {
58 return;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070059 }
60
Adam Lesinskib54ef102016-10-21 13:38:42 -070061 ResourceId id = reference->id.value();
62 auto cacheIter = mMapping->find(id);
63 if (cacheIter != mMapping->end()) {
64 reference->name = cacheIter->second;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070065 }
Adam Lesinskib54ef102016-10-21 13:38:42 -070066 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070067};
68
Adam Lesinskib54ef102016-10-21 13:38:42 -070069} // namespace
Adam Lesinski59e04c62016-02-04 15:59:23 -080070
Adam Lesinskib54ef102016-10-21 13:38:42 -070071BinaryResourceParser::BinaryResourceParser(IAaptContext* context,
72 ResourceTable* table,
73 const Source& source,
74 const void* data, size_t len)
75 : mContext(context),
76 mTable(table),
77 mSource(source),
78 mData(data),
79 mDataLen(len) {}
Adam Lesinski1ab598f2015-08-14 14:26:04 -070080
81bool BinaryResourceParser::parse() {
Adam Lesinskib54ef102016-10-21 13:38:42 -070082 ResChunkPullParser parser(mData, mDataLen);
Adam Lesinski1ab598f2015-08-14 14:26:04 -070083
Adam Lesinskib54ef102016-10-21 13:38:42 -070084 bool error = false;
85 while (ResChunkPullParser::isGoodEvent(parser.next())) {
86 if (parser.getChunk()->type != android::RES_TABLE_TYPE) {
87 mContext->getDiagnostics()->warn(DiagMessage(mSource)
88 << "unknown chunk of type '"
89 << (int)parser.getChunk()->type << "'");
90 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070091 }
92
Adam Lesinskib54ef102016-10-21 13:38:42 -070093 if (!parseTable(parser.getChunk())) {
94 error = true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070095 }
Adam Lesinskib54ef102016-10-21 13:38:42 -070096 }
97
98 if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) {
99 mContext->getDiagnostics()->error(DiagMessage(mSource)
100 << "corrupt resource table: "
101 << parser.getLastError());
102 return false;
103 }
104 return !error;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700105}
106
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700107/**
Adam Lesinskib54ef102016-10-21 13:38:42 -0700108 * Parses the resource table, which contains all the packages, types, and
109 * entries.
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700110 */
111bool BinaryResourceParser::parseTable(const ResChunk_header* chunk) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700112 const ResTable_header* tableHeader = convertTo<ResTable_header>(chunk);
113 if (!tableHeader) {
114 mContext->getDiagnostics()->error(DiagMessage(mSource)
115 << "corrupt ResTable_header chunk");
116 return false;
117 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700118
Adam Lesinskib54ef102016-10-21 13:38:42 -0700119 ResChunkPullParser parser(getChunkData(&tableHeader->header),
120 getChunkDataLen(&tableHeader->header));
121 while (ResChunkPullParser::isGoodEvent(parser.next())) {
122 switch (util::deviceToHost16(parser.getChunk()->type)) {
123 case android::RES_STRING_POOL_TYPE:
124 if (mValuePool.getError() == NO_INIT) {
125 status_t err = mValuePool.setTo(
126 parser.getChunk(), util::deviceToHost32(parser.getChunk()->size));
127 if (err != NO_ERROR) {
128 mContext->getDiagnostics()->error(
129 DiagMessage(mSource) << "corrupt string pool in ResTable: "
130 << mValuePool.getError());
131 return false;
132 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700133
Adam Lesinskib54ef102016-10-21 13:38:42 -0700134 // Reserve some space for the strings we are going to add.
135 mTable->stringPool.hintWillAdd(mValuePool.size(),
136 mValuePool.styleCount());
137 } else {
138 mContext->getDiagnostics()->warn(
139 DiagMessage(mSource) << "unexpected string pool in ResTable");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700140 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700141 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700142
Adam Lesinskib54ef102016-10-21 13:38:42 -0700143 case android::RES_TABLE_PACKAGE_TYPE:
144 if (!parsePackage(parser.getChunk())) {
145 return false;
146 }
147 break;
148
149 default:
150 mContext->getDiagnostics()->warn(
151 DiagMessage(mSource)
152 << "unexpected chunk type "
153 << (int)util::deviceToHost16(parser.getChunk()->type));
154 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700155 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700156 }
157
158 if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) {
159 mContext->getDiagnostics()->error(DiagMessage(mSource)
160 << "corrupt resource table: "
161 << parser.getLastError());
162 return false;
163 }
164 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700165}
166
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700167bool BinaryResourceParser::parsePackage(const ResChunk_header* chunk) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700168 const ResTable_package* packageHeader = convertTo<ResTable_package>(chunk);
169 if (!packageHeader) {
170 mContext->getDiagnostics()->error(DiagMessage(mSource)
171 << "corrupt ResTable_package chunk");
172 return false;
173 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700174
Adam Lesinskib54ef102016-10-21 13:38:42 -0700175 uint32_t packageId = util::deviceToHost32(packageHeader->id);
176 if (packageId > std::numeric_limits<uint8_t>::max()) {
177 mContext->getDiagnostics()->error(
178 DiagMessage(mSource) << "package ID is too big (" << packageId << ")");
179 return false;
180 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700181
Adam Lesinskib54ef102016-10-21 13:38:42 -0700182 // Extract the package name.
183 size_t len = strnlen16((const char16_t*)packageHeader->name,
184 arraysize(packageHeader->name));
185 std::u16string packageName;
186 packageName.resize(len);
187 for (size_t i = 0; i < len; i++) {
188 packageName[i] = util::deviceToHost16(packageHeader->name[i]);
189 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700190
Adam Lesinskib54ef102016-10-21 13:38:42 -0700191 ResourceTablePackage* package = mTable->createPackage(
192 util::utf16ToUtf8(packageName), static_cast<uint8_t>(packageId));
193 if (!package) {
194 mContext->getDiagnostics()->error(DiagMessage(mSource)
195 << "incompatible package '" << packageName
196 << "' with ID " << packageId);
197 return false;
198 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700199
Adam Lesinskib54ef102016-10-21 13:38:42 -0700200 // There can be multiple packages in a table, so
201 // clear the type and key pool in case they were set from a previous package.
202 mTypePool.uninit();
203 mKeyPool.uninit();
Adam Lesinskie352b992015-11-16 11:59:14 -0800204
Adam Lesinskib54ef102016-10-21 13:38:42 -0700205 ResChunkPullParser parser(getChunkData(&packageHeader->header),
206 getChunkDataLen(&packageHeader->header));
207 while (ResChunkPullParser::isGoodEvent(parser.next())) {
208 switch (util::deviceToHost16(parser.getChunk()->type)) {
209 case android::RES_STRING_POOL_TYPE:
210 if (mTypePool.getError() == NO_INIT) {
211 status_t err = mTypePool.setTo(
212 parser.getChunk(), util::deviceToHost32(parser.getChunk()->size));
213 if (err != NO_ERROR) {
214 mContext->getDiagnostics()->error(DiagMessage(mSource)
215 << "corrupt type string pool in "
216 << "ResTable_package: "
217 << mTypePool.getError());
218 return false;
219 }
220 } else if (mKeyPool.getError() == NO_INIT) {
221 status_t err = mKeyPool.setTo(
222 parser.getChunk(), util::deviceToHost32(parser.getChunk()->size));
223 if (err != NO_ERROR) {
224 mContext->getDiagnostics()->error(DiagMessage(mSource)
225 << "corrupt key string pool in "
226 << "ResTable_package: "
227 << mKeyPool.getError());
228 return false;
229 }
230 } else {
231 mContext->getDiagnostics()->warn(DiagMessage(mSource)
232 << "unexpected string pool");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700233 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700234 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700235
Adam Lesinskib54ef102016-10-21 13:38:42 -0700236 case android::RES_TABLE_TYPE_SPEC_TYPE:
237 if (!parseTypeSpec(parser.getChunk())) {
238 return false;
239 }
240 break;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700241
Adam Lesinskib54ef102016-10-21 13:38:42 -0700242 case android::RES_TABLE_TYPE_TYPE:
243 if (!parseType(package, parser.getChunk())) {
244 return false;
245 }
246 break;
247
248 default:
249 mContext->getDiagnostics()->warn(
250 DiagMessage(mSource)
251 << "unexpected chunk type "
252 << (int)util::deviceToHost16(parser.getChunk()->type));
253 break;
254 }
255 }
256
257 if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) {
258 mContext->getDiagnostics()->error(DiagMessage(mSource)
259 << "corrupt ResTable_package: "
260 << parser.getLastError());
261 return false;
262 }
263
264 // Now go through the table and change local resource ID references to
265 // symbolic references.
266 ReferenceIdToNameVisitor visitor(&mIdIndex);
267 visitAllValuesInTable(mTable, &visitor);
268 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700269}
270
271bool BinaryResourceParser::parseTypeSpec(const ResChunk_header* chunk) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700272 if (mTypePool.getError() != NO_ERROR) {
273 mContext->getDiagnostics()->error(DiagMessage(mSource)
274 << "missing type string pool");
275 return false;
276 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700277
Adam Lesinskib54ef102016-10-21 13:38:42 -0700278 const ResTable_typeSpec* typeSpec = convertTo<ResTable_typeSpec>(chunk);
279 if (!typeSpec) {
280 mContext->getDiagnostics()->error(DiagMessage(mSource)
281 << "corrupt ResTable_typeSpec chunk");
282 return false;
283 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700284
Adam Lesinskib54ef102016-10-21 13:38:42 -0700285 if (typeSpec->id == 0) {
286 mContext->getDiagnostics()->error(DiagMessage(mSource)
287 << "ResTable_typeSpec has invalid id: "
288 << typeSpec->id);
289 return false;
290 }
291 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700292}
293
294bool BinaryResourceParser::parseType(const ResourceTablePackage* package,
295 const ResChunk_header* chunk) {
Adam Lesinskib54ef102016-10-21 13:38:42 -0700296 if (mTypePool.getError() != NO_ERROR) {
297 mContext->getDiagnostics()->error(DiagMessage(mSource)
298 << "missing type string pool");
299 return false;
300 }
301
302 if (mKeyPool.getError() != NO_ERROR) {
303 mContext->getDiagnostics()->error(DiagMessage(mSource)
304 << "missing key string pool");
305 return false;
306 }
307
308 const ResTable_type* type = convertTo<ResTable_type>(chunk);
309 if (!type) {
310 mContext->getDiagnostics()->error(DiagMessage(mSource)
311 << "corrupt ResTable_type chunk");
312 return false;
313 }
314
315 if (type->id == 0) {
316 mContext->getDiagnostics()->error(DiagMessage(mSource)
317 << "ResTable_type has invalid id: "
318 << (int)type->id);
319 return false;
320 }
321
322 ConfigDescription config;
323 config.copyFromDtoH(type->config);
324
325 const std::string typeStr = util::getString(mTypePool, type->id - 1);
326
327 const ResourceType* parsedType = parseResourceType(typeStr);
328 if (!parsedType) {
329 mContext->getDiagnostics()->error(
330 DiagMessage(mSource) << "invalid type name '" << typeStr
331 << "' for type with ID " << (int)type->id);
332 return false;
333 }
334
335 TypeVariant tv(type);
336 for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
337 const ResTable_entry* entry = *it;
338 if (!entry) {
339 continue;
340 }
341
342 const ResourceName name(
343 package->name, *parsedType,
344 util::getString(mKeyPool, util::deviceToHost32(entry->key.index)));
345
346 const ResourceId resId(package->id.value(), type->id,
347 static_cast<uint16_t>(it.index()));
348
349 std::unique_ptr<Value> resourceValue;
350 if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
351 const ResTable_map_entry* mapEntry =
352 static_cast<const ResTable_map_entry*>(entry);
353
354 // TODO(adamlesinski): Check that the entry count is valid.
355 resourceValue = parseMapEntry(name, config, mapEntry);
356 } else {
357 const Res_value* value =
358 (const Res_value*)((const uint8_t*)entry +
359 util::deviceToHost32(entry->size));
360 resourceValue = parseValue(name, config, value, entry->flags);
361 }
362
363 if (!resourceValue) {
364 mContext->getDiagnostics()->error(
365 DiagMessage(mSource) << "failed to parse value for resource " << name
366 << " (" << resId << ") with configuration '"
367 << config << "'");
368 return false;
369 }
370
371 if (!mTable->addResourceAllowMangled(name, config, {},
372 std::move(resourceValue),
373 mContext->getDiagnostics())) {
374 return false;
375 }
376
377 if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) {
378 Symbol symbol;
379 symbol.state = SymbolState::kPublic;
380 symbol.source = mSource.withLine(0);
381 if (!mTable->setSymbolStateAllowMangled(name, resId, symbol,
382 mContext->getDiagnostics())) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700383 return false;
Adam Lesinskib54ef102016-10-21 13:38:42 -0700384 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700385 }
386
Adam Lesinskib54ef102016-10-21 13:38:42 -0700387 // Add this resource name->id mapping to the index so
388 // that we can resolve all ID references to name references.
389 auto cacheIter = mIdIndex.find(resId);
390 if (cacheIter == mIdIndex.end()) {
391 mIdIndex.insert({resId, name});
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700392 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700393 }
394 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700395}
396
Adam Lesinskib54ef102016-10-21 13:38:42 -0700397std::unique_ptr<Item> BinaryResourceParser::parseValue(
398 const ResourceNameRef& name, const ConfigDescription& config,
399 const Res_value* value, uint16_t flags) {
400 if (name.type == ResourceType::kId) {
401 return util::make_unique<Id>();
402 }
403
404 const uint32_t data = util::deviceToHost32(value->data);
405
406 if (value->dataType == Res_value::TYPE_STRING) {
407 const std::string str = util::getString(mValuePool, data);
408
409 const ResStringPool_span* spans = mValuePool.styleAt(data);
410
411 // Check if the string has a valid style associated with it.
412 if (spans != nullptr && spans->name.index != ResStringPool_span::END) {
413 StyleString styleStr = {str};
414 while (spans->name.index != ResStringPool_span::END) {
415 styleStr.spans.push_back(
416 Span{util::getString(mValuePool, spans->name.index),
417 spans->firstChar, spans->lastChar});
418 spans++;
419 }
420 return util::make_unique<StyledString>(mTable->stringPool.makeRef(
421 styleStr,
422 StringPool::Context(StringPool::Context::kStylePriority, config)));
423 } else {
424 if (name.type != ResourceType::kString &&
425 util::stringStartsWith(str, "res/")) {
426 // This must be a FileReference.
427 return util::make_unique<FileReference>(mTable->stringPool.makeRef(
428 str,
429 StringPool::Context(StringPool::Context::kHighPriority, config)));
430 }
431
432 // There are no styles associated with this string, so treat it as
433 // a simple string.
434 return util::make_unique<String>(
435 mTable->stringPool.makeRef(str, StringPool::Context(config)));
436 }
437 }
438
439 if (value->dataType == Res_value::TYPE_REFERENCE ||
440 value->dataType == Res_value::TYPE_ATTRIBUTE) {
441 const Reference::Type type = (value->dataType == Res_value::TYPE_REFERENCE)
442 ? Reference::Type::kResource
443 : Reference::Type::kAttribute;
444
445 if (data == 0) {
446 // A reference of 0, must be the magic @null reference.
447 Res_value nullType = {};
448 nullType.dataType = Res_value::TYPE_REFERENCE;
449 return util::make_unique<BinaryPrimitive>(nullType);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700450 }
451
Adam Lesinskib54ef102016-10-21 13:38:42 -0700452 // This is a normal reference.
453 return util::make_unique<Reference>(data, type);
454 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700455
Adam Lesinskib54ef102016-10-21 13:38:42 -0700456 // Treat this as a raw binary primitive.
457 return util::make_unique<BinaryPrimitive>(*value);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700458}
459
Adam Lesinskib54ef102016-10-21 13:38:42 -0700460std::unique_ptr<Value> BinaryResourceParser::parseMapEntry(
461 const ResourceNameRef& name, const ConfigDescription& config,
462 const ResTable_map_entry* map) {
463 switch (name.type) {
464 case ResourceType::kStyle:
465 return parseStyle(name, config, map);
466 case ResourceType::kAttrPrivate:
467 // fallthrough
468 case ResourceType::kAttr:
469 return parseAttr(name, config, map);
470 case ResourceType::kArray:
471 return parseArray(name, config, map);
472 case ResourceType::kPlurals:
473 return parsePlural(name, config, map);
474 default:
475 assert(false && "unknown map type");
476 break;
477 }
478 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700479}
480
Adam Lesinskib54ef102016-10-21 13:38:42 -0700481std::unique_ptr<Style> BinaryResourceParser::parseStyle(
482 const ResourceNameRef& name, const ConfigDescription& config,
483 const ResTable_map_entry* map) {
484 std::unique_ptr<Style> style = util::make_unique<Style>();
485 if (util::deviceToHost32(map->parent.ident) != 0) {
486 // The parent is a regular reference to a resource.
487 style->parent = Reference(util::deviceToHost32(map->parent.ident));
488 }
489
490 for (const ResTable_map& mapEntry : map) {
491 if (Res_INTERNALID(util::deviceToHost32(mapEntry.name.ident))) {
492 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700493 }
494
Adam Lesinskib54ef102016-10-21 13:38:42 -0700495 Style::Entry styleEntry;
496 styleEntry.key = Reference(util::deviceToHost32(mapEntry.name.ident));
497 styleEntry.value = parseValue(name, config, &mapEntry.value, 0);
498 if (!styleEntry.value) {
499 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700500 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700501 style->entries.push_back(std::move(styleEntry));
502 }
503 return style;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700504}
505
Adam Lesinskib54ef102016-10-21 13:38:42 -0700506std::unique_ptr<Attribute> BinaryResourceParser::parseAttr(
507 const ResourceNameRef& name, const ConfigDescription& config,
508 const ResTable_map_entry* map) {
509 const bool isWeak =
510 (util::deviceToHost16(map->flags) & ResTable_entry::FLAG_WEAK) != 0;
511 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700512
Adam Lesinskib54ef102016-10-21 13:38:42 -0700513 // First we must discover what type of attribute this is. Find the type mask.
514 auto typeMaskIter =
515 std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
516 return util::deviceToHost32(entry.name.ident) ==
517 ResTable_map::ATTR_TYPE;
518 });
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700519
Adam Lesinskib54ef102016-10-21 13:38:42 -0700520 if (typeMaskIter != end(map)) {
521 attr->typeMask = util::deviceToHost32(typeMaskIter->value.data);
522 }
523
524 for (const ResTable_map& mapEntry : map) {
525 if (Res_INTERNALID(util::deviceToHost32(mapEntry.name.ident))) {
526 switch (util::deviceToHost32(mapEntry.name.ident)) {
527 case ResTable_map::ATTR_MIN:
528 attr->minInt = static_cast<int32_t>(mapEntry.value.data);
529 break;
530 case ResTable_map::ATTR_MAX:
531 attr->maxInt = static_cast<int32_t>(mapEntry.value.data);
532 break;
533 }
534 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700535 }
536
Adam Lesinskib54ef102016-10-21 13:38:42 -0700537 if (attr->typeMask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
538 Attribute::Symbol symbol;
539 symbol.value = util::deviceToHost32(mapEntry.value.data);
540 symbol.symbol = Reference(util::deviceToHost32(mapEntry.name.ident));
541 attr->symbols.push_back(std::move(symbol));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700542 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700543 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700544
Adam Lesinskib54ef102016-10-21 13:38:42 -0700545 // TODO(adamlesinski): Find i80n, attributes.
546 return attr;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700547}
548
Adam Lesinskib54ef102016-10-21 13:38:42 -0700549std::unique_ptr<Array> BinaryResourceParser::parseArray(
550 const ResourceNameRef& name, const ConfigDescription& config,
551 const ResTable_map_entry* map) {
552 std::unique_ptr<Array> array = util::make_unique<Array>();
553 for (const ResTable_map& mapEntry : map) {
554 array->items.push_back(parseValue(name, config, &mapEntry.value, 0));
555 }
556 return array;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700557}
558
Adam Lesinskib54ef102016-10-21 13:38:42 -0700559std::unique_ptr<Plural> BinaryResourceParser::parsePlural(
560 const ResourceNameRef& name, const ConfigDescription& config,
561 const ResTable_map_entry* map) {
562 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
563 for (const ResTable_map& mapEntry : map) {
564 std::unique_ptr<Item> item = parseValue(name, config, &mapEntry.value, 0);
565 if (!item) {
566 return {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700567 }
Adam Lesinskib54ef102016-10-21 13:38:42 -0700568
569 switch (util::deviceToHost32(mapEntry.name.ident)) {
570 case ResTable_map::ATTR_ZERO:
571 plural->values[Plural::Zero] = std::move(item);
572 break;
573 case ResTable_map::ATTR_ONE:
574 plural->values[Plural::One] = std::move(item);
575 break;
576 case ResTable_map::ATTR_TWO:
577 plural->values[Plural::Two] = std::move(item);
578 break;
579 case ResTable_map::ATTR_FEW:
580 plural->values[Plural::Few] = std::move(item);
581 break;
582 case ResTable_map::ATTR_MANY:
583 plural->values[Plural::Many] = std::move(item);
584 break;
585 case ResTable_map::ATTR_OTHER:
586 plural->values[Plural::Other] = std::move(item);
587 break;
588 }
589 }
590 return plural;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700591}
592
Adam Lesinskib54ef102016-10-21 13:38:42 -0700593} // namespace aapt