2017-02-01 00:29:25 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "LoadedApk.h"
|
|
|
|
|
2017-02-01 22:47:03 +00:00
|
|
|
#include "ResourceValues.h"
|
|
|
|
#include "ValueVisitor.h"
|
|
|
|
#include "flatten/Archive.h"
|
|
|
|
#include "flatten/TableFlattener.h"
|
|
|
|
|
2017-02-01 00:29:25 +00:00
|
|
|
namespace aapt {
|
|
|
|
|
2017-02-01 22:47:03 +00:00
|
|
|
std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context,
|
|
|
|
const android::StringPiece& path) {
|
2017-02-01 00:29:25 +00:00
|
|
|
Source source(path);
|
|
|
|
std::string error;
|
|
|
|
std::unique_ptr<io::ZipFileCollection> apk =
|
|
|
|
io::ZipFileCollection::Create(path, &error);
|
|
|
|
if (!apk) {
|
|
|
|
context->GetDiagnostics()->Error(DiagMessage(source) << error);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
io::IFile* file = apk->FindFile("resources.arsc");
|
|
|
|
if (!file) {
|
|
|
|
context->GetDiagnostics()->Error(DiagMessage(source)
|
|
|
|
<< "no resources.arsc found");
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<io::IData> data = file->OpenAsData();
|
|
|
|
if (!data) {
|
|
|
|
context->GetDiagnostics()->Error(DiagMessage(source)
|
|
|
|
<< "could not open resources.arsc");
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
|
|
|
|
BinaryResourceParser parser(context, table.get(), source, data->data(),
|
|
|
|
data->size());
|
|
|
|
if (!parser.Parse()) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
|
|
|
|
}
|
|
|
|
|
2017-02-21 14:22:30 -08:00
|
|
|
bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOptions& options,
|
|
|
|
IArchiveWriter* writer) {
|
2017-02-01 22:47:03 +00:00
|
|
|
std::set<std::string> referenced_resources;
|
|
|
|
// List the files being referenced in the resource table.
|
|
|
|
for (auto& pkg : table_->packages) {
|
|
|
|
for (auto& type : pkg->types) {
|
|
|
|
for (auto& entry : type->entries) {
|
|
|
|
for (auto& config_value : entry->values) {
|
|
|
|
FileReference* file_ref = ValueCast<FileReference>(config_value->value.get());
|
|
|
|
if (file_ref) {
|
|
|
|
referenced_resources.insert(*file_ref->path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<io::IFileCollectionIterator> iterator = apk_->Iterator();
|
|
|
|
while (iterator->HasNext()) {
|
|
|
|
io::IFile* file = iterator->Next();
|
|
|
|
|
|
|
|
std::string path = file->GetSource().path;
|
|
|
|
// The name of the path has the format "<zip-file-name>@<path-to-file>".
|
|
|
|
path = path.substr(path.find("@") + 1);
|
|
|
|
|
|
|
|
// Skip resources that are not referenced if requested.
|
|
|
|
if (path.find("res/") == 0 && referenced_resources.find(path) == referenced_resources.end()) {
|
|
|
|
if (context->IsVerbose()) {
|
|
|
|
context->GetDiagnostics()->Note(DiagMessage()
|
2017-02-03 19:15:03 +00:00
|
|
|
<< "Removing resource '" << path << "' from APK.");
|
2017-02-01 22:47:03 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The resource table needs to be reserialized since it might have changed.
|
|
|
|
if (path == "resources.arsc") {
|
|
|
|
BigBuffer buffer = BigBuffer(1024);
|
2017-02-08 07:03:50 -08:00
|
|
|
// TODO(adamlesinski): How to determine if there were sparse entries (and if to encode
|
|
|
|
// with sparse entries) b/35389232.
|
2017-02-21 14:22:30 -08:00
|
|
|
TableFlattener flattener(options, &buffer);
|
2017-02-01 22:47:03 +00:00
|
|
|
if (!flattener.Consume(context, table_.get())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!writer->StartEntry(path, ArchiveEntry::kAlign) || !writer->WriteEntry(buffer) ||
|
|
|
|
!writer->FinishEntry()) {
|
|
|
|
context->GetDiagnostics()->Error(DiagMessage()
|
|
|
|
<< "Error when writing file '" << path << "' in APK.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<io::IData> data = file->OpenAsData();
|
2017-02-03 19:15:03 +00:00
|
|
|
uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
|
|
|
|
if (!writer->StartEntry(path, compression_flags) ||
|
2017-02-01 22:47:03 +00:00
|
|
|
!writer->WriteEntry(data->data(), data->size()) || !writer->FinishEntry()) {
|
|
|
|
context->GetDiagnostics()->Error(DiagMessage()
|
|
|
|
<< "Error when writing file '" << path << "' in APK.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-02-01 00:29:25 +00:00
|
|
|
} // namespace aapt
|