Files.cpp revision 52364f7ae31716d7827ea8f8566f4a28bd30a921
1a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown/*
2a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * Copyright (C) 2015 The Android Open Source Project
3a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown *
4a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * you may not use this file except in compliance with the License.
6a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * You may obtain a copy of the License at
7a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown *
8a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown *
10a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * Unless required by applicable law or agreed to in writing, software
11a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * See the License for the specific language governing permissions and
14a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown * limitations under the License.
15a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown */
16a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
17a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#include "util/Files.h"
18a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#include "util/Util.h"
19a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
20a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#include <cerrno>
21a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#include <cstdio>
22a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#include <dirent.h>
23a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#include <string>
24a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#include <sys/stat.h>
25a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
26a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#ifdef _WIN32
27a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown// Windows includes.
28a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#include <direct.h>
29a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#endif
30a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
31a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownnamespace aapt {
32a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownnamespace file {
33a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
34a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff BrownFileType getFileType(const StringPiece& path) {
35a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown    struct stat sb;
36a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    if (stat(path.data(), &sb) < 0) {
37a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (errno == ENOENT || errno == ENOTDIR) {
38a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            return FileType::kNonexistant;
39a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
40a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown        return FileType::kUnknown;
41a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
42a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
43a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    if (S_ISREG(sb.st_mode)) {
44a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return FileType::kRegular;
45a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    } else if (S_ISDIR(sb.st_mode)) {
46a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown        return FileType::kDirectory;
47a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    } else if (S_ISCHR(sb.st_mode)) {
48a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return FileType::kCharDev;
49a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    } else if (S_ISBLK(sb.st_mode)) {
50a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown        return FileType::kBlockDev;
51a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown    } else if (S_ISFIFO(sb.st_mode)) {
52a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return FileType::kFifo;
53a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown#if defined(S_ISLNK)
54a95a3b494fd88f83c9f5d32e001452575ba235ecJeff Brown    } else if (S_ISLNK(sb.st_mode)) {
55a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return FileType::kSymlink;
56a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#endif
57a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#if defined(S_ISSOCK)
58a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    } else if (S_ISSOCK(sb.st_mode)) {
59a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return FileType::kSocket;
60a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#endif
61a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    } else {
62a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return FileType::kUnknown;
63a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
64a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
65a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
66a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownstd::vector<std::string> listFiles(const StringPiece& root, std::string* outError) {
67a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    DIR* dir = opendir(root.data());
68a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    if (dir == nullptr) {
69a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (outError) {
70a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            std::stringstream errorStr;
71a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            errorStr << "unable to open file: " << strerror(errno);
72a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            *outError = errorStr.str();
73a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            return {};
74a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
75a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
76a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
77a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    std::vector<std::string> files;
78a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    dirent* entry;
79a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    while ((entry = readdir(dir))) {
80a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        files.emplace_back(entry->d_name);
81a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
82a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
83a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    closedir(dir);
84a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return files;
85a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
86a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
87a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Browninline static int mkdirImpl(const StringPiece& path) {
88a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#ifdef _WIN32
89a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return _mkdir(path.toString().c_str());
90a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#else
91a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return mkdir(path.toString().c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
92a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown#endif
93a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
94a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
95a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownbool mkdirs(const StringPiece& path) {
96a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const char* start = path.begin();
97a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const char* end = path.end();
98a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    for (const char* current = start; current != end; ++current) {
99a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (*current == sDirSep) {
100a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            StringPiece parentPath(start, current - start);
101a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            int result = mkdirImpl(parentPath);
102a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            if (result < 0 && errno != EEXIST) {
103a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                return false;
104a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
105a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
106a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
107a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return mkdirImpl(path) == 0 || errno == EEXIST;
108a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
109a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
110a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff BrownStringPiece getStem(const StringPiece& path) {
111a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const char* start = path.begin();
112a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const char* end = path.end();
113a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    for (const char* current = end - 1; current != start - 1; --current) {
114a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (*current == sDirSep) {
115a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            return StringPiece(start, current - start);
116a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
117a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
118a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return {};
119a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
120a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
121a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff BrownStringPiece getFilename(const StringPiece& path) {
122a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const char* end = path.end();
123a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const char* lastDirSep = path.begin();
124a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    for (const char* c = path.begin(); c != end; ++c) {
125a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (*c == sDirSep) {
126a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            lastDirSep = c + 1;
127a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
128a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
129a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return StringPiece(lastDirSep, end - lastDirSep);
130a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
131a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
132a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff BrownStringPiece getExtension(const StringPiece& path) {
133a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    StringPiece filename = getFilename(path);
134a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const char* const end = filename.end();
135a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const char* c = std::find(filename.begin(), end, '.');
136a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    if (c != end) {
137a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return StringPiece(c, end - c);
138a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
139a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return {};
140a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
141a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
142a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownstd::string packageToPath(const StringPiece& package) {
143a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    std::string outPath;
144a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    for (StringPiece part : util::tokenize<char>(package, '.')) {
145a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        appendPath(&outPath, part);
146a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
147a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return outPath;
148a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
149a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
150a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff BrownMaybe<android::FileMap> mmapPath(const StringPiece& path, std::string* outError) {
151a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    std::unique_ptr<FILE, decltype(fclose)*> f = { fopen(path.data(), "rb"), fclose };
152a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    if (!f) {
153a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (outError) *outError = strerror(errno);
154a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return {};
155a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
156a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
157a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    int fd = fileno(f.get());
158a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
159a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    struct stat fileStats = {};
160a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    if (fstat(fd, &fileStats) != 0) {
161a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (outError) *outError = strerror(errno);
162a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return {};
163a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
164a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
165a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    android::FileMap fileMap;
166a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    if (fileStats.st_size == 0) {
167a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        // mmap doesn't like a length of 0. Instead we return an empty FileMap.
168a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return std::move(fileMap);
169a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
170a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
171a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    if (!fileMap.create(path.data(), fd, 0, fileStats.st_size, true)) {
172a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (outError) *outError = strerror(errno);
173a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return {};
174a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
175a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return std::move(fileMap);
176a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
177a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
178a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownbool FileFilter::setPattern(const StringPiece& pattern) {
179a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    mPatternTokens = util::splitAndLowercase(pattern, ':');
180a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return true;
181a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
182a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
183a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brownbool FileFilter::operator()(const std::string& filename, FileType type) const {
184a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    if (filename == "." || filename == "..") {
185a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        return false;
186a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
187a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
188a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const char kDir[] = "dir";
189a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const char kFile[] = "file";
190a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    const size_t filenameLen = filename.length();
191a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    bool chatty = true;
192a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    for (const std::string& token : mPatternTokens) {
193a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        const char* tokenStr = token.c_str();
194a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (*tokenStr == '!') {
195a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            chatty = false;
196a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            tokenStr++;
197a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
198a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
199a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (strncasecmp(tokenStr, kDir, sizeof(kDir)) == 0) {
200a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            if (type != FileType::kDirectory) {
201a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                continue;
202a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
203a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            tokenStr += sizeof(kDir);
204a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
205a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
206a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (strncasecmp(tokenStr, kFile, sizeof(kFile)) == 0) {
207a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            if (type != FileType::kRegular) {
208a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                continue;
209a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
210a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            tokenStr += sizeof(kFile);
211a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
212a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
213a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        bool ignore = false;
214a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        size_t n = strlen(tokenStr);
215a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (*tokenStr == '*') {
216a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            // Math suffix.
217a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            tokenStr++;
218a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            n--;
219a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            if (n <= filenameLen) {
220a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                ignore = strncasecmp(tokenStr, filename.c_str() + filenameLen - n, n) == 0;
221a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
222a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        } else if (n > 1 && tokenStr[n - 1] == '*') {
223a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            // Match prefix.
224a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            ignore = strncasecmp(tokenStr, filename.c_str(), n - 1) == 0;
225a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        } else {
226a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            ignore = strcasecmp(tokenStr, filename.c_str()) == 0;
227a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
228a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
229a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        if (ignore) {
230a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            if (chatty) {
231a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                mDiag->warn(DiagMessage() << "skipping "
232a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                            << (type == FileType::kDirectory ? "dir '" : "file '")
233a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                            << filename << "' due to ignore pattern '"
234a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown                            << token << "'");
235a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            }
236a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown            return false;
237a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown        }
238a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    }
239a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown    return true;
240a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown}
241a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown
242a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown} // namespace file
243a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown} // namespace aapt
244a492c3a7b2c18426fd0cb4d017eacbc368195dc5Jeff Brown