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