blob: 7e5efa15f61b86ee46b18c644b42240e90901ade [file] [log] [blame]
Pierre Lecesneff759e62017-02-01 00:29:25 +00001/*
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 "LoadedApk.h"
18
Pierre Lecesne2599aa42017-02-01 22:47:03 +000019#include "ResourceValues.h"
20#include "ValueVisitor.h"
21#include "flatten/Archive.h"
22#include "flatten/TableFlattener.h"
Adam Lesinski06460ef2017-03-14 18:52:13 -070023#include "io/BigBufferInputStream.h"
Adam Lesinskid0f492d2017-04-03 18:12:45 -070024#include "io/Util.h"
Pierre Lecesne2599aa42017-02-01 22:47:03 +000025
Pierre Lecesneff759e62017-02-01 00:29:25 +000026namespace aapt {
27
Pierre Lecesne2599aa42017-02-01 22:47:03 +000028std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context,
29 const android::StringPiece& path) {
Pierre Lecesneff759e62017-02-01 00:29:25 +000030 Source source(path);
31 std::string error;
Adam Lesinski06460ef2017-03-14 18:52:13 -070032 std::unique_ptr<io::ZipFileCollection> apk = io::ZipFileCollection::Create(path, &error);
Pierre Lecesneff759e62017-02-01 00:29:25 +000033 if (!apk) {
34 context->GetDiagnostics()->Error(DiagMessage(source) << error);
35 return {};
36 }
37
38 io::IFile* file = apk->FindFile("resources.arsc");
39 if (!file) {
Adam Lesinski06460ef2017-03-14 18:52:13 -070040 context->GetDiagnostics()->Error(DiagMessage(source) << "no resources.arsc found");
Pierre Lecesneff759e62017-02-01 00:29:25 +000041 return {};
42 }
43
44 std::unique_ptr<io::IData> data = file->OpenAsData();
45 if (!data) {
Adam Lesinski06460ef2017-03-14 18:52:13 -070046 context->GetDiagnostics()->Error(DiagMessage(source) << "could not open resources.arsc");
Pierre Lecesneff759e62017-02-01 00:29:25 +000047 return {};
48 }
49
50 std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
Adam Lesinskid0f492d2017-04-03 18:12:45 -070051 BinaryResourceParser parser(context, table.get(), source, data->data(), data->size(), apk.get());
Pierre Lecesneff759e62017-02-01 00:29:25 +000052 if (!parser.Parse()) {
53 return {};
54 }
Pierre Lecesneff759e62017-02-01 00:29:25 +000055 return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
56}
57
Adam Lesinskid48944a2017-02-21 14:22:30 -080058bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOptions& options,
59 IArchiveWriter* writer) {
Shane Farmer57669432017-06-19 12:52:04 -070060 FilterChain empty;
61 return WriteToArchive(context, options, &empty, writer);
62}
63
64bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOptions& options,
65 FilterChain* filters, IArchiveWriter* writer) {
Pierre Lecesne2599aa42017-02-01 22:47:03 +000066 std::set<std::string> referenced_resources;
67 // List the files being referenced in the resource table.
68 for (auto& pkg : table_->packages) {
69 for (auto& type : pkg->types) {
70 for (auto& entry : type->entries) {
71 for (auto& config_value : entry->values) {
72 FileReference* file_ref = ValueCast<FileReference>(config_value->value.get());
73 if (file_ref) {
74 referenced_resources.insert(*file_ref->path);
75 }
76 }
77 }
78 }
79 }
80
81 std::unique_ptr<io::IFileCollectionIterator> iterator = apk_->Iterator();
82 while (iterator->HasNext()) {
83 io::IFile* file = iterator->Next();
84
85 std::string path = file->GetSource().path;
86 // The name of the path has the format "<zip-file-name>@<path-to-file>".
87 path = path.substr(path.find("@") + 1);
88
89 // Skip resources that are not referenced if requested.
90 if (path.find("res/") == 0 && referenced_resources.find(path) == referenced_resources.end()) {
91 if (context->IsVerbose()) {
92 context->GetDiagnostics()->Note(DiagMessage()
Pierre Lecesnefa131d52017-02-03 19:15:03 +000093 << "Removing resource '" << path << "' from APK.");
Pierre Lecesne2599aa42017-02-01 22:47:03 +000094 }
95 continue;
96 }
97
Shane Farmer57669432017-06-19 12:52:04 -070098 if (!filters->Keep(path)) {
99 if (context->IsVerbose()) {
100 context->GetDiagnostics()->Note(DiagMessage() << "Filtered '" << path << "' from APK.");
101 }
102 continue;
103 }
104
Adam Lesinski06460ef2017-03-14 18:52:13 -0700105 // The resource table needs to be re-serialized since it might have changed.
Pierre Lecesne2599aa42017-02-01 22:47:03 +0000106 if (path == "resources.arsc") {
Adam Lesinski06460ef2017-03-14 18:52:13 -0700107 BigBuffer buffer(4096);
Adam Lesinskic8f71aa2017-02-08 07:03:50 -0800108 // TODO(adamlesinski): How to determine if there were sparse entries (and if to encode
109 // with sparse entries) b/35389232.
Adam Lesinskid48944a2017-02-21 14:22:30 -0800110 TableFlattener flattener(options, &buffer);
Pierre Lecesne2599aa42017-02-01 22:47:03 +0000111 if (!flattener.Consume(context, table_.get())) {
112 return false;
113 }
114
Adam Lesinski06460ef2017-03-14 18:52:13 -0700115 io::BigBufferInputStream input_stream(&buffer);
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700116 if (!io::CopyInputStreamToArchive(context, &input_stream, path, ArchiveEntry::kAlign,
117 writer)) {
Pierre Lecesne2599aa42017-02-01 22:47:03 +0000118 return false;
119 }
Pierre Lecesne2599aa42017-02-01 22:47:03 +0000120
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700121 } else {
122 uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
123 if (!io::CopyFileToArchive(context, file, path, compression_flags, writer)) {
124 return false;
125 }
Pierre Lecesne2599aa42017-02-01 22:47:03 +0000126 }
127 }
Pierre Lecesne2599aa42017-02-01 22:47:03 +0000128 return true;
129}
130
Pierre Lecesneff759e62017-02-01 00:29:25 +0000131} // namespace aapt