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 171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ConfigDescription.h" 181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "Diagnostics.h" 191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "Flags.h" 201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceParser.h" 211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceTable.h" 221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "compile/IdAssigner.h" 231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "compile/Png.h" 24393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski#include "compile/PseudolocaleGenerator.h" 251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "compile/XmlIdCollector.h" 26a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski#include "flatten/Archive.h" 271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "flatten/XmlFlattener.h" 2859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski#include "proto/ProtoSerialize.h" 291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Files.h" 301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Maybe.h" 311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Util.h" 32467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski#include "xml/XmlDom.h" 33467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski#include "xml/XmlPullParser.h" 341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 3559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski#include <google/protobuf/io/zero_copy_stream_impl_lite.h> 3659e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski#include <google/protobuf/io/coded_stream.h> 3759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 38a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski#include <dirent.h> 391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <fstream> 401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <string> 411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace aapt { 431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistruct ResourcePathData { 451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Source source; 461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::u16string resourceDir; 471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::u16string name; 481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::string extension; 491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // Original config str. We keep this because when we parse the config, we may add on 511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // version qualifiers. We want to preserve the original input so the output is easily 521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // computed before hand. 531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::string configStr; 541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ConfigDescription config; 551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}; 561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/** 581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Resource file paths are expected to look like: 591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * [--/res/]type[-config]/name 601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */ 611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistatic Maybe<ResourcePathData> extractResourcePathData(const std::string& path, 621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::string* outError) { 631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::vector<std::string> parts = util::split(path, file::sDirSep); 641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (parts.size() < 2) { 651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (outError) *outError = "bad resource path"; 661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return {}; 671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::string& dir = parts[parts.size() - 2]; 701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski StringPiece dirStr = dir; 711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski StringPiece configStr; 731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ConfigDescription config; 741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski size_t dashPos = dir.find('-'); 751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (dashPos != std::string::npos) { 761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski configStr = dirStr.substr(dashPos + 1, dir.size() - (dashPos + 1)); 771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!ConfigDescription::parse(configStr, &config)) { 781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (outError) { 791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::stringstream errStr; 801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski errStr << "invalid configuration '" << configStr << "'"; 811ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *outError = errStr.str(); 821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return {}; 841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski dirStr = dirStr.substr(0, dashPos); 861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 871ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 881ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::string& filename = parts[parts.size() - 1]; 891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski StringPiece name = filename; 901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski StringPiece extension; 911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski size_t dotPos = filename.find('.'); 921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (dotPos != std::string::npos) { 931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski extension = name.substr(dotPos + 1, filename.size() - (dotPos + 1)); 941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski name = name.substr(0, dotPos); 951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return ResourcePathData{ 98a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski Source(path), 991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski util::utf8ToUtf16(dirStr), 1001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski util::utf8ToUtf16(name), 1011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski extension.toString(), 1021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski configStr.toString(), 1031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski config 1041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski }; 1051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 1061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistruct CompileOptions { 1081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::string outputPath; 109a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski Maybe<std::string> resDir; 110393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski bool pseudolocalize = false; 111979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski bool legacyMode = false; 1121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski bool verbose = false; 1131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}; 1141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 115a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinskistatic std::string buildIntermediateFilename(const ResourcePathData& data) { 1161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::stringstream name; 1171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski name << data.resourceDir; 1181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!data.configStr.empty()) { 1191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski name << "-" << data.configStr; 1201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 12152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski name << "_" << data.name; 12252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski if (!data.extension.empty()) { 12352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski name << "." << data.extension; 12452364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski } 12552364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski name << ".flat"; 126a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski return name.str(); 127a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski} 128a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 129a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinskistatic bool isHidden(const StringPiece& filename) { 130a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski return util::stringStartsWith<char>(filename, "."); 131a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski} 132a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 133a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski/** 134a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski * Walks the res directory structure, looking for resource files. 135a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski */ 136a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinskistatic bool loadInputFilesFromDir(IAaptContext* context, const CompileOptions& options, 137a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski std::vector<ResourcePathData>* outPathData) { 138a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const std::string& rootDir = options.resDir.value(); 139a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski std::unique_ptr<DIR, decltype(closedir)*> d(opendir(rootDir.data()), closedir); 140a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!d) { 141a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski context->getDiagnostics()->error(DiagMessage() << strerror(errno)); 142a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski return false; 143a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 144a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 145a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski while (struct dirent* entry = readdir(d.get())) { 146a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (isHidden(entry->d_name)) { 147a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski continue; 148a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 149a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 150a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski std::string prefixPath = rootDir; 151a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski file::appendPath(&prefixPath, entry->d_name); 152a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 153a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (file::getFileType(prefixPath) != file::FileType::kDirectory) { 154a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski continue; 155a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 156a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 157a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski std::unique_ptr<DIR, decltype(closedir)*> subDir(opendir(prefixPath.data()), closedir); 158a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!subDir) { 159a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski context->getDiagnostics()->error(DiagMessage() << strerror(errno)); 160a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski return false; 161a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 162a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 163a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski while (struct dirent* leafEntry = readdir(subDir.get())) { 164a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (isHidden(leafEntry->d_name)) { 165a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski continue; 166a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 167a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 168a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski std::string fullPath = prefixPath; 169a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski file::appendPath(&fullPath, leafEntry->d_name); 170a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 171a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski std::string errStr; 172a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski Maybe<ResourcePathData> pathData = extractResourcePathData(fullPath, &errStr); 173a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!pathData) { 174a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski context->getDiagnostics()->error(DiagMessage() << errStr); 175a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski return false; 176a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 177a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 178a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski outPathData->push_back(std::move(pathData.value())); 179a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 180a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 181a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski return true; 1821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 1831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistatic bool compileTable(IAaptContext* context, const CompileOptions& options, 185a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const ResourcePathData& pathData, IArchiveWriter* writer, 186a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const std::string& outputPath) { 1871ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ResourceTable table; 1881ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski { 1891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::ifstream fin(pathData.source.path, std::ifstream::binary); 1901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!fin) { 1911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski context->getDiagnostics()->error(DiagMessage(pathData.source) << strerror(errno)); 1921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 1931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // Parse the values file from XML. 197467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski xml::XmlPullParser xmlParser(fin); 1989f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 1999f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski ResourceParserOptions parserOptions; 200979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski parserOptions.errorOnPositionalArguments = !options.legacyMode; 2019f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 2029f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski // If the filename includes donottranslate, then the default translatable is false. 2039f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski parserOptions.translatable = pathData.name.find(u"donottranslate") == std::string::npos; 2049f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 2051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ResourceParser resParser(context->getDiagnostics(), &table, pathData.source, 2069f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski pathData.config, parserOptions); 2071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!resParser.parse(&xmlParser)) { 2081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 2091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 2101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 2111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski fin.close(); 2121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 2131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 214393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski if (options.pseudolocalize) { 215393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski // Generate pseudo-localized strings (en-XA and ar-XB). 216393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski // These are created as weak symbols, and are only generated from default configuration 217393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski // strings and plurals. 218393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski PseudolocaleGenerator pseudolocaleGenerator; 219393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski if (!pseudolocaleGenerator.consume(context, &table)) { 220393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski return false; 221393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } 222393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } 223393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 22483f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski // Ensure we have the compilation package at least. 22583f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski table.createPackage(context->getCompilationPackage()); 22683f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski 227a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski // Assign an ID to any package that has resources. 22883f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski for (auto& pkg : table.packages) { 22983f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski if (!pkg->id) { 23083f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski // If no package ID was set while parsing (public identifiers), auto assign an ID. 23183f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski pkg->id = context->getPackageId(); 23283f2255f69729e0e97539e96e5e6161843e85823Adam Lesinski } 2339ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski } 2349ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 23559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // Create the file/zip entry. 23659e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!writer->startEntry(outputPath, 0)) { 23759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open"); 2381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 2391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 2401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 24159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(&table); 24259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 24359e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream interface. 24459e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski { 24559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer); 24659e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 24759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!pbTable->SerializeToZeroCopyStream(&adaptor)) { 24859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write"); 24959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return false; 25059e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski } 25159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski } 25259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 25359e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!writer->finishEntry()) { 25459e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to finish entry"); 2551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 2561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 25759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return true; 25859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski} 2591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 26059e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinskistatic bool writeHeaderAndBufferToWriter(const StringPiece& outputPath, const ResourceFile& file, 26159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski const BigBuffer& buffer, IArchiveWriter* writer, 26259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski IDiagnostics* diag) { 26359e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // Start the entry so we can write the header. 264a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!writer->startEntry(outputPath, 0)) { 26559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski diag->error(DiagMessage(outputPath) << "failed to open file"); 26659e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return false; 26759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski } 26859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 26959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // Create the header. 27059e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski std::unique_ptr<pb::CompiledFile> pbCompiledFile = serializeCompiledFileToPb(file); 27159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 27259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski { 27359e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // The stream must be destroyed before we finish the entry, or else 27459e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // some data won't be flushed. 27559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream 27659e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // interface. 27759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer); 27859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski CompiledFileOutputStream outputStream(&adaptor, pbCompiledFile.get()); 27959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski for (const BigBuffer::Block& block : buffer) { 28059e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!outputStream.Write(block.buffer.get(), block.size)) { 28159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski diag->error(DiagMessage(outputPath) << "failed to write data"); 28259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return false; 28359e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski } 28459e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski } 28559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski } 28659e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 28759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!writer->finishEntry()) { 28859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski diag->error(DiagMessage(outputPath) << "failed to finish writing data"); 2891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 2901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 29159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return true; 29259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski} 2931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 29459e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinskistatic bool writeHeaderAndMmapToWriter(const StringPiece& outputPath, const ResourceFile& file, 29559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski const android::FileMap& map, IArchiveWriter* writer, 29659e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski IDiagnostics* diag) { 29759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // Start the entry so we can write the header. 29859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!writer->startEntry(outputPath, 0)) { 29959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski diag->error(DiagMessage(outputPath) << "failed to open file"); 30059e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return false; 30159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski } 30259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 30359e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // Create the header. 30459e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski std::unique_ptr<pb::CompiledFile> pbCompiledFile = serializeCompiledFileToPb(file); 30559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 30659e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski { 30759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // The stream must be destroyed before we finish the entry, or else 30859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // some data won't be flushed. 30959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream 31059e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski // interface. 31159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer); 31259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski CompiledFileOutputStream outputStream(&adaptor, pbCompiledFile.get()); 31359e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!outputStream.Write(map.getDataPtr(), map.getDataLength())) { 31459e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski diag->error(DiagMessage(outputPath) << "failed to write data"); 31559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return false; 316a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 3171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 318a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 31959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!writer->finishEntry()) { 32059e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski diag->error(DiagMessage(outputPath) << "failed to finish writing data"); 32159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return false; 32259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski } 32359e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return true; 3241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 3261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistatic bool compileXml(IAaptContext* context, const CompileOptions& options, 327a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const ResourcePathData& pathData, IArchiveWriter* writer, 328a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const std::string& outputPath) { 3291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 330467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski std::unique_ptr<xml::XmlResource> xmlRes; 3311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski { 3321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::ifstream fin(pathData.source.path, std::ifstream::binary); 3331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!fin) { 3341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski context->getDiagnostics()->error(DiagMessage(pathData.source) << strerror(errno)); 3351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 3361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 3371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 3381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski xmlRes = xml::inflate(&fin, context->getDiagnostics(), pathData.source); 3391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 3401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski fin.close(); 3411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 3421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 3431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!xmlRes) { 3441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 3451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 3461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 3471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // Collect IDs that are defined here. 3481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski XmlIdCollector collector; 3491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!collector.consume(context, xmlRes.get())) { 3501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 3511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 3521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 353a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski xmlRes->file.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name); 3541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski xmlRes->file.config = pathData.config; 3551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski xmlRes->file.source = pathData.source; 3561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 3571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski BigBuffer buffer(1024); 3581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski XmlFlattenerOptions xmlFlattenerOptions; 3591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski xmlFlattenerOptions.keepRawValues = true; 36059e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski XmlFlattener flattener(&buffer, xmlFlattenerOptions); 3611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!flattener.consume(context, xmlRes.get())) { 3621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 3631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 3641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 36559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!writeHeaderAndBufferToWriter(outputPath, xmlRes->file, buffer, writer, 36659e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski context->getDiagnostics())) { 3671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 3681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 36959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return true; 3701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 3721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistatic bool compilePng(IAaptContext* context, const CompileOptions& options, 373a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const ResourcePathData& pathData, IArchiveWriter* writer, 374a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const std::string& outputPath) { 3751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski BigBuffer buffer(4096); 3761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ResourceFile resFile; 377a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name); 3781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski resFile.config = pathData.config; 3791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski resFile.source = pathData.source; 3801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 3811ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski { 3821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::ifstream fin(pathData.source.path, std::ifstream::binary); 3831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!fin) { 3841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski context->getDiagnostics()->error(DiagMessage(pathData.source) << strerror(errno)); 3851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 3861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 3871ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 3881ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Png png(context->getDiagnostics()); 38959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!png.process(pathData.source, &fin, &buffer, {})) { 3901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 3911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 3921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 3931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 39459e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!writeHeaderAndBufferToWriter(outputPath, resFile, buffer, writer, 39559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski context->getDiagnostics())) { 3961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 3971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 39859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski return true; 3991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 4001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistatic bool compileFile(IAaptContext* context, const CompileOptions& options, 402a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const ResourcePathData& pathData, IArchiveWriter* writer, 403a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const std::string& outputPath) { 4041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski BigBuffer buffer(256); 4051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ResourceFile resFile; 406a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name); 4071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski resFile.config = pathData.config; 4081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski resFile.source = pathData.source; 4091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::string errorStr; 4111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Maybe<android::FileMap> f = file::mmapPath(pathData.source.path, &errorStr); 4121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!f) { 4131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski context->getDiagnostics()->error(DiagMessage(pathData.source) << errorStr); 4141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 4151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 4161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 41759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski if (!writeHeaderAndMmapToWriter(outputPath, resFile, f.value(), writer, 41859e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski context->getDiagnostics())) { 41952364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski return false; 42052364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski } 42152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski return true; 4221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 4231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskiclass CompileContext : public IAaptContext { 4251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskipublic: 426355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski void setVerbose(bool val) { 427355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski mVerbose = val; 428355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski } 429355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski 430355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski bool verbose() override { 431355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski return mVerbose; 432355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski } 433355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski 4341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski IDiagnostics* getDiagnostics() override { 4351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return &mDiagnostics; 4361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 4371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski NameMangler* getNameMangler() override { 4391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski abort(); 4401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return nullptr; 4411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 4421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 44364587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski const std::u16string& getCompilationPackage() override { 44464587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski static std::u16string empty; 44564587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski return empty; 4461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 4471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski uint8_t getPackageId() override { 4499ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return 0x0; 4501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 4511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 45264587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski SymbolTable* getExternalSymbols() override { 4531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski abort(); 4541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return nullptr; 4551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 45664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski 45764587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinskiprivate: 45864587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski StdErrDiagnostics mDiagnostics; 45964587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski bool mVerbose = false; 46064587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski 4611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}; 4621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/** 4641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Entry point for compilation phase. Parses arguments and dispatches to the correct steps. 4651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */ 4661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskiint compile(const std::vector<StringPiece>& args) { 467355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski CompileContext context; 4681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski CompileOptions options; 4691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 470355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski bool verbose = false; 4711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Flags flags = Flags() 4721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski .requiredFlag("-o", "Output path", &options.outputPath) 473a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski .optionalFlag("--dir", "Directory to scan for resources", &options.resDir) 474393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski .optionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales " 475393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski "(en-XA and ar-XB)", &options.pseudolocalize) 476979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski .optionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings", 477979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski &options.legacyMode) 478355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski .optionalSwitch("-v", "Enables verbose logging", &verbose); 4791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!flags.parse("aapt2 compile", args, &std::cerr)) { 4801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return 1; 4811ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 4821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 483355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski context.setVerbose(verbose); 484355f285ffd000f6cfe76680eb22d010546d124bbAdam Lesinski 485a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski std::unique_ptr<IArchiveWriter> archiveWriter; 4861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 4871ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::vector<ResourcePathData> inputData; 488a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (options.resDir) { 489a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!flags.getArgs().empty()) { 490a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski // Can't have both files and a resource directory. 491a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski context.getDiagnostics()->error(DiagMessage() << "files given but --dir specified"); 492a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski flags.usage("aapt2 compile", &std::cerr); 493a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski return 1; 494a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 4951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 496a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!loadInputFilesFromDir(&context, options, &inputData)) { 4971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return 1; 4981ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 499a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 500a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski archiveWriter = createZipFileArchiveWriter(context.getDiagnostics(), options.outputPath); 501a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 502a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } else { 503a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski inputData.reserve(flags.getArgs().size()); 504a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 505a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski // Collect data from the path for each input file. 506a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski for (const std::string& arg : flags.getArgs()) { 507a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski std::string errorStr; 508a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (Maybe<ResourcePathData> pathData = extractResourcePathData(arg, &errorStr)) { 509a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski inputData.push_back(std::move(pathData.value())); 510a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } else { 511a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski context.getDiagnostics()->error(DiagMessage() << errorStr << " (" << arg << ")"); 512a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski return 1; 513a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 514a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 515a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 516a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski archiveWriter = createDirectoryArchiveWriter(context.getDiagnostics(), options.outputPath); 517a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski } 518a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski 519a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!archiveWriter) { 520a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski return false; 5211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski bool error = false; 5241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski for (ResourcePathData& pathData : inputData) { 5251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (options.verbose) { 5261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski context.getDiagnostics()->note(DiagMessage(pathData.source) << "processing"); 5271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (pathData.resourceDir == u"values") { 5301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // Overwrite the extension. 5311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski pathData.extension = "arsc"; 5321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 533a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const std::string outputFilename = buildIntermediateFilename(pathData); 534a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!compileTable(&context, options, pathData, archiveWriter.get(), outputFilename)) { 5351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 5361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else { 539a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski const std::string outputFilename = buildIntermediateFilename(pathData); 5401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (const ResourceType* type = parseResourceType(pathData.resourceDir)) { 5411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (*type != ResourceType::kRaw) { 5421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (pathData.extension == "xml") { 543a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!compileXml(&context, options, pathData, archiveWriter.get(), 544a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski outputFilename)) { 5451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 5461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else if (pathData.extension == "png" || pathData.extension == "9.png") { 548a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!compilePng(&context, options, pathData, archiveWriter.get(), 549a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski outputFilename)) { 5501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 5511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else { 553a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!compileFile(&context, options, pathData, archiveWriter.get(), 554a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski outputFilename)) { 5551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 5561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else { 559a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski if (!compileFile(&context, options, pathData, archiveWriter.get(), 560a40e972fdaa68fc486ff90a319195515819068b2Adam Lesinski outputFilename)) { 5611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 5621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else { 5651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski context.getDiagnostics()->error( 5661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski DiagMessage() << "invalid file path '" << pathData.source << "'"); 5671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 5681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (error) { 5731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return 1; 5741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return 0; 5761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 5771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} // namespace aapt 579