AAPT2
First checking of AAPT2. The individual phases of AAPT2 work, but there
are some missing pieces.
For early testing we are missing:
- Need to properly mark file references and include them in package
- Need to package into zip
Final AAPT for apps we are missing:
- Need to crush PNGs
- Need to parse 9-patches
- Need to validate all of AndroidManifest.xml
- Need to write align method to align resource tables for splits.
Final AAPT for apps + system we are missing:
- Need to handle overlays
- Need to store comments for R file
- Need to handle --shared-lib (dynamic references too).
New AAPT features coming:
- Need to import compiled libraries
- Name mangling
- R file generation for library code
Change-Id: I95f8a63581b81a1f424ae6fb2c373c883b72c18d
diff --git a/tools/aapt2/Files.cpp b/tools/aapt2/Files.cpp
new file mode 100644
index 0000000..c910c81
--- /dev/null
+++ b/tools/aapt2/Files.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Files.h"
+#include "Util.h"
+
+#include <cerrno>
+#include <dirent.h>
+#include <string>
+#include <sys/stat.h>
+
+namespace aapt {
+
+FileType getFileType(const StringPiece& path) {
+ struct stat sb;
+ if (stat(path.data(), &sb) < 0) {
+ if (errno == ENOENT || errno == ENOTDIR) {
+ return FileType::kNonexistant;
+ }
+ return FileType::kUnknown;
+ }
+
+ if (S_ISREG(sb.st_mode)) {
+ return FileType::kRegular;
+ } else if (S_ISDIR(sb.st_mode)) {
+ return FileType::kDirectory;
+ } else if (S_ISCHR(sb.st_mode)) {
+ return FileType::kCharDev;
+ } else if (S_ISBLK(sb.st_mode)) {
+ return FileType::kBlockDev;
+ } else if (S_ISFIFO(sb.st_mode)) {
+ return FileType::kFifo;
+ } else if (S_ISLNK(sb.st_mode)) {
+ return FileType::kSymlink;
+ } else if (S_ISSOCK(sb.st_mode)) {
+ return FileType::kSocket;
+ } else {
+ return FileType::kUnknown;
+ }
+}
+
+std::vector<std::string> listFiles(const StringPiece& root) {
+ DIR* dir = opendir(root.data());
+ if (dir == nullptr) {
+ Logger::error(Source{ root.toString() })
+ << "unable to open file: "
+ << strerror(errno)
+ << "."
+ << std::endl;
+ return {};
+ }
+
+ std::vector<std::string> files;
+ dirent* entry;
+ while ((entry = readdir(dir))) {
+ files.emplace_back(entry->d_name);
+ }
+
+ closedir(dir);
+ return files;
+}
+
+inline static int mkdirImpl(const StringPiece& path) {
+#ifdef HAVE_MS_C_RUNTIME
+ return _mkdir(path.toString().c_str());
+#else
+ return mkdir(path.toString().c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+#endif
+}
+
+bool mkdirs(const StringPiece& path) {
+ const char* start = path.begin();
+ const char* end = path.end();
+ for (const char* current = start; current != end; ++current) {
+ if (*current == sDirSep) {
+ StringPiece parentPath(start, current - start);
+ int result = mkdirImpl(parentPath);
+ if (result < 0 && errno != EEXIST) {
+ return false;
+ }
+ }
+ }
+ return mkdirImpl(path) == 0 || errno == EEXIST;
+}
+
+bool FileFilter::setPattern(const StringPiece& pattern) {
+ mPatternTokens = util::splitAndLowercase(pattern, ':');
+ return true;
+}
+
+bool FileFilter::operator()(const std::string& filename, FileType type) const {
+ if (filename == "." || filename == "..") {
+ return false;
+ }
+
+ const char kDir[] = "dir";
+ const char kFile[] = "file";
+ const size_t filenameLen = filename.length();
+ bool chatty = true;
+ for (const std::string& token : mPatternTokens) {
+ const char* tokenStr = token.c_str();
+ if (*tokenStr == '!') {
+ chatty = false;
+ tokenStr++;
+ }
+
+ if (strncasecmp(tokenStr, kDir, sizeof(kDir)) == 0) {
+ if (type != FileType::kDirectory) {
+ continue;
+ }
+ tokenStr += sizeof(kDir);
+ }
+
+ if (strncasecmp(tokenStr, kFile, sizeof(kFile)) == 0) {
+ if (type != FileType::kRegular) {
+ continue;
+ }
+ tokenStr += sizeof(kFile);
+ }
+
+ bool ignore = false;
+ size_t n = strlen(tokenStr);
+ if (*tokenStr == '*') {
+ // Math suffix.
+ tokenStr++;
+ n--;
+ if (n <= filenameLen) {
+ ignore = strncasecmp(tokenStr, filename.c_str() + filenameLen - n, n) == 0;
+ }
+ } else if (n > 1 && tokenStr[n - 1] == '*') {
+ // Match prefix.
+ ignore = strncasecmp(tokenStr, filename.c_str(), n - 1) == 0;
+ } else {
+ ignore = strcasecmp(tokenStr, filename.c_str()) == 0;
+ }
+
+ if (ignore) {
+ if (chatty) {
+ Logger::warn()
+ << "skipping " <<
+ (type == FileType::kDirectory ? "dir '" : "file '")
+ << filename
+ << "' due to ignore pattern '"
+ << token
+ << "'."
+ << std::endl;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+
+} // namespace aapt