1/*
2 * Copyright (C) 2016 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 "ResourceTable.h"
18#include "ResourceUtils.h"
19#include "ValueVisitor.h"
20#include "proto/ProtoHelpers.h"
21#include "proto/ProtoSerialize.h"
22
23#include <androidfw/ResourceTypes.h>
24
25namespace aapt {
26
27namespace {
28
29class ReferenceIdToNameVisitor : public ValueVisitor {
30public:
31    using ValueVisitor::visit;
32
33    ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping) :
34            mMapping(mapping) {
35        assert(mMapping);
36    }
37
38    void visit(Reference* reference) override {
39        if (!reference->id || !reference->id.value().isValid()) {
40            return;
41        }
42
43        ResourceId id = reference->id.value();
44        auto cacheIter = mMapping->find(id);
45        if (cacheIter != mMapping->end()) {
46            reference->name = cacheIter->second.toResourceName();
47        }
48    }
49
50private:
51    const std::map<ResourceId, ResourceNameRef>* mMapping;
52};
53
54class PackagePbDeserializer {
55public:
56    PackagePbDeserializer(const android::ResStringPool* valuePool,
57                          const android::ResStringPool* sourcePool,
58                          const android::ResStringPool* symbolPool,
59                          const Source& source, IDiagnostics* diag) :
60            mValuePool(valuePool), mSourcePool(sourcePool), mSymbolPool(symbolPool),
61            mSource(source), mDiag(diag) {
62    }
63
64public:
65    bool deserializeFromPb(const pb::Package& pbPackage, ResourceTable* table) {
66        Maybe<uint8_t> id;
67        if (pbPackage.has_package_id()) {
68            id = static_cast<uint8_t>(pbPackage.package_id());
69        }
70
71        std::map<ResourceId, ResourceNameRef> idIndex;
72
73        ResourceTablePackage* pkg = table->createPackage(
74                util::utf8ToUtf16(pbPackage.package_name()), id);
75        for (const pb::Type& pbType : pbPackage.types()) {
76            const ResourceType* resType = parseResourceType(util::utf8ToUtf16(pbType.name()));
77            if (!resType) {
78                mDiag->error(DiagMessage(mSource) << "unknown type '" << pbType.name() << "'");
79                return {};
80            }
81
82            ResourceTableType* type = pkg->findOrCreateType(*resType);
83
84            for (const pb::Entry& pbEntry : pbType.entries()) {
85                ResourceEntry* entry = type->findOrCreateEntry(util::utf8ToUtf16(pbEntry.name()));
86
87                // Deserialize the symbol status (public/private with source and comments).
88                if (pbEntry.has_symbol_status()) {
89                    const pb::SymbolStatus& pbStatus = pbEntry.symbol_status();
90                    if (pbStatus.has_source()) {
91                        deserializeSourceFromPb(pbStatus.source(), *mSourcePool,
92                                                &entry->symbolStatus.source);
93                    }
94
95                    if (pbStatus.has_comment()) {
96                        entry->symbolStatus.comment = util::utf8ToUtf16(pbStatus.comment());
97                    }
98
99                    SymbolState visibility = deserializeVisibilityFromPb(pbStatus.visibility());
100                    entry->symbolStatus.state = visibility;
101
102                    if (visibility == SymbolState::kPublic) {
103                        // This is a public symbol, we must encode the ID now if there is one.
104                        if (pbEntry.has_id()) {
105                            entry->id = static_cast<uint16_t>(pbEntry.id());
106                        }
107
108                        if (type->symbolStatus.state != SymbolState::kPublic) {
109                            // If the type has not been made public, do so now.
110                            type->symbolStatus.state = SymbolState::kPublic;
111                            if (pbType.has_id()) {
112                                type->id = static_cast<uint8_t>(pbType.id());
113                            }
114                        }
115                    } else if (visibility == SymbolState::kPrivate) {
116                        if (type->symbolStatus.state == SymbolState::kUndefined) {
117                            type->symbolStatus.state = SymbolState::kPrivate;
118                        }
119                    }
120                }
121
122                ResourceId resId(pbPackage.package_id(), pbType.id(), pbEntry.id());
123                if (resId.isValid()) {
124                    idIndex[resId] = ResourceNameRef(pkg->name, type->type, entry->name);
125                }
126
127                for (const pb::ConfigValue& pbConfigValue : pbEntry.config_values()) {
128                    const pb::ConfigDescription& pbConfig = pbConfigValue.config();
129
130                    ConfigDescription config;
131                    if (!deserializeConfigDescriptionFromPb(pbConfig, &config)) {
132                        mDiag->error(DiagMessage(mSource) << "invalid configuration");
133                        return {};
134                    }
135
136                    ResourceConfigValue* configValue = entry->findOrCreateValue(config,
137                                                                                pbConfig.product());
138                    if (configValue->value) {
139                        // Duplicate config.
140                        mDiag->error(DiagMessage(mSource) << "duplicate configuration");
141                        return {};
142                    }
143
144                    configValue->value = deserializeValueFromPb(pbConfigValue.value(),
145                                                                config, &table->stringPool);
146                    if (!configValue->value) {
147                        return {};
148                    }
149                }
150            }
151        }
152
153        ReferenceIdToNameVisitor visitor(&idIndex);
154        visitAllValuesInPackage(pkg, &visitor);
155        return true;
156    }
157
158private:
159    std::unique_ptr<Item> deserializeItemFromPb(const pb::Item& pbItem,
160                                                const ConfigDescription& config,
161                                                StringPool* pool) {
162        if (pbItem.has_ref()) {
163            const pb::Reference& pbRef = pbItem.ref();
164            std::unique_ptr<Reference> ref = util::make_unique<Reference>();
165            if (!deserializeReferenceFromPb(pbRef, ref.get())) {
166                return {};
167            }
168            return std::move(ref);
169
170        } else if (pbItem.has_prim()) {
171            const pb::Primitive& pbPrim = pbItem.prim();
172            android::Res_value prim = {};
173            prim.dataType = static_cast<uint8_t>(pbPrim.type());
174            prim.data = pbPrim.data();
175            return util::make_unique<BinaryPrimitive>(prim);
176
177        } else if (pbItem.has_id()) {
178            return util::make_unique<Id>();
179
180        } else if (pbItem.has_str()) {
181            const uint32_t idx = pbItem.str().idx();
182            StringPiece16 str = util::getString(*mValuePool, idx);
183
184            const android::ResStringPool_span* spans = mValuePool->styleAt(idx);
185            if (spans && spans->name.index != android::ResStringPool_span::END) {
186                StyleString styleStr = { str.toString() };
187                while (spans->name.index != android::ResStringPool_span::END) {
188                    styleStr.spans.push_back(Span{
189                            util::getString(*mValuePool, spans->name.index).toString(),
190                            spans->firstChar,
191                            spans->lastChar
192                    });
193                    spans++;
194                }
195                return util::make_unique<StyledString>(
196                        pool->makeRef(styleStr, StringPool::Context{ 1, config }));
197            }
198            return util::make_unique<String>(
199                    pool->makeRef(str, StringPool::Context{ 1, config }));
200
201        } else if (pbItem.has_raw_str()) {
202            const uint32_t idx = pbItem.raw_str().idx();
203            StringPiece16 str = util::getString(*mValuePool, idx);
204            return util::make_unique<RawString>(
205                    pool->makeRef(str, StringPool::Context{ 1, config }));
206
207        } else if (pbItem.has_file()) {
208            const uint32_t idx = pbItem.file().path_idx();
209            StringPiece16 str = util::getString(*mValuePool, idx);
210            return util::make_unique<FileReference>(
211                    pool->makeRef(str, StringPool::Context{ 0, config }));
212
213        } else {
214            mDiag->error(DiagMessage(mSource) << "unknown item");
215        }
216        return {};
217    }
218
219    std::unique_ptr<Value> deserializeValueFromPb(const pb::Value& pbValue,
220                                                  const ConfigDescription& config,
221                                                  StringPool* pool) {
222        const bool isWeak = pbValue.has_weak() ? pbValue.weak() : false;
223
224        std::unique_ptr<Value> value;
225        if (pbValue.has_item()) {
226            value = deserializeItemFromPb(pbValue.item(), config, pool);
227            if (!value) {
228                return {};
229            }
230
231        } else if (pbValue.has_compound_value()) {
232            const pb::CompoundValue pbCompoundValue = pbValue.compound_value();
233            if (pbCompoundValue.has_attr()) {
234                const pb::Attribute& pbAttr = pbCompoundValue.attr();
235                std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak);
236                attr->typeMask = pbAttr.format_flags();
237                attr->minInt = pbAttr.min_int();
238                attr->maxInt = pbAttr.max_int();
239                for (const pb::Attribute_Symbol& pbSymbol : pbAttr.symbols()) {
240                    Attribute::Symbol symbol;
241                    deserializeItemCommon(pbSymbol, &symbol.symbol);
242                    if (!deserializeReferenceFromPb(pbSymbol.name(), &symbol.symbol)) {
243                        return {};
244                    }
245                    symbol.value = pbSymbol.value();
246                    attr->symbols.push_back(std::move(symbol));
247                }
248                value = std::move(attr);
249
250            } else if (pbCompoundValue.has_style()) {
251                const pb::Style& pbStyle = pbCompoundValue.style();
252                std::unique_ptr<Style> style = util::make_unique<Style>();
253                if (pbStyle.has_parent()) {
254                    style->parent = Reference();
255                    if (!deserializeReferenceFromPb(pbStyle.parent(), &style->parent.value())) {
256                        return {};
257                    }
258
259                    if (pbStyle.has_parent_source()) {
260                        Source parentSource;
261                        deserializeSourceFromPb(pbStyle.parent_source(), *mSourcePool,
262                                                &parentSource);
263                        style->parent.value().setSource(std::move(parentSource));
264                    }
265                }
266
267                for (const pb::Style_Entry& pbEntry : pbStyle.entries()) {
268                    Style::Entry entry;
269                    deserializeItemCommon(pbEntry, &entry.key);
270                    if (!deserializeReferenceFromPb(pbEntry.key(), &entry.key)) {
271                        return {};
272                    }
273
274                    entry.value = deserializeItemFromPb(pbEntry.item(), config, pool);
275                    if (!entry.value) {
276                        return {};
277                    }
278
279                    deserializeItemCommon(pbEntry, entry.value.get());
280                    style->entries.push_back(std::move(entry));
281                }
282                value = std::move(style);
283
284            } else if (pbCompoundValue.has_styleable()) {
285                const pb::Styleable& pbStyleable = pbCompoundValue.styleable();
286                std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
287                for (const pb::Styleable_Entry& pbEntry : pbStyleable.entries()) {
288                    Reference attrRef;
289                    deserializeItemCommon(pbEntry, &attrRef);
290                    deserializeReferenceFromPb(pbEntry.attr(), &attrRef);
291                    styleable->entries.push_back(std::move(attrRef));
292                }
293                value = std::move(styleable);
294
295            } else if (pbCompoundValue.has_array()) {
296                const pb::Array& pbArray = pbCompoundValue.array();
297                std::unique_ptr<Array> array = util::make_unique<Array>();
298                for (const pb::Array_Entry& pbEntry : pbArray.entries()) {
299                    std::unique_ptr<Item> item = deserializeItemFromPb(pbEntry.item(), config,
300                                                                       pool);
301                    if (!item) {
302                        return {};
303                    }
304
305                    deserializeItemCommon(pbEntry, item.get());
306                    array->items.push_back(std::move(item));
307                }
308                value = std::move(array);
309
310            } else if (pbCompoundValue.has_plural()) {
311                const pb::Plural& pbPlural = pbCompoundValue.plural();
312                std::unique_ptr<Plural> plural = util::make_unique<Plural>();
313                for (const pb::Plural_Entry& pbEntry : pbPlural.entries()) {
314                    size_t pluralIdx = deserializePluralEnumFromPb(pbEntry.arity());
315                    plural->values[pluralIdx] = deserializeItemFromPb(pbEntry.item(), config,
316                                                                      pool);
317                    if (!plural->values[pluralIdx]) {
318                        return {};
319                    }
320
321                    deserializeItemCommon(pbEntry, plural->values[pluralIdx].get());
322                }
323                value = std::move(plural);
324
325            } else {
326                mDiag->error(DiagMessage(mSource) << "unknown compound value");
327                return {};
328            }
329        } else {
330            mDiag->error(DiagMessage(mSource) << "unknown value");
331            return {};
332        }
333
334        assert(value && "forgot to set value");
335
336        value->setWeak(isWeak);
337        deserializeItemCommon(pbValue, value.get());
338        return value;
339    }
340
341    bool deserializeReferenceFromPb(const pb::Reference& pbRef, Reference* outRef) {
342        outRef->referenceType = deserializeReferenceTypeFromPb(pbRef.type());
343        outRef->privateReference = pbRef.private_();
344
345        if (!pbRef.has_id() && !pbRef.has_symbol_idx()) {
346            return false;
347        }
348
349        if (pbRef.has_id()) {
350            outRef->id = ResourceId(pbRef.id());
351        }
352
353        if (pbRef.has_symbol_idx()) {
354            StringPiece16 strSymbol = util::getString(*mSymbolPool, pbRef.symbol_idx());
355            ResourceNameRef nameRef;
356            if (!ResourceUtils::parseResourceName(strSymbol, &nameRef, nullptr)) {
357                mDiag->error(DiagMessage(mSource) << "invalid reference name '"
358                             << strSymbol << "'");
359                return false;
360            }
361
362            outRef->name = nameRef.toResourceName();
363        }
364        return true;
365    }
366
367    template <typename T>
368    void deserializeItemCommon(const T& pbItem, Value* outValue) {
369        if (pbItem.has_source()) {
370            Source source;
371            deserializeSourceFromPb(pbItem.source(), *mSourcePool, &source);
372            outValue->setSource(std::move(source));
373        }
374
375        if (pbItem.has_comment()) {
376            outValue->setComment(util::utf8ToUtf16(pbItem.comment()));
377        }
378    }
379
380private:
381    const android::ResStringPool* mValuePool;
382    const android::ResStringPool* mSourcePool;
383    const android::ResStringPool* mSymbolPool;
384    const Source mSource;
385    IDiagnostics* mDiag;
386};
387
388} // namespace
389
390std::unique_ptr<ResourceTable> deserializeTableFromPb(const pb::ResourceTable& pbTable,
391                                                      const Source& source,
392                                                      IDiagnostics* diag) {
393    // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
394    // causes errors when qualifying it with android::
395    using namespace android;
396
397    std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
398
399    if (!pbTable.has_string_pool()) {
400        diag->error(DiagMessage(source) << "no string pool found");
401        return {};
402    }
403
404    ResStringPool valuePool;
405    status_t result = valuePool.setTo(pbTable.string_pool().data().data(),
406                                      pbTable.string_pool().data().size());
407    if (result != NO_ERROR) {
408        diag->error(DiagMessage(source) << "invalid string pool");
409        return {};
410    }
411
412    ResStringPool sourcePool;
413    if (pbTable.has_source_pool()) {
414        result = sourcePool.setTo(pbTable.source_pool().data().data(),
415                                  pbTable.source_pool().data().size());
416        if (result != NO_ERROR) {
417            diag->error(DiagMessage(source) << "invalid source pool");
418            return {};
419        }
420    }
421
422    ResStringPool symbolPool;
423    if (pbTable.has_symbol_pool()) {
424        result = symbolPool.setTo(pbTable.symbol_pool().data().data(),
425                                  pbTable.symbol_pool().data().size());
426        if (result != NO_ERROR) {
427            diag->error(DiagMessage(source) << "invalid symbol pool");
428            return {};
429        }
430    }
431
432    PackagePbDeserializer packagePbDeserializer(&valuePool, &sourcePool, &symbolPool, source, diag);
433    for (const pb::Package& pbPackage : pbTable.packages()) {
434        if (!packagePbDeserializer.deserializeFromPb(pbPackage, table.get())) {
435            return {};
436        }
437    }
438    return table;
439}
440
441std::unique_ptr<ResourceFile> deserializeCompiledFileFromPb(const pb::CompiledFile& pbFile,
442                                                            const Source& source,
443                                                            IDiagnostics* diag) {
444    std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>();
445
446    ResourceNameRef nameRef;
447
448    // Need to create an lvalue here so that nameRef can point to something real.
449    std::u16string utf16Name = util::utf8ToUtf16(pbFile.resource_name());
450    if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) {
451        diag->error(DiagMessage(source) << "invalid resource name in compiled file header: "
452                    << pbFile.resource_name());
453        return {};
454    }
455    file->name = nameRef.toResourceName();
456    file->source.path = pbFile.source_path();
457    deserializeConfigDescriptionFromPb(pbFile.config(), &file->config);
458
459    for (const pb::CompiledFile_Symbol& pbSymbol : pbFile.exported_symbols()) {
460        // Need to create an lvalue here so that nameRef can point to something real.
461        utf16Name = util::utf8ToUtf16(pbSymbol.resource_name());
462        if (!ResourceUtils::parseResourceName(utf16Name, &nameRef)) {
463            diag->error(DiagMessage(source) << "invalid resource name for exported symbol in "
464                                               "compiled file header: "
465                                            << pbFile.resource_name());
466            return {};
467        }
468        file->exportedSymbols.push_back(
469                SourcedResourceName{ nameRef.toResourceName(), pbSymbol.line_no() });
470    }
471    return file;
472}
473
474CompiledFileInputStream::CompiledFileInputStream(const void* data, size_t size) :
475        mIn(static_cast<const uint8_t*>(data), size), mPbFile(),
476        mData(static_cast<const uint8_t*>(data)), mSize(size) {
477}
478
479const pb::CompiledFile* CompiledFileInputStream::CompiledFile() {
480    if (!mPbFile) {
481        std::unique_ptr<pb::CompiledFile> pbFile = util::make_unique<pb::CompiledFile>();
482        uint64_t pbSize = 0u;
483        if (!mIn.ReadLittleEndian64(&pbSize)) {
484            return nullptr;
485        }
486        mIn.PushLimit(static_cast<int>(pbSize));
487        if (!pbFile->ParsePartialFromCodedStream(&mIn)) {
488            return nullptr;
489        }
490
491        const size_t padding = 4 - (pbSize & 0x03);
492        const size_t offset = sizeof(uint64_t) + pbSize + padding;
493        if (offset > mSize) {
494            return nullptr;
495        }
496
497        mData += offset;
498        mSize -= offset;
499        mPbFile = std::move(pbFile);
500    }
501    return mPbFile.get();
502}
503
504const void* CompiledFileInputStream::data() {
505    if (!mPbFile) {
506        if (!CompiledFile()) {
507            return nullptr;
508        }
509    }
510    return mData;
511}
512
513size_t CompiledFileInputStream::size() {
514    if (!mPbFile) {
515        if (!CompiledFile()) {
516            return 0;
517        }
518    }
519    return mSize;
520}
521
522} // namespace aapt
523