AAPT2: Fix windows unicode path issues
Mingw64 was being difficult, so instead of defining a wmain entrypoint,
the command line parameters are parsed manually using built-in Windows
methods that support Unicode. The results are converted to UTF8 and
handled just like the rest of the linux/mac version of the code.
This also removes dependencies on std::istream in favour of a
FileInputStream which calls the appropriate unicode version of
open to read a file.
No speed regressions found on Linux or MacOS.
Bug: 62336414
Bug: 63830502
Test: manual
Change-Id: I597da51e33729ed1b98bf246e7e773337fd3fee8
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 1bf2594..6f97efe 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -27,6 +27,8 @@
#include "android-base/errors.h"
#include "android-base/file.h"
#include "android-base/logging.h"
+#include "android-base/unique_fd.h"
+#include "android-base/utf8.h"
#include "util/Util.h"
@@ -35,14 +37,32 @@
#include <direct.h>
#endif
-using android::StringPiece;
+using ::android::FileMap;
+using ::android::StringPiece;
+using ::android::base::ReadFileToString;
+using ::android::base::SystemErrorCodeToString;
+using ::android::base::unique_fd;
namespace aapt {
namespace file {
-FileType GetFileType(const StringPiece& path) {
+FileType GetFileType(const std::string& path) {
+// TODO(adamlesinski): I'd like to move this to ::android::base::utf8 but Windows does some macro
+// trickery with 'stat' and things don't override very well.
+#ifdef _WIN32
+ std::wstring path_utf16;
+ if (!::android::base::UTF8PathToWindowsLongPath(path.c_str(), &path_utf16)) {
+ return FileType::kNonexistant;
+ }
+
+ struct _stat64 sb;
+ int result = _wstat64(path_utf16.c_str(), &sb);
+#else
struct stat sb;
- if (stat(path.data(), &sb) < 0) {
+ int result = stat(path.c_str(), &sb);
+#endif
+
+ if (result == -1) {
if (errno == ENOENT || errno == ENOTDIR) {
return FileType::kNonexistant;
}
@@ -72,27 +92,18 @@
}
}
-inline static int MkdirImpl(const StringPiece& path) {
-#ifdef _WIN32
- return _mkdir(path.to_string().c_str());
-#else
- return mkdir(path.to_string().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 && current != start) {
- StringPiece parent_path(start, current - start);
- int result = MkdirImpl(parent_path);
- if (result < 0 && errno != EEXIST) {
- return false;
- }
+bool mkdirs(const std::string& path) {
+ constexpr const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP;
+ size_t current_pos = 0u;
+ while ((current_pos = path.find(sDirSep, current_pos)) != std::string::npos) {
+ std::string parent_path = path.substr(0, current_pos);
+ int result = ::android::base::utf8::mkdir(parent_path.c_str(), mode);
+ if (result < 0 && errno != EEXIST) {
+ return false;
}
+ current_pos += 1;
}
- return MkdirImpl(path) == 0 || errno == EEXIST;
+ return ::android::base::utf8::mkdir(path.c_str(), mode) == 0 || errno == EEXIST;
}
StringPiece GetStem(const StringPiece& path) {
@@ -129,10 +140,8 @@
void AppendPath(std::string* base, StringPiece part) {
CHECK(base != nullptr);
- const bool base_has_trailing_sep =
- (!base->empty() && *(base->end() - 1) == sDirSep);
- const bool part_has_leading_sep =
- (!part.empty() && *(part.begin()) == sDirSep);
+ const bool base_has_trailing_sep = (!base->empty() && *(base->end() - 1) == sDirSep);
+ const bool part_has_leading_sep = (!part.empty() && *(part.begin()) == sDirSep);
if (base_has_trailing_sep && part_has_leading_sep) {
// Remove the part's leading sep
part = part.substr(1, part.size() - 1);
@@ -151,31 +160,34 @@
return out_path;
}
-Maybe<android::FileMap> MmapPath(const StringPiece& path,
- std::string* out_error) {
- std::unique_ptr<FILE, decltype(fclose)*> f = {fopen(path.data(), "rb"),
- fclose};
- if (!f) {
- if (out_error) *out_error = android::base::SystemErrorCodeToString(errno);
+Maybe<FileMap> MmapPath(const std::string& path, std::string* out_error) {
+ int flags = O_RDONLY | O_CLOEXEC | O_BINARY;
+ unique_fd fd(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), flags)));
+ if (fd == -1) {
+ if (out_error) {
+ *out_error = SystemErrorCodeToString(errno);
+ }
return {};
}
- int fd = fileno(f.get());
-
struct stat filestats = {};
if (fstat(fd, &filestats) != 0) {
- if (out_error) *out_error = android::base::SystemErrorCodeToString(errno);
+ if (out_error) {
+ *out_error = SystemErrorCodeToString(errno);
+ }
return {};
}
- android::FileMap filemap;
+ FileMap filemap;
if (filestats.st_size == 0) {
// mmap doesn't like a length of 0. Instead we return an empty FileMap.
return std::move(filemap);
}
- if (!filemap.create(path.data(), fd, 0, filestats.st_size, true)) {
- if (out_error) *out_error = android::base::SystemErrorCodeToString(errno);
+ if (!filemap.create(path.c_str(), fd, 0, filestats.st_size, true)) {
+ if (out_error) {
+ *out_error = SystemErrorCodeToString(errno);
+ }
return {};
}
return std::move(filemap);
@@ -184,7 +196,7 @@
bool AppendArgsFromFile(const StringPiece& path, std::vector<std::string>* out_arglist,
std::string* out_error) {
std::string contents;
- if (!android::base::ReadFileToString(path.to_string(), &contents, true /*follow_symlinks*/)) {
+ if (!ReadFileToString(path.to_string(), &contents, true /*follow_symlinks*/)) {
if (out_error) {
*out_error = "failed to read argument-list file";
}
@@ -270,7 +282,7 @@
const std::string root_dir = path.to_string();
std::unique_ptr<DIR, decltype(closedir)*> d(opendir(root_dir.data()), closedir);
if (!d) {
- diag->Error(DiagMessage() << android::base::SystemErrorCodeToString(errno));
+ diag->Error(DiagMessage() << SystemErrorCodeToString(errno));
return {};
}