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 26namespace aapt { 27 28std::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 58bool 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 119