OSDN Git Service

Merge "Avoid acquiring a lock on the InputReader thread" into oc-dev
[android-x86/frameworks-base.git] / tools / aapt2 / LoadedApk.cpp
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 "LoadedApk.h"
18
19 #include "ResourceValues.h"
20 #include "ValueVisitor.h"
21 #include "flatten/Archive.h"
22 #include "flatten/TableFlattener.h"
23 #include "io/BigBufferInputStream.h"
24 #include "io/Util.h"
25
26 namespace aapt {
27
28 std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context,
29                                                       const android::StringPiece& path) {
30   Source source(path);
31   std::string error;
32   std::unique_ptr<io::ZipFileCollection> apk = io::ZipFileCollection::Create(path, &error);
33   if (!apk) {
34     context->GetDiagnostics()->Error(DiagMessage(source) << error);
35     return {};
36   }
37
38   io::IFile* file = apk->FindFile("resources.arsc");
39   if (!file) {
40     context->GetDiagnostics()->Error(DiagMessage(source) << "no resources.arsc found");
41     return {};
42   }
43
44   std::unique_ptr<io::IData> data = file->OpenAsData();
45   if (!data) {
46     context->GetDiagnostics()->Error(DiagMessage(source) << "could not open resources.arsc");
47     return {};
48   }
49
50   std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
51   BinaryResourceParser parser(context, table.get(), source, data->data(), data->size(), apk.get());
52   if (!parser.Parse()) {
53     return {};
54   }
55   return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
56 }
57
58 bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOptions& options,
59                                IArchiveWriter* writer) {
60   std::set<std::string> referenced_resources;
61   // List the files being referenced in the resource table.
62   for (auto& pkg : table_->packages) {
63     for (auto& type : pkg->types) {
64       for (auto& entry : type->entries) {
65         for (auto& config_value : entry->values) {
66           FileReference* file_ref = ValueCast<FileReference>(config_value->value.get());
67           if (file_ref) {
68             referenced_resources.insert(*file_ref->path);
69           }
70         }
71       }
72     }
73   }
74
75   std::unique_ptr<io::IFileCollectionIterator> iterator = apk_->Iterator();
76   while (iterator->HasNext()) {
77     io::IFile* file = iterator->Next();
78
79     std::string path = file->GetSource().path;
80     // The name of the path has the format "<zip-file-name>@<path-to-file>".
81     path = path.substr(path.find("@") + 1);
82
83     // Skip resources that are not referenced if requested.
84     if (path.find("res/") == 0 && referenced_resources.find(path) == referenced_resources.end()) {
85       if (context->IsVerbose()) {
86         context->GetDiagnostics()->Note(DiagMessage()
87                                         << "Removing resource '" << path << "' from APK.");
88       }
89       continue;
90     }
91
92     // The resource table needs to be re-serialized since it might have changed.
93     if (path == "resources.arsc") {
94       BigBuffer buffer(4096);
95       // TODO(adamlesinski): How to determine if there were sparse entries (and if to encode
96       // with sparse entries) b/35389232.
97       TableFlattener flattener(options, &buffer);
98       if (!flattener.Consume(context, table_.get())) {
99         return false;
100       }
101
102       io::BigBufferInputStream input_stream(&buffer);
103       if (!io::CopyInputStreamToArchive(context, &input_stream, path, ArchiveEntry::kAlign,
104                                         writer)) {
105         return false;
106       }
107
108     } else {
109       uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
110       if (!io::CopyFileToArchive(context, file, path, compression_flags, writer)) {
111         return false;
112       }
113     }
114   }
115   return true;
116 }
117
118 }  // namespace aapt