Austin Schuh | e89fa2d | 2019-08-14 20:24:23 -0700 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2016 Google Inc. All rights reserved. |
| 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 | // clang-format off |
| 18 | // Dont't remove `format off`, it prevent reordering of win-includes. |
| 19 | #ifdef _WIN32 |
| 20 | # ifndef WIN32_LEAN_AND_MEAN |
| 21 | # define WIN32_LEAN_AND_MEAN |
| 22 | # endif |
| 23 | # ifndef NOMINMAX |
| 24 | # define NOMINMAX |
| 25 | # endif |
| 26 | # ifdef _MSC_VER |
| 27 | # include <crtdbg.h> |
| 28 | # endif |
| 29 | # include <windows.h> // Must be included before <direct.h> |
| 30 | # include <direct.h> |
| 31 | # include <winbase.h> |
| 32 | # undef interface // This is also important because of reasons |
| 33 | #else |
| 34 | # include <limits.h> |
| 35 | #endif |
| 36 | // clang-format on |
| 37 | |
| 38 | #include "flatbuffers/base.h" |
| 39 | #include "flatbuffers/util.h" |
| 40 | |
| 41 | #include <sys/stat.h> |
| 42 | #include <clocale> |
| 43 | #include <fstream> |
| 44 | |
| 45 | namespace flatbuffers { |
| 46 | |
| 47 | bool FileExistsRaw(const char *name) { |
| 48 | std::ifstream ifs(name); |
| 49 | return ifs.good(); |
| 50 | } |
| 51 | |
| 52 | bool LoadFileRaw(const char *name, bool binary, std::string *buf) { |
| 53 | if (DirExists(name)) return false; |
| 54 | std::ifstream ifs(name, binary ? std::ifstream::binary : std::ifstream::in); |
| 55 | if (!ifs.is_open()) return false; |
| 56 | if (binary) { |
| 57 | // The fastest way to read a file into a string. |
| 58 | ifs.seekg(0, std::ios::end); |
| 59 | auto size = ifs.tellg(); |
| 60 | (*buf).resize(static_cast<size_t>(size)); |
| 61 | ifs.seekg(0, std::ios::beg); |
| 62 | ifs.read(&(*buf)[0], (*buf).size()); |
| 63 | } else { |
| 64 | // This is slower, but works correctly on all platforms for text files. |
| 65 | std::ostringstream oss; |
| 66 | oss << ifs.rdbuf(); |
| 67 | *buf = oss.str(); |
| 68 | } |
| 69 | return !ifs.bad(); |
| 70 | } |
| 71 | |
| 72 | static LoadFileFunction g_load_file_function = LoadFileRaw; |
| 73 | static FileExistsFunction g_file_exists_function = FileExistsRaw; |
| 74 | |
| 75 | bool LoadFile(const char *name, bool binary, std::string *buf) { |
| 76 | FLATBUFFERS_ASSERT(g_load_file_function); |
| 77 | return g_load_file_function(name, binary, buf); |
| 78 | } |
| 79 | |
| 80 | bool FileExists(const char *name) { |
| 81 | FLATBUFFERS_ASSERT(g_file_exists_function); |
| 82 | return g_file_exists_function(name); |
| 83 | } |
| 84 | |
| 85 | bool DirExists(const char *name) { |
| 86 | // clang-format off |
| 87 | |
| 88 | #ifdef _WIN32 |
| 89 | #define flatbuffers_stat _stat |
| 90 | #define FLATBUFFERS_S_IFDIR _S_IFDIR |
| 91 | #else |
| 92 | #define flatbuffers_stat stat |
| 93 | #define FLATBUFFERS_S_IFDIR S_IFDIR |
| 94 | #endif |
| 95 | // clang-format on |
| 96 | struct flatbuffers_stat file_info; |
| 97 | if (flatbuffers_stat(name, &file_info) != 0) return false; |
| 98 | return (file_info.st_mode & FLATBUFFERS_S_IFDIR) != 0; |
| 99 | } |
| 100 | |
| 101 | LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function) { |
| 102 | LoadFileFunction previous_function = g_load_file_function; |
| 103 | g_load_file_function = load_file_function ? load_file_function : LoadFileRaw; |
| 104 | return previous_function; |
| 105 | } |
| 106 | |
| 107 | FileExistsFunction SetFileExistsFunction( |
| 108 | FileExistsFunction file_exists_function) { |
| 109 | FileExistsFunction previous_function = g_file_exists_function; |
| 110 | g_file_exists_function = |
| 111 | file_exists_function ? file_exists_function : FileExistsRaw; |
| 112 | return previous_function; |
| 113 | } |
| 114 | |
| 115 | bool SaveFile(const char *name, const char *buf, size_t len, bool binary) { |
| 116 | std::ofstream ofs(name, binary ? std::ofstream::binary : std::ofstream::out); |
| 117 | if (!ofs.is_open()) return false; |
| 118 | ofs.write(buf, len); |
| 119 | return !ofs.bad(); |
| 120 | } |
| 121 | |
| 122 | // We internally store paths in posix format ('/'). Paths supplied |
| 123 | // by the user should go through PosixPath to ensure correct behavior |
| 124 | // on Windows when paths are string-compared. |
| 125 | |
| 126 | static const char kPathSeparatorWindows = '\\'; |
| 127 | static const char *PathSeparatorSet = "\\/"; // Intentionally no ':' |
| 128 | |
| 129 | std::string StripExtension(const std::string &filepath) { |
| 130 | size_t i = filepath.find_last_of('.'); |
| 131 | return i != std::string::npos ? filepath.substr(0, i) : filepath; |
| 132 | } |
| 133 | |
| 134 | std::string GetExtension(const std::string &filepath) { |
| 135 | size_t i = filepath.find_last_of('.'); |
| 136 | return i != std::string::npos ? filepath.substr(i + 1) : ""; |
| 137 | } |
| 138 | |
| 139 | std::string StripPath(const std::string &filepath) { |
| 140 | size_t i = filepath.find_last_of(PathSeparatorSet); |
| 141 | return i != std::string::npos ? filepath.substr(i + 1) : filepath; |
| 142 | } |
| 143 | |
| 144 | std::string StripFileName(const std::string &filepath) { |
| 145 | size_t i = filepath.find_last_of(PathSeparatorSet); |
| 146 | return i != std::string::npos ? filepath.substr(0, i) : ""; |
| 147 | } |
| 148 | |
| 149 | std::string ConCatPathFileName(const std::string &path, |
| 150 | const std::string &filename) { |
| 151 | std::string filepath = path; |
| 152 | if (filepath.length()) { |
| 153 | char &filepath_last_character = string_back(filepath); |
| 154 | if (filepath_last_character == kPathSeparatorWindows) { |
| 155 | filepath_last_character = kPathSeparator; |
| 156 | } else if (filepath_last_character != kPathSeparator) { |
| 157 | filepath += kPathSeparator; |
| 158 | } |
| 159 | } |
| 160 | filepath += filename; |
| 161 | // Ignore './' at the start of filepath. |
| 162 | if (filepath[0] == '.' && filepath[1] == kPathSeparator) { |
| 163 | filepath.erase(0, 2); |
| 164 | } |
| 165 | return filepath; |
| 166 | } |
| 167 | |
| 168 | std::string PosixPath(const char *path) { |
| 169 | std::string p = path; |
| 170 | std::replace(p.begin(), p.end(), '\\', '/'); |
| 171 | return p; |
| 172 | } |
| 173 | |
| 174 | void EnsureDirExists(const std::string &filepath) { |
| 175 | auto parent = StripFileName(filepath); |
| 176 | if (parent.length()) EnsureDirExists(parent); |
| 177 | // clang-format off |
| 178 | |
| 179 | #ifdef _WIN32 |
| 180 | (void)_mkdir(filepath.c_str()); |
| 181 | #else |
| 182 | mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP); |
| 183 | #endif |
| 184 | // clang-format on |
| 185 | } |
| 186 | |
| 187 | std::string AbsolutePath(const std::string &filepath) { |
| 188 | // clang-format off |
| 189 | |
| 190 | #ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION |
| 191 | return filepath; |
| 192 | #else |
| 193 | #ifdef _WIN32 |
| 194 | char abs_path[MAX_PATH]; |
| 195 | return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr) |
| 196 | #else |
| 197 | char abs_path[PATH_MAX]; |
| 198 | return realpath(filepath.c_str(), abs_path) |
| 199 | #endif |
| 200 | ? abs_path |
| 201 | : filepath; |
| 202 | #endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION |
| 203 | // clang-format on |
| 204 | } |
| 205 | |
| 206 | // Locale-independent code. |
| 207 | #if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \ |
| 208 | (FLATBUFFERS_LOCALE_INDEPENDENT > 0) |
| 209 | |
| 210 | // clang-format off |
| 211 | // Allocate locale instance at startup of application. |
| 212 | ClassicLocale ClassicLocale::instance_; |
| 213 | |
| 214 | #ifdef _MSC_VER |
| 215 | ClassicLocale::ClassicLocale() |
| 216 | : locale_(_create_locale(LC_ALL, "C")) {} |
| 217 | ClassicLocale::~ClassicLocale() { _free_locale(locale_); } |
| 218 | #else |
| 219 | ClassicLocale::ClassicLocale() |
| 220 | : locale_(newlocale(LC_ALL, "C", nullptr)) {} |
| 221 | ClassicLocale::~ClassicLocale() { freelocale(locale_); } |
| 222 | #endif |
| 223 | // clang-format on |
| 224 | |
| 225 | #endif // !FLATBUFFERS_LOCALE_INDEPENDENT |
| 226 | |
| 227 | std::string RemoveStringQuotes(const std::string &s) { |
| 228 | auto ch = *s.c_str(); |
| 229 | return ((s.size() >= 2) && (ch == '\"' || ch == '\'') && |
| 230 | (ch == string_back(s))) |
| 231 | ? s.substr(1, s.length() - 2) |
| 232 | : s; |
| 233 | } |
| 234 | |
| 235 | bool SetGlobalTestLocale(const char *locale_name, std::string *_value) { |
| 236 | const auto the_locale = setlocale(LC_ALL, locale_name); |
| 237 | if (!the_locale) return false; |
| 238 | if (_value) *_value = std::string(the_locale); |
| 239 | return true; |
| 240 | } |
| 241 | |
| 242 | bool ReadEnvironmentVariable(const char *var_name, std::string *_value) { |
| 243 | #ifdef _MSC_VER |
| 244 | __pragma(warning(disable : 4996)); // _CRT_SECURE_NO_WARNINGS |
| 245 | #endif |
| 246 | auto env_str = std::getenv(var_name); |
| 247 | if (!env_str) return false; |
| 248 | if (_value) *_value = std::string(env_str); |
| 249 | return true; |
| 250 | } |
| 251 | |
| 252 | void SetupDefaultCRTReportMode() { |
| 253 | // clang-format off |
| 254 | |
| 255 | #ifdef _MSC_VER |
| 256 | // By default, send all reports to STDOUT to prevent CI hangs. |
| 257 | // Enable assert report box [Abort|Retry|Ignore] if a debugger is present. |
| 258 | const int dbg_mode = (_CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG) | |
| 259 | (IsDebuggerPresent() ? _CRTDBG_MODE_WNDW : 0); |
| 260 | (void)dbg_mode; // release mode fix |
| 261 | // CrtDebug reports to _CRT_WARN channel. |
| 262 | _CrtSetReportMode(_CRT_WARN, dbg_mode); |
| 263 | _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); |
| 264 | // The assert from <assert.h> reports to _CRT_ERROR channel |
| 265 | _CrtSetReportMode(_CRT_ERROR, dbg_mode); |
| 266 | _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT); |
| 267 | // Internal CRT assert channel? |
| 268 | _CrtSetReportMode(_CRT_ASSERT, dbg_mode); |
| 269 | _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT); |
| 270 | #endif |
| 271 | |
| 272 | // clang-format on |
| 273 | } |
| 274 | |
| 275 | } // namespace flatbuffers |