blob: 1eefb821768e8eefcfc73c90b9e817b44faa7e83 [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "ConfigDescription.h"
18#include "Diagnostics.h"
19#include "Flags.h"
20#include "ResourceParser.h"
21#include "ResourceTable.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070022#include "compile/IdAssigner.h"
23#include "compile/Png.h"
Adam Lesinski393b5f02015-12-17 13:03:11 -080024#include "compile/PseudolocaleGenerator.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070025#include "compile/XmlIdCollector.h"
Adam Lesinskia40e9722015-11-24 19:11:46 -080026#include "flatten/Archive.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070027#include "flatten/XmlFlattener.h"
Adam Lesinski59e04c62016-02-04 15:59:23 -080028#include "proto/ProtoSerialize.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070029#include "util/Files.h"
30#include "util/Maybe.h"
31#include "util/Util.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080032#include "xml/XmlDom.h"
33#include "xml/XmlPullParser.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070034
Adam Lesinski59e04c62016-02-04 15:59:23 -080035#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
36#include <google/protobuf/io/coded_stream.h>
37
Adam Lesinskia40e9722015-11-24 19:11:46 -080038#include <dirent.h>
Adam Lesinski1ab598f2015-08-14 14:26:04 -070039#include <fstream>
40#include <string>
41
42namespace aapt {
43
44struct ResourcePathData {
45 Source source;
46 std::u16string resourceDir;
47 std::u16string name;
48 std::string extension;
49
50 // Original config str. We keep this because when we parse the config, we may add on
51 // version qualifiers. We want to preserve the original input so the output is easily
52 // computed before hand.
53 std::string configStr;
54 ConfigDescription config;
55};
56
57/**
58 * Resource file paths are expected to look like:
59 * [--/res/]type[-config]/name
60 */
61static Maybe<ResourcePathData> extractResourcePathData(const std::string& path,
62 std::string* outError) {
63 std::vector<std::string> parts = util::split(path, file::sDirSep);
64 if (parts.size() < 2) {
65 if (outError) *outError = "bad resource path";
66 return {};
67 }
68
69 std::string& dir = parts[parts.size() - 2];
70 StringPiece dirStr = dir;
71
72 StringPiece configStr;
73 ConfigDescription config;
74 size_t dashPos = dir.find('-');
75 if (dashPos != std::string::npos) {
76 configStr = dirStr.substr(dashPos + 1, dir.size() - (dashPos + 1));
77 if (!ConfigDescription::parse(configStr, &config)) {
78 if (outError) {
79 std::stringstream errStr;
80 errStr << "invalid configuration '" << configStr << "'";
81 *outError = errStr.str();
82 }
83 return {};
84 }
85 dirStr = dirStr.substr(0, dashPos);
86 }
87
88 std::string& filename = parts[parts.size() - 1];
89 StringPiece name = filename;
90 StringPiece extension;
91 size_t dotPos = filename.find('.');
92 if (dotPos != std::string::npos) {
93 extension = name.substr(dotPos + 1, filename.size() - (dotPos + 1));
94 name = name.substr(0, dotPos);
95 }
96
97 return ResourcePathData{
Adam Lesinskia40e9722015-11-24 19:11:46 -080098 Source(path),
Adam Lesinski1ab598f2015-08-14 14:26:04 -070099 util::utf8ToUtf16(dirStr),
100 util::utf8ToUtf16(name),
101 extension.toString(),
102 configStr.toString(),
103 config
104 };
105}
106
107struct CompileOptions {
108 std::string outputPath;
Adam Lesinskia40e9722015-11-24 19:11:46 -0800109 Maybe<std::string> resDir;
Adam Lesinski7751afc2016-01-06 15:45:28 -0800110 std::vector<std::u16string> products;
Adam Lesinski393b5f02015-12-17 13:03:11 -0800111 bool pseudolocalize = false;
Adam Lesinski979ccb22016-01-11 10:42:19 -0800112 bool legacyMode = false;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700113 bool verbose = false;
114};
115
Adam Lesinskia40e9722015-11-24 19:11:46 -0800116static std::string buildIntermediateFilename(const ResourcePathData& data) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700117 std::stringstream name;
118 name << data.resourceDir;
119 if (!data.configStr.empty()) {
120 name << "-" << data.configStr;
121 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800122 name << "_" << data.name;
123 if (!data.extension.empty()) {
124 name << "." << data.extension;
125 }
126 name << ".flat";
Adam Lesinskia40e9722015-11-24 19:11:46 -0800127 return name.str();
128}
129
130static bool isHidden(const StringPiece& filename) {
131 return util::stringStartsWith<char>(filename, ".");
132}
133
134/**
135 * Walks the res directory structure, looking for resource files.
136 */
137static bool loadInputFilesFromDir(IAaptContext* context, const CompileOptions& options,
138 std::vector<ResourcePathData>* outPathData) {
139 const std::string& rootDir = options.resDir.value();
140 std::unique_ptr<DIR, decltype(closedir)*> d(opendir(rootDir.data()), closedir);
141 if (!d) {
142 context->getDiagnostics()->error(DiagMessage() << strerror(errno));
143 return false;
144 }
145
146 while (struct dirent* entry = readdir(d.get())) {
147 if (isHidden(entry->d_name)) {
148 continue;
149 }
150
151 std::string prefixPath = rootDir;
152 file::appendPath(&prefixPath, entry->d_name);
153
154 if (file::getFileType(prefixPath) != file::FileType::kDirectory) {
155 continue;
156 }
157
158 std::unique_ptr<DIR, decltype(closedir)*> subDir(opendir(prefixPath.data()), closedir);
159 if (!subDir) {
160 context->getDiagnostics()->error(DiagMessage() << strerror(errno));
161 return false;
162 }
163
164 while (struct dirent* leafEntry = readdir(subDir.get())) {
165 if (isHidden(leafEntry->d_name)) {
166 continue;
167 }
168
169 std::string fullPath = prefixPath;
170 file::appendPath(&fullPath, leafEntry->d_name);
171
172 std::string errStr;
173 Maybe<ResourcePathData> pathData = extractResourcePathData(fullPath, &errStr);
174 if (!pathData) {
175 context->getDiagnostics()->error(DiagMessage() << errStr);
176 return false;
177 }
178
179 outPathData->push_back(std::move(pathData.value()));
180 }
181 }
182 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700183}
184
185static bool compileTable(IAaptContext* context, const CompileOptions& options,
Adam Lesinskia40e9722015-11-24 19:11:46 -0800186 const ResourcePathData& pathData, IArchiveWriter* writer,
187 const std::string& outputPath) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700188 ResourceTable table;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700189 {
190 std::ifstream fin(pathData.source.path, std::ifstream::binary);
191 if (!fin) {
192 context->getDiagnostics()->error(DiagMessage(pathData.source) << strerror(errno));
193 return false;
194 }
195
196
197 // Parse the values file from XML.
Adam Lesinski467f1712015-11-16 17:35:44 -0800198 xml::XmlPullParser xmlParser(fin);
Adam Lesinski9f222042015-11-04 13:51:45 -0800199
200 ResourceParserOptions parserOptions;
Adam Lesinski7751afc2016-01-06 15:45:28 -0800201 parserOptions.products = options.products;
Adam Lesinski979ccb22016-01-11 10:42:19 -0800202 parserOptions.errorOnPositionalArguments = !options.legacyMode;
Adam Lesinski9f222042015-11-04 13:51:45 -0800203
204 // If the filename includes donottranslate, then the default translatable is false.
205 parserOptions.translatable = pathData.name.find(u"donottranslate") == std::string::npos;
206
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700207 ResourceParser resParser(context->getDiagnostics(), &table, pathData.source,
Adam Lesinski9f222042015-11-04 13:51:45 -0800208 pathData.config, parserOptions);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700209 if (!resParser.parse(&xmlParser)) {
210 return false;
211 }
212
213 fin.close();
214 }
215
Adam Lesinski393b5f02015-12-17 13:03:11 -0800216 if (options.pseudolocalize) {
217 // Generate pseudo-localized strings (en-XA and ar-XB).
218 // These are created as weak symbols, and are only generated from default configuration
219 // strings and plurals.
220 PseudolocaleGenerator pseudolocaleGenerator;
221 if (!pseudolocaleGenerator.consume(context, &table)) {
222 return false;
223 }
224 }
225
Adam Lesinski83f22552015-11-07 11:51:23 -0800226 // Ensure we have the compilation package at least.
227 table.createPackage(context->getCompilationPackage());
228
Adam Lesinskia40e9722015-11-24 19:11:46 -0800229 // Assign an ID to any package that has resources.
Adam Lesinski83f22552015-11-07 11:51:23 -0800230 for (auto& pkg : table.packages) {
231 if (!pkg->id) {
232 // If no package ID was set while parsing (public identifiers), auto assign an ID.
233 pkg->id = context->getPackageId();
234 }
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700235 }
236
Adam Lesinski59e04c62016-02-04 15:59:23 -0800237 // Create the file/zip entry.
Adam Lesinskia40e9722015-11-24 19:11:46 -0800238 if (!writer->startEntry(outputPath, 0)) {
239 context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open");
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700240 return false;
241 }
242
Adam Lesinski59e04c62016-02-04 15:59:23 -0800243 std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(&table);
244
245 // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream interface.
246 {
247 google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
248
249 if (!pbTable->SerializeToZeroCopyStream(&adaptor)) {
250 context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write");
251 return false;
Adam Lesinskia40e9722015-11-24 19:11:46 -0800252 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700253 }
Adam Lesinskia40e9722015-11-24 19:11:46 -0800254
Adam Lesinski59e04c62016-02-04 15:59:23 -0800255 if (!writer->finishEntry()) {
256 context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to finish entry");
257 return false;
258 }
259 return true;
260}
261
262static bool writeHeaderAndBufferToWriter(const StringPiece& outputPath, const ResourceFile& file,
263 const BigBuffer& buffer, IArchiveWriter* writer,
264 IDiagnostics* diag) {
265 // Start the entry so we can write the header.
266 if (!writer->startEntry(outputPath, 0)) {
267 diag->error(DiagMessage(outputPath) << "failed to open file");
268 return false;
269 }
270
271 // Create the header.
272 std::unique_ptr<pb::CompiledFile> pbCompiledFile = serializeCompiledFileToPb(file);
273
274 {
275 // The stream must be destroyed before we finish the entry, or else
276 // some data won't be flushed.
277 // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
278 // interface.
279 google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
280 CompiledFileOutputStream outputStream(&adaptor, pbCompiledFile.get());
281 for (const BigBuffer::Block& block : buffer) {
282 if (!outputStream.Write(block.buffer.get(), block.size)) {
283 diag->error(DiagMessage(outputPath) << "failed to write data");
284 return false;
285 }
286 }
287 }
288
289 if (!writer->finishEntry()) {
290 diag->error(DiagMessage(outputPath) << "failed to finish writing data");
291 return false;
292 }
293 return true;
294}
295
296static bool writeHeaderAndMmapToWriter(const StringPiece& outputPath, const ResourceFile& file,
297 const android::FileMap& map, IArchiveWriter* writer,
298 IDiagnostics* diag) {
299 // Start the entry so we can write the header.
300 if (!writer->startEntry(outputPath, 0)) {
301 diag->error(DiagMessage(outputPath) << "failed to open file");
302 return false;
303 }
304
305 // Create the header.
306 std::unique_ptr<pb::CompiledFile> pbCompiledFile = serializeCompiledFileToPb(file);
307
308 {
309 // The stream must be destroyed before we finish the entry, or else
310 // some data won't be flushed.
311 // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
312 // interface.
313 google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
314 CompiledFileOutputStream outputStream(&adaptor, pbCompiledFile.get());
315 if (!outputStream.Write(map.getDataPtr(), map.getDataLength())) {
316 diag->error(DiagMessage(outputPath) << "failed to write data");
317 return false;
318 }
319 }
320
321 if (!writer->finishEntry()) {
322 diag->error(DiagMessage(outputPath) << "failed to finish writing data");
323 return false;
324 }
325 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700326}
327
328static bool compileXml(IAaptContext* context, const CompileOptions& options,
Adam Lesinskia40e9722015-11-24 19:11:46 -0800329 const ResourcePathData& pathData, IArchiveWriter* writer,
330 const std::string& outputPath) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700331
Adam Lesinski467f1712015-11-16 17:35:44 -0800332 std::unique_ptr<xml::XmlResource> xmlRes;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700333 {
334 std::ifstream fin(pathData.source.path, std::ifstream::binary);
335 if (!fin) {
336 context->getDiagnostics()->error(DiagMessage(pathData.source) << strerror(errno));
337 return false;
338 }
339
340 xmlRes = xml::inflate(&fin, context->getDiagnostics(), pathData.source);
341
342 fin.close();
343 }
344
345 if (!xmlRes) {
346 return false;
347 }
348
349 // Collect IDs that are defined here.
350 XmlIdCollector collector;
351 if (!collector.consume(context, xmlRes.get())) {
352 return false;
353 }
354
Adam Lesinskia40e9722015-11-24 19:11:46 -0800355 xmlRes->file.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700356 xmlRes->file.config = pathData.config;
357 xmlRes->file.source = pathData.source;
358
359 BigBuffer buffer(1024);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700360 XmlFlattenerOptions xmlFlattenerOptions;
361 xmlFlattenerOptions.keepRawValues = true;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800362 XmlFlattener flattener(&buffer, xmlFlattenerOptions);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700363 if (!flattener.consume(context, xmlRes.get())) {
364 return false;
365 }
366
Adam Lesinski59e04c62016-02-04 15:59:23 -0800367 if (!writeHeaderAndBufferToWriter(outputPath, xmlRes->file, buffer, writer,
368 context->getDiagnostics())) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700369 return false;
370 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800371 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700372}
373
374static bool compilePng(IAaptContext* context, const CompileOptions& options,
Adam Lesinskia40e9722015-11-24 19:11:46 -0800375 const ResourcePathData& pathData, IArchiveWriter* writer,
376 const std::string& outputPath) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700377 BigBuffer buffer(4096);
378 ResourceFile resFile;
Adam Lesinskia40e9722015-11-24 19:11:46 -0800379 resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700380 resFile.config = pathData.config;
381 resFile.source = pathData.source;
382
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700383 {
384 std::ifstream fin(pathData.source.path, std::ifstream::binary);
385 if (!fin) {
386 context->getDiagnostics()->error(DiagMessage(pathData.source) << strerror(errno));
387 return false;
388 }
389
390 Png png(context->getDiagnostics());
Adam Lesinski59e04c62016-02-04 15:59:23 -0800391 if (!png.process(pathData.source, &fin, &buffer, {})) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700392 return false;
393 }
394 }
395
Adam Lesinski59e04c62016-02-04 15:59:23 -0800396 if (!writeHeaderAndBufferToWriter(outputPath, resFile, buffer, writer,
397 context->getDiagnostics())) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700398 return false;
399 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800400 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700401}
402
403static bool compileFile(IAaptContext* context, const CompileOptions& options,
Adam Lesinskia40e9722015-11-24 19:11:46 -0800404 const ResourcePathData& pathData, IArchiveWriter* writer,
405 const std::string& outputPath) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700406 BigBuffer buffer(256);
407 ResourceFile resFile;
Adam Lesinskia40e9722015-11-24 19:11:46 -0800408 resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700409 resFile.config = pathData.config;
410 resFile.source = pathData.source;
411
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700412 std::string errorStr;
413 Maybe<android::FileMap> f = file::mmapPath(pathData.source.path, &errorStr);
414 if (!f) {
415 context->getDiagnostics()->error(DiagMessage(pathData.source) << errorStr);
416 return false;
417 }
418
Adam Lesinski59e04c62016-02-04 15:59:23 -0800419 if (!writeHeaderAndMmapToWriter(outputPath, resFile, f.value(), writer,
420 context->getDiagnostics())) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700421 return false;
422 }
Adam Lesinski52364f72016-01-11 13:10:24 -0800423 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700424}
425
426class CompileContext : public IAaptContext {
427private:
428 StdErrDiagnostics mDiagnostics;
429
430public:
431 IDiagnostics* getDiagnostics() override {
432 return &mDiagnostics;
433 }
434
435 NameMangler* getNameMangler() override {
436 abort();
437 return nullptr;
438 }
439
440 StringPiece16 getCompilationPackage() override {
441 return {};
442 }
443
444 uint8_t getPackageId() override {
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700445 return 0x0;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700446 }
447
448 ISymbolTable* getExternalSymbols() override {
449 abort();
450 return nullptr;
451 }
452};
453
454/**
455 * Entry point for compilation phase. Parses arguments and dispatches to the correct steps.
456 */
457int compile(const std::vector<StringPiece>& args) {
458 CompileOptions options;
459
Adam Lesinski7751afc2016-01-06 15:45:28 -0800460 Maybe<std::string> productList;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700461 Flags flags = Flags()
462 .requiredFlag("-o", "Output path", &options.outputPath)
Adam Lesinski7751afc2016-01-06 15:45:28 -0800463 .optionalFlag("--product", "Comma separated list of product types to compile",
464 &productList)
Adam Lesinskia40e9722015-11-24 19:11:46 -0800465 .optionalFlag("--dir", "Directory to scan for resources", &options.resDir)
Adam Lesinski393b5f02015-12-17 13:03:11 -0800466 .optionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales "
467 "(en-XA and ar-XB)", &options.pseudolocalize)
Adam Lesinski979ccb22016-01-11 10:42:19 -0800468 .optionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings",
469 &options.legacyMode)
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700470 .optionalSwitch("-v", "Enables verbose logging", &options.verbose);
471 if (!flags.parse("aapt2 compile", args, &std::cerr)) {
472 return 1;
473 }
474
Adam Lesinski7751afc2016-01-06 15:45:28 -0800475 if (productList) {
476 for (StringPiece part : util::tokenize<char>(productList.value(), ',')) {
477 options.products.push_back(util::utf8ToUtf16(part));
478 }
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700479 }
480
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700481 CompileContext context;
Adam Lesinskia40e9722015-11-24 19:11:46 -0800482 std::unique_ptr<IArchiveWriter> archiveWriter;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700483
484 std::vector<ResourcePathData> inputData;
Adam Lesinskia40e9722015-11-24 19:11:46 -0800485 if (options.resDir) {
486 if (!flags.getArgs().empty()) {
487 // Can't have both files and a resource directory.
488 context.getDiagnostics()->error(DiagMessage() << "files given but --dir specified");
489 flags.usage("aapt2 compile", &std::cerr);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700490 return 1;
491 }
Adam Lesinskia40e9722015-11-24 19:11:46 -0800492
493 if (!loadInputFilesFromDir(&context, options, &inputData)) {
494 return 1;
495 }
496
497 archiveWriter = createZipFileArchiveWriter(context.getDiagnostics(), options.outputPath);
498
499 } else {
500 inputData.reserve(flags.getArgs().size());
501
502 // Collect data from the path for each input file.
503 for (const std::string& arg : flags.getArgs()) {
504 std::string errorStr;
505 if (Maybe<ResourcePathData> pathData = extractResourcePathData(arg, &errorStr)) {
506 inputData.push_back(std::move(pathData.value()));
507 } else {
508 context.getDiagnostics()->error(DiagMessage() << errorStr << " (" << arg << ")");
509 return 1;
510 }
511 }
512
513 archiveWriter = createDirectoryArchiveWriter(context.getDiagnostics(), options.outputPath);
514 }
515
516 if (!archiveWriter) {
517 return false;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700518 }
519
520 bool error = false;
521 for (ResourcePathData& pathData : inputData) {
522 if (options.verbose) {
523 context.getDiagnostics()->note(DiagMessage(pathData.source) << "processing");
524 }
525
526 if (pathData.resourceDir == u"values") {
527 // Overwrite the extension.
528 pathData.extension = "arsc";
529
Adam Lesinskia40e9722015-11-24 19:11:46 -0800530 const std::string outputFilename = buildIntermediateFilename(pathData);
531 if (!compileTable(&context, options, pathData, archiveWriter.get(), outputFilename)) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700532 error = true;
533 }
534
535 } else {
Adam Lesinskia40e9722015-11-24 19:11:46 -0800536 const std::string outputFilename = buildIntermediateFilename(pathData);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700537 if (const ResourceType* type = parseResourceType(pathData.resourceDir)) {
538 if (*type != ResourceType::kRaw) {
539 if (pathData.extension == "xml") {
Adam Lesinskia40e9722015-11-24 19:11:46 -0800540 if (!compileXml(&context, options, pathData, archiveWriter.get(),
541 outputFilename)) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700542 error = true;
543 }
544 } else if (pathData.extension == "png" || pathData.extension == "9.png") {
Adam Lesinskia40e9722015-11-24 19:11:46 -0800545 if (!compilePng(&context, options, pathData, archiveWriter.get(),
546 outputFilename)) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700547 error = true;
548 }
549 } else {
Adam Lesinskia40e9722015-11-24 19:11:46 -0800550 if (!compileFile(&context, options, pathData, archiveWriter.get(),
551 outputFilename)) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700552 error = true;
553 }
554 }
555 } else {
Adam Lesinskia40e9722015-11-24 19:11:46 -0800556 if (!compileFile(&context, options, pathData, archiveWriter.get(),
557 outputFilename)) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700558 error = true;
559 }
560 }
561 } else {
562 context.getDiagnostics()->error(
563 DiagMessage() << "invalid file path '" << pathData.source << "'");
564 error = true;
565 }
566 }
567 }
568
569 if (error) {
570 return 1;
571 }
572 return 0;
573}
574
575} // namespace aapt