/* * Copyright 2016 Google Inc. All rights reserved. * * 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. */ // clang-format off // Dont't remove `format off`, it prevent reordering of win-includes. #include #if defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) || \ defined(__QNXNTO__) # define _POSIX_C_SOURCE 200809L # define _XOPEN_SOURCE 700L #endif #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # ifndef NOMINMAX # define NOMINMAX # endif # ifdef _MSC_VER # include # endif # include // Must be included before # ifndef __CYGWIN__ # include # endif # include # undef interface // This is also important because of reasons #endif // clang-format on #include "flatbuffers/util.h" #include #include #include #include #include #include "flatbuffers/base.h" namespace flatbuffers { namespace { static bool FileExistsRaw(const char *name) { std::ifstream ifs(name); return ifs.good(); } static bool LoadFileRaw(const char *name, bool binary, std::string *buf) { if (DirExists(name)) return false; std::ifstream ifs(name, binary ? std::ifstream::binary : std::ifstream::in); if (!ifs.is_open()) return false; if (binary) { // The fastest way to read a file into a string. ifs.seekg(0, std::ios::end); auto size = ifs.tellg(); (*buf).resize(static_cast(size)); ifs.seekg(0, std::ios::beg); ifs.read(&(*buf)[0], (*buf).size()); } else { // This is slower, but works correctly on all platforms for text files. std::ostringstream oss; oss << ifs.rdbuf(); *buf = oss.str(); } return !ifs.bad(); } LoadFileFunction g_load_file_function = LoadFileRaw; FileExistsFunction g_file_exists_function = FileExistsRaw; static std::string ToCamelCase(const std::string &input, bool is_upper) { std::string s; for (size_t i = 0; i < input.length(); i++) { if (!i && input[i] == '_') { s += input[i]; // we ignore leading underscore but make following // alphabet char upper. if (i + 1 < input.length() && is_alpha(input[i + 1])) s += CharToUpper(input[++i]); } else if (!i) s += is_upper ? CharToUpper(input[i]) : CharToLower(input[i]); else if (input[i] == '_' && i + 1 < input.length()) s += CharToUpper(input[++i]); else s += input[i]; } return s; } static std::string ToSnakeCase(const std::string &input, bool screaming) { std::string s; for (size_t i = 0; i < input.length(); i++) { if (i == 0) { s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]); } else if (input[i] == '_') { s += '_'; } else if (!islower(input[i])) { // Prevent duplicate underscores for Upper_Snake_Case strings // and UPPERCASE strings. if (islower(input[i - 1]) || (isdigit(input[i - 1]) && !isdigit(input[i]))) { s += '_'; } s += screaming ? CharToUpper(input[i]) : CharToLower(input[i]); } else { s += screaming ? CharToUpper(input[i]) : input[i]; } } return s; } std::string ToAll(const std::string &input, std::function transform) { std::string s; for (size_t i = 0; i < input.length(); i++) { s += transform(input[i]); } return s; } std::string CamelToSnake(const std::string &input) { std::string s; for (size_t i = 0; i < input.length(); i++) { if (i == 0) { s += CharToLower(input[i]); } else if (input[i] == '_') { s += '_'; } else if (!islower(input[i])) { // Prevent duplicate underscores for Upper_Snake_Case strings // and UPPERCASE strings. if (islower(input[i - 1]) || (isdigit(input[i - 1]) && !isdigit(input[i]))) { s += '_'; } s += CharToLower(input[i]); } else { s += input[i]; } } return s; } std::string DasherToSnake(const std::string &input) { std::string s; for (size_t i = 0; i < input.length(); i++) { if (input[i] == '-') { s += "_"; } else { s += input[i]; } } return s; } std::string ToDasher(const std::string &input) { std::string s; char p = 0; for (size_t i = 0; i < input.length(); i++) { char const &c = input[i]; if (c == '_') { if (i > 0 && p != kPathSeparator && // The following is a special case to ignore digits after a _. This is // because ThisExample3 would be converted to this_example_3 in the // CamelToSnake conversion, and then dasher would do this-example-3, // but it expects this-example3. !(i + 1 < input.length() && isdigit(input[i + 1]))) s += "-"; } else { s += c; } p = c; } return s; } // Converts foo_bar_123baz_456 to foo_bar123_baz456 std::string SnakeToSnake2(const std::string &s) { if (s.length() <= 1) return s; std::string result; result.reserve(s.size()); for (size_t i = 0; i < s.length() - 1; i++) { if (s[i] == '_' && isdigit(s[i + 1])) { continue; // Move the `_` until after the digits. } result.push_back(s[i]); if (isdigit(s[i]) && isalpha(s[i + 1]) && islower(s[i + 1])) { result.push_back('_'); } } result.push_back(s.back()); return result; } } // namespace bool LoadFile(const char *name, bool binary, std::string *buf) { FLATBUFFERS_ASSERT(g_load_file_function); return g_load_file_function(name, binary, buf); } bool FileExists(const char *name) { FLATBUFFERS_ASSERT(g_file_exists_function); return g_file_exists_function(name); } bool DirExists(const char *name) { // clang-format off #ifdef _WIN32 #define flatbuffers_stat _stat #define FLATBUFFERS_S_IFDIR _S_IFDIR #else #define flatbuffers_stat stat #define FLATBUFFERS_S_IFDIR S_IFDIR #endif // clang-format on struct flatbuffers_stat file_info; if (flatbuffers_stat(name, &file_info) != 0) return false; return (file_info.st_mode & FLATBUFFERS_S_IFDIR) != 0; } LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function) { LoadFileFunction previous_function = g_load_file_function; g_load_file_function = load_file_function ? load_file_function : LoadFileRaw; return previous_function; } FileExistsFunction SetFileExistsFunction( FileExistsFunction file_exists_function) { FileExistsFunction previous_function = g_file_exists_function; g_file_exists_function = file_exists_function ? file_exists_function : FileExistsRaw; return previous_function; } bool SaveFile(const char *name, const char *buf, size_t len, bool binary) { std::ofstream ofs(name, binary ? std::ofstream::binary : std::ofstream::out); if (!ofs.is_open()) return false; ofs.write(buf, len); return !ofs.bad(); } // We internally store paths in posix format ('/'). Paths supplied // by the user should go through PosixPath to ensure correct behavior // on Windows when paths are string-compared. static const char kPathSeparatorWindows = '\\'; static const char *PathSeparatorSet = "\\/"; // Intentionally no ':' std::string StripExtension(const std::string &filepath) { size_t i = filepath.find_last_of('.'); return i != std::string::npos ? filepath.substr(0, i) : filepath; } std::string GetExtension(const std::string &filepath) { size_t i = filepath.find_last_of('.'); return i != std::string::npos ? filepath.substr(i + 1) : ""; } std::string StripPath(const std::string &filepath) { size_t i = filepath.find_last_of(PathSeparatorSet); return i != std::string::npos ? filepath.substr(i + 1) : filepath; } std::string StripFileName(const std::string &filepath) { size_t i = filepath.find_last_of(PathSeparatorSet); return i != std::string::npos ? filepath.substr(0, i) : ""; } std::string StripPrefix(const std::string &filepath, const std::string &prefix_to_remove) { if (!strncmp(filepath.c_str(), prefix_to_remove.c_str(), prefix_to_remove.size())) { return filepath.substr(prefix_to_remove.size()); } return filepath; } std::string ConCatPathFileName(const std::string &path, const std::string &filename) { std::string filepath = path; if (filepath.length()) { char &filepath_last_character = filepath.back(); if (filepath_last_character == kPathSeparatorWindows) { filepath_last_character = kPathSeparator; } else if (filepath_last_character != kPathSeparator) { filepath += kPathSeparator; } } filepath += filename; // Ignore './' at the start of filepath. if (filepath[0] == '.' && filepath[1] == kPathSeparator) { filepath.erase(0, 2); } return filepath; } std::string PosixPath(const char *path) { std::string p = path; std::replace(p.begin(), p.end(), '\\', '/'); return p; } std::string PosixPath(const std::string &path) { return PosixPath(path.c_str()); } void EnsureDirExists(const std::string &filepath) { auto parent = StripFileName(filepath); if (parent.length()) EnsureDirExists(parent); // clang-format off #ifdef _WIN32 (void)_mkdir(filepath.c_str()); #else mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP); #endif // clang-format on } std::string AbsolutePath(const std::string &filepath) { // clang-format off #ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION return filepath; #else #if defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) char abs_path[MAX_PATH]; return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr) #else char *abs_path_temp = realpath(filepath.c_str(), nullptr); bool success = abs_path_temp != nullptr; std::string abs_path; if(success) { abs_path = abs_path_temp; free(abs_path_temp); } return success #endif ? abs_path : filepath; #endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION // clang-format on } std::string RelativeToRootPath(const std::string &project, const std::string &filepath) { std::string absolute_project = PosixPath(AbsolutePath(project)); if (absolute_project.back() != '/') absolute_project += "/"; std::string absolute_filepath = PosixPath(AbsolutePath(filepath)); // Find the first character where they disagree. // The previous directory is the lowest common ancestor; const char *a = absolute_project.c_str(); const char *b = absolute_filepath.c_str(); size_t common_prefix_len = 0; while (*a != '\0' && *b != '\0' && *a == *b) { if (*a == '/') common_prefix_len = a - absolute_project.c_str(); a++; b++; } // the number of ../ to prepend to b depends on the number of remaining // directories in A. const char *suffix = absolute_project.c_str() + common_prefix_len; size_t num_up = 0; while (*suffix != '\0') if (*suffix++ == '/') num_up++; num_up--; // last one is known to be '/'. std::string result = "//"; for (size_t i = 0; i < num_up; i++) result += "../"; result += absolute_filepath.substr(common_prefix_len + 1); return result; } // Locale-independent code. #if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \ (FLATBUFFERS_LOCALE_INDEPENDENT > 0) // clang-format off // Allocate locale instance at startup of application. ClassicLocale ClassicLocale::instance_; #ifdef _MSC_VER ClassicLocale::ClassicLocale() : locale_(_create_locale(LC_ALL, "C")) {} ClassicLocale::~ClassicLocale() { _free_locale(locale_); } #else ClassicLocale::ClassicLocale() : locale_(newlocale(LC_ALL, "C", nullptr)) {} ClassicLocale::~ClassicLocale() { freelocale(locale_); } #endif // clang-format on #endif // !FLATBUFFERS_LOCALE_INDEPENDENT std::string RemoveStringQuotes(const std::string &s) { auto ch = *s.c_str(); return ((s.size() >= 2) && (ch == '\"' || ch == '\'') && (ch == s.back())) ? s.substr(1, s.length() - 2) : s; } bool SetGlobalTestLocale(const char *locale_name, std::string *_value) { const auto the_locale = setlocale(LC_ALL, locale_name); if (!the_locale) return false; if (_value) *_value = std::string(the_locale); return true; } bool ReadEnvironmentVariable(const char *var_name, std::string *_value) { #ifdef _MSC_VER __pragma(warning(disable : 4996)); // _CRT_SECURE_NO_WARNINGS #endif auto env_str = std::getenv(var_name); if (!env_str) return false; if (_value) *_value = std::string(env_str); return true; } std::string ConvertCase(const std::string &input, Case output_case, Case input_case) { if (output_case == Case::kKeep) return input; // The output cases expect snake_case inputs, so if we don't have that input // format, try to convert to snake_case. switch (input_case) { case Case::kLowerCamel: case Case::kUpperCamel: return ConvertCase(CamelToSnake(input), output_case); case Case::kDasher: return ConvertCase(DasherToSnake(input), output_case); case Case::kKeep: printf("WARNING: Converting from kKeep case.\n"); break; default: case Case::kSnake: case Case::kScreamingSnake: case Case::kAllLower: case Case::kAllUpper: break; } switch (output_case) { case Case::kUpperCamel: return ToCamelCase(input, true); case Case::kLowerCamel: return ToCamelCase(input, false); case Case::kSnake: return input; case Case::kScreamingSnake: return ToSnakeCase(input, true); case Case::kAllUpper: return ToAll(input, CharToUpper); case Case::kAllLower: return ToAll(input, CharToLower); case Case::kDasher: return ToDasher(input); case Case::kSnake2: return SnakeToSnake2(input); default: case Case::kUnknown: return input; } } } // namespace flatbuffers