Compile.cpp revision 820d72adc0eccbfe4ac4238cdc89b7680ea03d9e
11ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/* 21ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 31ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * 41ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 51ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * you may not use this file except in compliance with the License. 61ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * You may obtain a copy of the License at 71ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * 81ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 91ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * 101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Unless required by applicable law or agreed to in writing, software 111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * See the License for the specific language governing permissions and 141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * limitations under the License. 151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */ 161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 17ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <dirent.h> 18ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 19ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <fstream> 20ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <string> 21ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 22d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski#include "android-base/errors.h" 23d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski#include "android-base/file.h" 24d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski#include "androidfw/StringPiece.h" 25d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski#include "google/protobuf/io/coded_stream.h" 26d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski#include "google/protobuf/io/zero_copy_stream_impl_lite.h" 27d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski 281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ConfigDescription.h" 291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "Diagnostics.h" 301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "Flags.h" 311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceParser.h" 321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceTable.h" 331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "compile/IdAssigner.h" 345eeaaddffd23d8d85aeb321e3ceea626e42cf9deAdam Lesinski#include "compile/InlineXmlFormatParser.h" 351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "compile/Png.h" 36393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski#include "compile/PseudolocaleGenerator.h" 371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "compile/XmlIdCollector.h" 38a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski#include "flatten/Archive.h" 391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "flatten/XmlFlattener.h" 4006460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski#include "io/BigBufferOutputStream.h" 41d0f492db038c6210c1138865d816bfb134376538Adam Lesinski#include "io/Util.h" 4259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski#include "proto/ProtoSerialize.h" 431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Files.h" 441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Maybe.h" 451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Util.h" 46467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski#include "xml/XmlDom.h" 47467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski#include "xml/XmlPullParser.h" 481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 49d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinskiusing android::StringPiece; 505eeaaddffd23d8d85aeb321e3ceea626e42cf9deAdam Lesinskiusing google::protobuf::io::CopyingOutputStreamAdaptor; 515eeaaddffd23d8d85aeb321e3ceea626e42cf9deAdam Lesinski 521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace aapt { 531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistruct ResourcePathData { 55cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Source source; 56ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string resource_dir; 57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string name; 58cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string extension; 59cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 60cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Original config str. We keep this because when we parse the config, we may 61cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // add on 62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // version qualifiers. We want to preserve the original input so the output is 63cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // easily 64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // computed before hand. 65ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string config_str; 66cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ConfigDescription config; 671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}; 681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/** 701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Resource file paths are expected to look like: 711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * [--/res/]type[-config]/name 721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */ 73ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic Maybe<ResourcePathData> ExtractResourcePathData(const std::string& path, 74ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string* out_error) { 75ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::vector<std::string> parts = util::Split(path, file::sDirSep); 76cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (parts.size() < 2) { 77ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (out_error) *out_error = "bad resource path"; 78cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 79cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 81cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string& dir = parts[parts.size() - 2]; 82ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece dir_str = dir; 83cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 84ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece config_str; 85cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ConfigDescription config; 86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski size_t dash_pos = dir.find('-'); 87ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (dash_pos != std::string::npos) { 88ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski config_str = dir_str.substr(dash_pos + 1, dir.size() - (dash_pos + 1)); 89ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!ConfigDescription::Parse(config_str, &config)) { 90ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (out_error) { 91ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream err_str; 92ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski err_str << "invalid configuration '" << config_str << "'"; 93ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *out_error = err_str.str(); 94cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 95cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 96cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 97ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski dir_str = dir_str.substr(0, dash_pos); 98cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 99cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 100cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string& filename = parts[parts.size() - 1]; 101cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece name = filename; 102cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece extension; 103ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski size_t dot_pos = filename.find('.'); 104ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (dot_pos != std::string::npos) { 105ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski extension = name.substr(dot_pos + 1, filename.size() - (dot_pos + 1)); 106ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski name = name.substr(0, dot_pos); 107cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 108cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 109d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski return ResourcePathData{Source(path), dir_str.to_string(), name.to_string(), 110d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski extension.to_string(), config_str.to_string(), config}; 1111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 1121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistruct CompileOptions { 114ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string output_path; 115ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Maybe<std::string> res_dir; 116cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool pseudolocalize = false; 117ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool legacy_mode = false; 118cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool verbose = false; 1191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}; 1201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 121ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic std::string BuildIntermediateFilename(const ResourcePathData& data) { 122cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::stringstream name; 123ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski name << data.resource_dir; 124ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!data.config_str.empty()) { 125ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski name << "-" << data.config_str; 126cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 127cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski name << "_" << data.name; 128cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!data.extension.empty()) { 129cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski name << "." << data.extension; 130cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 131cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski name << ".flat"; 132cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return name.str(); 133a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski} 134a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 135ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool IsHidden(const StringPiece& filename) { 136ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return util::StartsWith(filename, "."); 137a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski} 138a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 139a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski/** 140a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski * Walks the res directory structure, looking for resource files. 141a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski */ 142d0f492db038c6210c1138865d816bfb134376538Adam Lesinskistatic bool LoadInputFilesFromDir(IAaptContext* context, const CompileOptions& options, 143d0f492db038c6210c1138865d816bfb134376538Adam Lesinski std::vector<ResourcePathData>* out_path_data) { 144ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const std::string& root_dir = options.res_dir.value(); 14506460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski std::unique_ptr<DIR, decltype(closedir)*> d(opendir(root_dir.data()), closedir); 146cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!d) { 14706460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski context->GetDiagnostics()->Error(DiagMessage() 14806460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski << android::base::SystemErrorCodeToString(errno)); 149cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 150cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 151a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 152cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski while (struct dirent* entry = readdir(d.get())) { 153ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (IsHidden(entry->d_name)) { 154cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski continue; 155a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 1569f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 157ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string prefix_path = root_dir; 158ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski file::AppendPath(&prefix_path, entry->d_name); 1599f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 160ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (file::GetFileType(prefix_path) != file::FileType::kDirectory) { 161cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski continue; 1621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 16406460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski std::unique_ptr<DIR, decltype(closedir)*> subdir(opendir(prefix_path.data()), closedir); 165ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!subdir) { 16606460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski context->GetDiagnostics()->Error(DiagMessage() 16706460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski << android::base::SystemErrorCodeToString(errno)); 168cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 169393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } 170393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 171ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski while (struct dirent* leaf_entry = readdir(subdir.get())) { 172ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (IsHidden(leaf_entry->d_name)) { 173cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski continue; 174cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 17583f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski 176ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string full_path = prefix_path; 177ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski file::AppendPath(&full_path, leaf_entry->d_name); 1789ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 179ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string err_str; 18006460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski Maybe<ResourcePathData> path_data = ExtractResourcePathData(full_path, &err_str); 181ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!path_data) { 182ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context->GetDiagnostics()->Error(DiagMessage() << err_str); 1831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 184cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 1851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 186ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out_path_data->push_back(std::move(path_data.value())); 18759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski } 188cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 189cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 190cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} 19159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 192ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool CompileTable(IAaptContext* context, const CompileOptions& options, 193d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const ResourcePathData& path_data, IArchiveWriter* writer, 194ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const std::string& output_path) { 195cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceTable table; 196cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski { 197ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::ifstream fin(path_data.source.path, std::ifstream::binary); 198cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!fin) { 199ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(path_data.source) 20006460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski << android::base::SystemErrorCodeToString(errno)); 201cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 202cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 203cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 204cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Parse the values file from XML. 205ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski xml::XmlPullParser xml_parser(fin); 206cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 207ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceParserOptions parser_options; 208ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski parser_options.error_on_positional_arguments = !options.legacy_mode; 209cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 210cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // If the filename includes donottranslate, then the default translatable is 211cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // false. 212d0f492db038c6210c1138865d816bfb134376538Adam Lesinski parser_options.translatable = path_data.name.find("donottranslate") == std::string::npos; 213cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 214d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ResourceParser res_parser(context->GetDiagnostics(), &table, path_data.source, path_data.config, 215ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski parser_options); 216ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!res_parser.Parse(&xml_parser)) { 217cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 218cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 219cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 220cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski fin.close(); 221cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 222cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 223cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (options.pseudolocalize) { 224cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Generate pseudo-localized strings (en-XA and ar-XB). 225cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // These are created as weak symbols, and are only generated from default 226cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // configuration 227cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // strings and plurals. 228ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski PseudolocaleGenerator pseudolocale_generator; 229ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!pseudolocale_generator.Consume(context, &table)) { 230cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 231cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 232cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 233cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 234cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Ensure we have the compilation package at least. 235ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski table.CreatePackage(context->GetCompilationPackage()); 236cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 237cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Assign an ID to any package that has resources. 238cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (auto& pkg : table.packages) { 239cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!pkg->id) { 240cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // If no package ID was set while parsing (public identifiers), auto 241cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // assign an ID. 242ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski pkg->id = context->GetPackageId(); 243cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 244cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 245cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 246cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Create the file/zip entry. 247ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!writer->StartEntry(output_path, 0)) { 24806460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to open"); 249cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 250cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 251cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 252cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Make sure CopyingOutputStreamAdaptor is deleted before we call 253ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // writer->FinishEntry(). 254cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski { 255cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Wrap our IArchiveWriter with an adaptor that implements the 25606460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski // ZeroCopyOutputStream interface. 257ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CopyingOutputStreamAdaptor copying_adaptor(writer); 258cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 259ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(&table); 260ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!pb_table->SerializeToZeroCopyStream(©ing_adaptor)) { 26106460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write"); 262cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 263cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 264cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 265cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 266ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!writer->FinishEntry()) { 26706460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to finish entry"); 268cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 269cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 270cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 27159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski} 2721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 273d0f492db038c6210c1138865d816bfb134376538Adam Lesinskistatic bool WriteHeaderAndBufferToWriter(const StringPiece& output_path, const ResourceFile& file, 274d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const BigBuffer& buffer, IArchiveWriter* writer, 27559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski IDiagnostics* diag) { 276cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Start the entry so we can write the header. 277ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!writer->StartEntry(output_path, 0)) { 278ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski diag->Error(DiagMessage(output_path) << "failed to open file"); 279cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 280cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 281cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 282cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Make sure CopyingOutputStreamAdaptor is deleted before we call 283ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // writer->FinishEntry(). 284cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski { 285cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Wrap our IArchiveWriter with an adaptor that implements the 28606460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski // ZeroCopyOutputStream interface. 287ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CopyingOutputStreamAdaptor copying_adaptor(writer); 288ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CompiledFileOutputStream output_stream(©ing_adaptor); 289cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 290cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Number of CompiledFiles. 291ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski output_stream.WriteLittleEndian32(1); 292cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 29306460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski std::unique_ptr<pb::CompiledFile> compiled_file = SerializeCompiledFileToPb(file); 294ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski output_stream.WriteCompiledFile(compiled_file.get()); 295ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski output_stream.WriteData(&buffer); 296cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 297ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (output_stream.HadError()) { 298ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski diag->Error(DiagMessage(output_path) << "failed to write data"); 299cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 300cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 301cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 302cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 303ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!writer->FinishEntry()) { 304ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski diag->Error(DiagMessage(output_path) << "failed to finish writing data"); 305cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 306cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 307cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 30859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski} 3091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 310d0f492db038c6210c1138865d816bfb134376538Adam Lesinskistatic bool WriteHeaderAndMmapToWriter(const StringPiece& output_path, const ResourceFile& file, 311d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const android::FileMap& map, IArchiveWriter* writer, 31259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski IDiagnostics* diag) { 313cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Start the entry so we can write the header. 314ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!writer->StartEntry(output_path, 0)) { 315ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski diag->Error(DiagMessage(output_path) << "failed to open file"); 316cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 317cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 318cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 319cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Make sure CopyingOutputStreamAdaptor is deleted before we call 320ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // writer->FinishEntry(). 321cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski { 322cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Wrap our IArchiveWriter with an adaptor that implements the 323ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // ZeroCopyOutputStream interface. 324ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CopyingOutputStreamAdaptor copying_adaptor(writer); 325ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CompiledFileOutputStream output_stream(©ing_adaptor); 326cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 327cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Number of CompiledFiles. 328ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski output_stream.WriteLittleEndian32(1); 329cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 330d0f492db038c6210c1138865d816bfb134376538Adam Lesinski std::unique_ptr<pb::CompiledFile> compiled_file = SerializeCompiledFileToPb(file); 331ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski output_stream.WriteCompiledFile(compiled_file.get()); 332ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski output_stream.WriteData(map.getDataPtr(), map.getDataLength()); 333cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 334ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (output_stream.HadError()) { 335ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski diag->Error(DiagMessage(output_path) << "failed to write data"); 336cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 337cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 338cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 339cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 340ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!writer->FinishEntry()) { 341ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski diag->Error(DiagMessage(output_path) << "failed to finish writing data"); 342cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 343cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 344cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 3451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 347d0f492db038c6210c1138865d816bfb134376538Adam Lesinskistatic bool FlattenXmlToOutStream(IAaptContext* context, const StringPiece& output_path, 348d0f492db038c6210c1138865d816bfb134376538Adam Lesinski xml::XmlResource* xmlres, CompiledFileOutputStream* out) { 349cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski BigBuffer buffer(1024); 350ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski XmlFlattenerOptions xml_flattener_options; 351ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski xml_flattener_options.keep_raw_values = true; 352ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski XmlFlattener flattener(&buffer, xml_flattener_options); 353ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!flattener.Consume(context, xmlres)) { 354cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 355cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 356cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 35706460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski std::unique_ptr<pb::CompiledFile> pb_compiled_file = SerializeCompiledFileToPb(xmlres->file); 358ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out->WriteCompiledFile(pb_compiled_file.get()); 359cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski out->WriteData(&buffer); 360cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 361cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (out->HadError()) { 36206460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to write data"); 363cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 364cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 365cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 3665eeaaddffd23d8d85aeb321e3ceea626e42cf9deAdam Lesinski} 3675eeaaddffd23d8d85aeb321e3ceea626e42cf9deAdam Lesinski 368776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinskistatic bool IsValidFile(IAaptContext* context, const StringPiece& input_path) { 369776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski const file::FileType file_type = file::GetFileType(input_path); 370776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski if (file_type != file::FileType::kRegular && file_type != file::FileType::kSymlink) { 371776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski if (file_type == file::FileType::kDirectory) { 372776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(input_path) 373776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski << "resource file cannot be a directory"); 374776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski } else { 375776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(input_path) 376776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski << "not a valid resource file"); 377776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski } 378776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski return false; 379776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski } 380776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski return true; 381776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski} 382776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski 383ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool CompileXml(IAaptContext* context, const CompileOptions& options, 384d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const ResourcePathData& path_data, IArchiveWriter* writer, 385d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const std::string& output_path) { 386ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (context->IsVerbose()) { 38706460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling XML"); 388cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 389cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 390ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<xml::XmlResource> xmlres; 391cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski { 392ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::ifstream fin(path_data.source.path, std::ifstream::binary); 393cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!fin) { 394ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(path_data.source) 39506460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski << android::base::SystemErrorCodeToString(errno)); 396cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 397cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 398cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 399ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski xmlres = xml::Inflate(&fin, context->GetDiagnostics(), path_data.source); 400cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 401cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski fin.close(); 402cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 403cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 404ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!xmlres) { 405cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 406cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 407cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 408d0f492db038c6210c1138865d816bfb134376538Adam Lesinski xmlres->file.name = ResourceName({}, *ParseResourceType(path_data.resource_dir), path_data.name); 409ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski xmlres->file.config = path_data.config; 410ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski xmlres->file.source = path_data.source; 411cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 412cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Collect IDs that are defined here. 413cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski XmlIdCollector collector; 414ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!collector.Consume(context, xmlres.get())) { 415cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 416cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 417cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 418cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Look for and process any <aapt:attr> tags and create sub-documents. 419ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski InlineXmlFormatParser inline_xml_format_parser; 420ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!inline_xml_format_parser.Consume(context, xmlres.get())) { 421cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 422cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 423cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 424cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Start the entry so we can write the header. 425ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!writer->StartEntry(output_path, 0)) { 426d0f492db038c6210c1138865d816bfb134376538Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to open file"); 427cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 428cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 429cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 430cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Make sure CopyingOutputStreamAdaptor is deleted before we call 431ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski // writer->FinishEntry(). 432cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski { 433cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Wrap our IArchiveWriter with an adaptor that implements the 434cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // ZeroCopyOutputStream 435cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // interface. 436ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CopyingOutputStreamAdaptor copying_adaptor(writer); 437ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski CompiledFileOutputStream output_stream(©ing_adaptor); 438cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 439ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::vector<std::unique_ptr<xml::XmlResource>>& inline_documents = 440ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski inline_xml_format_parser.GetExtractedInlineXmlDocuments(); 441cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 442cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Number of CompiledFiles. 443ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski output_stream.WriteLittleEndian32(1 + inline_documents.size()); 444cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 445d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (!FlattenXmlToOutStream(context, output_path, xmlres.get(), &output_stream)) { 446cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 447cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 448cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 449ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (auto& inline_xml_doc : inline_documents) { 450d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (!FlattenXmlToOutStream(context, output_path, inline_xml_doc.get(), &output_stream)) { 4511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 452cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 4531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 454cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 4551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 456ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!writer->FinishEntry()) { 457d0f492db038c6210c1138865d816bfb134376538Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(output_path) << "failed to finish writing data"); 458cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 459cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 460cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 4611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 4621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 463ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool CompilePng(IAaptContext* context, const CompileOptions& options, 464d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const ResourcePathData& path_data, IArchiveWriter* writer, 465d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const std::string& output_path) { 466ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (context->IsVerbose()) { 467d0f492db038c6210c1138865d816bfb134376538Adam Lesinski context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling PNG"); 468cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 469cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 470cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski BigBuffer buffer(4096); 471ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceFile res_file; 472d0f492db038c6210c1138865d816bfb134376538Adam Lesinski res_file.name = ResourceName({}, *ParseResourceType(path_data.resource_dir), path_data.name); 473ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski res_file.config = path_data.config; 474ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski res_file.source = path_data.source; 475cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 476cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski { 477cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string content; 478ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!android::base::ReadFileToString(path_data.source.path, &content)) { 479d0f492db038c6210c1138865d816bfb134376538Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(path_data.source) 480d0f492db038c6210c1138865d816bfb134376538Adam Lesinski << android::base::SystemErrorCodeToString(errno)); 481cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 482cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 483cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 484ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski BigBuffer crunched_png_buffer(4096); 48506460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski io::BigBufferOutputStream crunched_png_buffer_out(&crunched_png_buffer); 486cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 487cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Ensure that we only keep the chunks we care about if we end up 488cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // using the original PNG instead of the crunched one. 489ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski PngChunkFilter png_chunk_filter(content); 490ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<Image> image = ReadPng(context, &png_chunk_filter); 491cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!image) { 492cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 493cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 494cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 495ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<NinePatch> nine_patch; 496ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (path_data.extension == "9.png") { 497cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string err; 49806460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski nine_patch = NinePatch::Create(image->rows.get(), image->width, image->height, &err); 499ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!nine_patch) { 500ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context->GetDiagnostics()->Error(DiagMessage() << err); 5011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 502cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 503cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 504cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Remove the 1px border around the NinePatch. 505cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Basically the row array is shifted up by 1, and the length is treated 506cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // as height - 2. 507cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // For each row, shift the array to the left by 1, and treat the length as 508cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // width - 2. 509cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski image->width -= 2; 510cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski image->height -= 2; 51106460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski memmove(image->rows.get(), image->rows.get() + 1, image->height * sizeof(uint8_t**)); 512cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (int32_t h = 0; h < image->height; h++) { 513cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski memmove(image->rows[h], image->rows[h] + 4, image->width * 4); 514cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 515cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 516ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (context->IsVerbose()) { 517d0f492db038c6210c1138865d816bfb134376538Adam Lesinski context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "9-patch: " 518d0f492db038c6210c1138865d816bfb134376538Adam Lesinski << *nine_patch); 519cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 520cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 521cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 522cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Write the crunched PNG. 52306460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski if (!WritePng(context, image.get(), nine_patch.get(), &crunched_png_buffer_out, {})) { 524cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 525cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 526cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 527ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (nine_patch != nullptr || 528ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski crunched_png_buffer_out.ByteCount() <= png_chunk_filter.ByteCount()) { 529cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // No matter what, we must use the re-encoded PNG, even if it is larger. 530cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // 9-patch images must be re-encoded since their borders are stripped. 531ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski buffer.AppendBuffer(std::move(crunched_png_buffer)); 532cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 533cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // The re-encoded PNG is larger than the original, and there is 534cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // no mandatory transformation. Use the original. 535ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (context->IsVerbose()) { 53606460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski context->GetDiagnostics()->Note(DiagMessage(path_data.source) 53706460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski << "original PNG is smaller than crunched PNG" 53806460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski << ", using original"); 539cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 540cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 54106460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski png_chunk_filter.Rewind(); 542ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski BigBuffer filtered_png_buffer(4096); 54306460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski io::BigBufferOutputStream filtered_png_buffer_out(&filtered_png_buffer); 54406460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski io::Copy(&filtered_png_buffer_out, &png_chunk_filter); 545ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski buffer.AppendBuffer(std::move(filtered_png_buffer)); 5461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 548ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (context->IsVerbose()) { 54906460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski // For debugging only, use the legacy PNG cruncher and compare the resulting file sizes. 55006460ef0d7072114ea3280e1650f77f55e7223f4Adam Lesinski // This will help catch exotic cases where the new code may generate larger PNGs. 551ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::stringstream legacy_stream(content); 552ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski BigBuffer legacy_buffer(4096); 553ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Png png(context->GetDiagnostics()); 554ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!png.process(path_data.source, &legacy_stream, &legacy_buffer, {})) { 5551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 556cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 557cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 558ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context->GetDiagnostics()->Note(DiagMessage(path_data.source) 559ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski << "legacy=" << legacy_buffer.size() 560cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski << " new=" << buffer.size()); 5611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 562cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 5631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 564ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!WriteHeaderAndBufferToWriter(output_path, res_file, buffer, writer, 565ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context->GetDiagnostics())) { 566cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 567cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 568cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 569cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} 570cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 571ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool CompileFile(IAaptContext* context, const CompileOptions& options, 572d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const ResourcePathData& path_data, IArchiveWriter* writer, 573ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const std::string& output_path) { 574ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (context->IsVerbose()) { 575d0f492db038c6210c1138865d816bfb134376538Adam Lesinski context->GetDiagnostics()->Note(DiagMessage(path_data.source) << "compiling file"); 576cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 577cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 578cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski BigBuffer buffer(256); 579ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceFile res_file; 580d0f492db038c6210c1138865d816bfb134376538Adam Lesinski res_file.name = ResourceName({}, *ParseResourceType(path_data.resource_dir), path_data.name); 581ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski res_file.config = path_data.config; 582ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski res_file.source = path_data.source; 583ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 584ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string error_str; 585ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Maybe<android::FileMap> f = file::MmapPath(path_data.source.path, &error_str); 586cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!f) { 587776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski context->GetDiagnostics()->Error(DiagMessage(path_data.source) << "failed to mmap file: " 588776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski << error_str); 589cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 590cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 591cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 592ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!WriteHeaderAndMmapToWriter(output_path, res_file, f.value(), writer, 593ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context->GetDiagnostics())) { 594cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 595cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 596cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 5971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 5981ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskiclass CompileContext : public IAaptContext { 600cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski public: 601820d72adc0eccbfe4ac4238cdc89b7680ea03d9eChris Warrington CompileContext(IDiagnostics* diagnostics) : diagnostics_(diagnostics) { 602820d72adc0eccbfe4ac4238cdc89b7680ea03d9eChris Warrington } 603820d72adc0eccbfe4ac4238cdc89b7680ea03d9eChris Warrington 604b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski PackageType GetPackageType() override { 605b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski // Every compilation unit starts as an app and then gets linked as potentially something else. 606b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski return PackageType::kApp; 607b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski } 608b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski 609d0f492db038c6210c1138865d816bfb134376538Adam Lesinski void SetVerbose(bool val) { 610d0f492db038c6210c1138865d816bfb134376538Adam Lesinski verbose_ = val; 611d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 612355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski 613d0f492db038c6210c1138865d816bfb134376538Adam Lesinski bool IsVerbose() override { 614d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return verbose_; 615d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 616355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski 617d0f492db038c6210c1138865d816bfb134376538Adam Lesinski IDiagnostics* GetDiagnostics() override { 618820d72adc0eccbfe4ac4238cdc89b7680ea03d9eChris Warrington return diagnostics_; 619d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 6201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 621ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski NameMangler* GetNameMangler() override { 622cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski abort(); 623cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return nullptr; 624cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 6251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 626ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const std::string& GetCompilationPackage() override { 627cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski static std::string empty; 628cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return empty; 629cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 6301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 631d0f492db038c6210c1138865d816bfb134376538Adam Lesinski uint8_t GetPackageId() override { 632d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return 0x0; 633d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 6341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 635ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski SymbolTable* GetExternalSymbols() override { 636cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski abort(); 637cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return nullptr; 638cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 639fb6312fe93a8544e6a95d1c619c8cea3940cbe1aAdam Lesinski 640d0f492db038c6210c1138865d816bfb134376538Adam Lesinski int GetMinSdkVersion() override { 641d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return 0; 642d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 64364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski 644cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski private: 645820d72adc0eccbfe4ac4238cdc89b7680ea03d9eChris Warrington IDiagnostics* diagnostics_; 646ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool verbose_ = false; 6471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}; 6481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 6491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/** 650cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * Entry point for compilation phase. Parses arguments and dispatches to the 651cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * correct steps. 6521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */ 653820d72adc0eccbfe4ac4238cdc89b7680ea03d9eChris Warringtonint Compile(const std::vector<StringPiece>& args, IDiagnostics* diagnostics) { 654820d72adc0eccbfe4ac4238cdc89b7680ea03d9eChris Warrington CompileContext context(diagnostics); 655cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski CompileOptions options; 656cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 657cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool verbose = false; 658cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Flags flags = 659cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Flags() 660ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski .RequiredFlag("-o", "Output path", &options.output_path) 661d0f492db038c6210c1138865d816bfb134376538Adam Lesinski .OptionalFlag("--dir", "Directory to scan for resources", &options.res_dir) 662ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski .OptionalSwitch("--pseudo-localize", 663cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "Generate resources for pseudo-locales " 664cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "(en-XA and ar-XB)", 665cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski &options.pseudolocalize) 666d0f492db038c6210c1138865d816bfb134376538Adam Lesinski .OptionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings", 667d0f492db038c6210c1138865d816bfb134376538Adam Lesinski &options.legacy_mode) 668ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski .OptionalSwitch("-v", "Enables verbose logging", &verbose); 669ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!flags.Parse("aapt2 compile", args, &std::cerr)) { 670cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 1; 671cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 672cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 673ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski context.SetVerbose(verbose); 674cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 675ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<IArchiveWriter> archive_writer; 676cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 677ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::vector<ResourcePathData> input_data; 678ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (options.res_dir) { 679ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!flags.GetArgs().empty()) { 680cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Can't have both files and a resource directory. 681d0f492db038c6210c1138865d816bfb134376538Adam Lesinski context.GetDiagnostics()->Error(DiagMessage() << "files given but --dir specified"); 682ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski flags.Usage("aapt2 compile", &std::cerr); 683cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 1; 684cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 685cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 686ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!LoadInputFilesFromDir(&context, options, &input_data)) { 687cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 1; 688cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 689cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 690d0f492db038c6210c1138865d816bfb134376538Adam Lesinski archive_writer = CreateZipFileArchiveWriter(context.GetDiagnostics(), options.output_path); 691cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 692cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 693ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski input_data.reserve(flags.GetArgs().size()); 694cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 695cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Collect data from the path for each input file. 696ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (const std::string& arg : flags.GetArgs()) { 697ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string error_str; 698d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (Maybe<ResourcePathData> path_data = ExtractResourcePathData(arg, &error_str)) { 699ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski input_data.push_back(std::move(path_data.value())); 700cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 701d0f492db038c6210c1138865d816bfb134376538Adam Lesinski context.GetDiagnostics()->Error(DiagMessage() << error_str << " (" << arg << ")"); 7021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return 1; 703cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 7041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 7051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 706d0f492db038c6210c1138865d816bfb134376538Adam Lesinski archive_writer = CreateDirectoryArchiveWriter(context.GetDiagnostics(), options.output_path); 707cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 708355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski 709ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!archive_writer) { 710dfaecafbe9fb7c5800191edfe3aa5d5938705204Adam Lesinski return 1; 711cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 7121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 713cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool error = false; 714ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (ResourcePathData& path_data : input_data) { 715cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (options.verbose) { 716d0f492db038c6210c1138865d816bfb134376538Adam Lesinski context.GetDiagnostics()->Note(DiagMessage(path_data.source) << "processing"); 717cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 7181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 719776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski if (!IsValidFile(&context, path_data.source.path)) { 720776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski error = true; 721776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski continue; 722776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski } 723776aa959c7122f23f3c58443ea1b673127ed01f2Adam Lesinski 724ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (path_data.resource_dir == "values") { 725cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Overwrite the extension. 726ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski path_data.extension = "arsc"; 727a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 728ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const std::string output_filename = BuildIntermediateFilename(path_data); 729d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (!CompileTable(&context, options, path_data, archive_writer.get(), output_filename)) { 730cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski error = true; 731cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 732a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 733a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } else { 734ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const std::string output_filename = BuildIntermediateFilename(path_data); 735d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (const ResourceType* type = ParseResourceType(path_data.resource_dir)) { 736cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (*type != ResourceType::kRaw) { 737ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (path_data.extension == "xml") { 738d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (!CompileXml(&context, options, path_data, archive_writer.get(), output_filename)) { 739cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski error = true; 740a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 741d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } else if (path_data.extension == "png" || path_data.extension == "9.png") { 742d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (!CompilePng(&context, options, path_data, archive_writer.get(), output_filename)) { 743cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski error = true; 7441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 745cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 746d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (!CompileFile(&context, options, path_data, archive_writer.get(), output_filename)) { 747cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski error = true; 7481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 749cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 750cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 751d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (!CompileFile(&context, options, path_data, archive_writer.get(), output_filename)) { 752cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski error = true; 753cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 7541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 755cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 756d0f492db038c6210c1138865d816bfb134376538Adam Lesinski context.GetDiagnostics()->Error(DiagMessage() << "invalid file path '" << path_data.source 757d0f492db038c6210c1138865d816bfb134376538Adam Lesinski << "'"); 758cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski error = true; 759cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 760cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 761cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 762cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 763cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (error) { 764cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 1; 765cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 766cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 0; 7671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 7681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 769cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} // namespace aapt 770