1 /* 2 * Copyright 2014 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 #ifndef FLATBUFFERS_UTIL_H_ 18 #define FLATBUFFERS_UTIL_H_ 19 20 #include <fstream> 21 #include <iomanip> 22 #include <string> 23 #include <sstream> 24 #include <stdint.h> 25 #include <stdlib.h> 26 #include <assert.h> 27 #ifdef _WIN32 28 #ifndef WIN32_LEAN_AND_MEAN 29 #define WIN32_LEAN_AND_MEAN 30 #endif 31 #ifndef NOMINMAX 32 #define NOMINMAX 33 #endif 34 #include <windows.h> 35 #include <winbase.h> 36 #include <direct.h> 37 #else 38 #include <limits.h> 39 #endif 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 43 #include "flatbuffers/flatbuffers.h" 44 45 namespace flatbuffers { 46 47 // Convert an integer or floating point value to a string. 48 // In contrast to std::stringstream, "char" values are 49 // converted to a string of digits, and we don't use scientific notation. 50 template<typename T> std::string NumToString(T t) { 51 std::stringstream ss; 52 ss << t; 53 return ss.str(); 54 } 55 // Avoid char types used as character data. 56 template<> inline std::string NumToString<signed char>(signed char t) { 57 return NumToString(static_cast<int>(t)); 58 } 59 template<> inline std::string NumToString<unsigned char>(unsigned char t) { 60 return NumToString(static_cast<int>(t)); 61 } 62 63 // Special versions for floats/doubles. 64 template<> inline std::string NumToString<double>(double t) { 65 // to_string() prints different numbers of digits for floats depending on 66 // platform and isn't available on Android, so we use stringstream 67 std::stringstream ss; 68 // Use std::fixed to surpress scientific notation. 69 ss << std::fixed << t; 70 auto s = ss.str(); 71 // Sadly, std::fixed turns "1" into "1.00000", so here we undo that. 72 auto p = s.find_last_not_of('0'); 73 if (p != std::string::npos) { 74 s.resize(p + 1); // Strip trailing zeroes. 75 if (s[s.size() - 1] == '.') 76 s.erase(s.size() - 1, 1); // Strip '.' if a whole number. 77 } 78 return s; 79 } 80 template<> inline std::string NumToString<float>(float t) { 81 return NumToString(static_cast<double>(t)); 82 } 83 84 // Convert an integer value to a hexadecimal string. 85 // The returned string length is always xdigits long, prefixed by 0 digits. 86 // For example, IntToStringHex(0x23, 8) returns the string "00000023". 87 inline std::string IntToStringHex(int i, int xdigits) { 88 std::stringstream ss; 89 ss << std::setw(xdigits) 90 << std::setfill('0') 91 << std::hex 92 << std::uppercase 93 << i; 94 return ss.str(); 95 } 96 97 // Portable implementation of strtoll(). 98 inline int64_t StringToInt(const char *str, char **endptr = nullptr, 99 int base = 10) { 100 #ifdef _MSC_VER 101 return _strtoi64(str, endptr, base); 102 #else 103 return strtoll(str, endptr, base); 104 #endif 105 } 106 107 // Portable implementation of strtoull(). 108 inline uint64_t StringToUInt(const char *str, char **endptr = nullptr, 109 int base = 10) { 110 #ifdef _MSC_VER 111 return _strtoui64(str, endptr, base); 112 #else 113 return strtoull(str, endptr, base); 114 #endif 115 } 116 117 typedef bool (*LoadFileFunction)(const char *filename, bool binary, 118 std::string *dest); 119 typedef bool (*FileExistsFunction)(const char *filename); 120 121 LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function); 122 123 FileExistsFunction SetFileExistsFunction(FileExistsFunction 124 file_exists_function); 125 126 127 // Check if file "name" exists. 128 bool FileExists(const char *name); 129 130 // Check if "name" exists and it is also a directory. 131 bool DirExists(const char *name); 132 133 // Load file "name" into "buf" returning true if successful 134 // false otherwise. If "binary" is false data is read 135 // using ifstream's text mode, otherwise data is read with 136 // no transcoding. 137 bool LoadFile(const char *name, bool binary, std::string *buf); 138 139 // Save data "buf" of length "len" bytes into a file 140 // "name" returning true if successful, false otherwise. 141 // If "binary" is false data is written using ifstream's 142 // text mode, otherwise data is written with no 143 // transcoding. 144 inline bool SaveFile(const char *name, const char *buf, size_t len, 145 bool binary) { 146 std::ofstream ofs(name, binary ? std::ofstream::binary : std::ofstream::out); 147 if (!ofs.is_open()) return false; 148 ofs.write(buf, len); 149 return !ofs.bad(); 150 } 151 152 // Save data "buf" into file "name" returning true if 153 // successful, false otherwise. If "binary" is false 154 // data is written using ifstream's text mode, otherwise 155 // data is written with no transcoding. 156 inline bool SaveFile(const char *name, const std::string &buf, bool binary) { 157 return SaveFile(name, buf.c_str(), buf.size(), binary); 158 } 159 160 // Functionality for minimalistic portable path handling: 161 162 static const char kPosixPathSeparator = '/'; 163 #ifdef _WIN32 164 static const char kPathSeparator = '\\'; 165 static const char *PathSeparatorSet = "\\/"; // Intentionally no ':' 166 #else 167 static const char kPathSeparator = kPosixPathSeparator; 168 static const char *PathSeparatorSet = "/"; 169 #endif // _WIN32 170 171 // Returns the path with the extension, if any, removed. 172 inline std::string StripExtension(const std::string &filepath) { 173 size_t i = filepath.find_last_of("."); 174 return i != std::string::npos ? filepath.substr(0, i) : filepath; 175 } 176 177 // Returns the extension, if any. 178 inline std::string GetExtension(const std::string &filepath) { 179 size_t i = filepath.find_last_of("."); 180 return i != std::string::npos ? filepath.substr(i + 1) : ""; 181 } 182 183 // Return the last component of the path, after the last separator. 184 inline std::string StripPath(const std::string &filepath) { 185 size_t i = filepath.find_last_of(PathSeparatorSet); 186 return i != std::string::npos ? filepath.substr(i + 1) : filepath; 187 } 188 189 // Strip the last component of the path + separator. 190 inline std::string StripFileName(const std::string &filepath) { 191 size_t i = filepath.find_last_of(PathSeparatorSet); 192 return i != std::string::npos ? filepath.substr(0, i) : ""; 193 } 194 195 // Concatenates a path with a filename, regardless of wether the path 196 // ends in a separator or not. 197 inline std::string ConCatPathFileName(const std::string &path, 198 const std::string &filename) { 199 std::string filepath = path; 200 if (path.length() && path[path.size() - 1] != kPathSeparator && 201 path[path.size() - 1] != kPosixPathSeparator) 202 filepath += kPathSeparator; 203 filepath += filename; 204 return filepath; 205 } 206 207 // This function ensure a directory exists, by recursively 208 // creating dirs for any parts of the path that don't exist yet. 209 inline void EnsureDirExists(const std::string &filepath) { 210 auto parent = StripFileName(filepath); 211 if (parent.length()) EnsureDirExists(parent); 212 #ifdef _WIN32 213 (void)_mkdir(filepath.c_str()); 214 #else 215 mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP); 216 #endif 217 } 218 219 // Obtains the absolute path from any other path. 220 // Returns the input path if the absolute path couldn't be resolved. 221 inline std::string AbsolutePath(const std::string &filepath) { 222 #ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION 223 return filepath; 224 #else 225 #ifdef _WIN32 226 char abs_path[MAX_PATH]; 227 return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr) 228 #else 229 char abs_path[PATH_MAX]; 230 return realpath(filepath.c_str(), abs_path) 231 #endif 232 ? abs_path 233 : filepath; 234 #endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION 235 } 236 237 // To and from UTF-8 unicode conversion functions 238 239 // Convert a unicode code point into a UTF-8 representation by appending it 240 // to a string. Returns the number of bytes generated. 241 inline int ToUTF8(uint32_t ucc, std::string *out) { 242 assert(!(ucc & 0x80000000)); // Top bit can't be set. 243 // 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8 244 for (int i = 0; i < 6; i++) { 245 // Max bits this encoding can represent. 246 uint32_t max_bits = 6 + i * 5 + static_cast<int>(!i); 247 if (ucc < (1u << max_bits)) { // does it fit? 248 // Remaining bits not encoded in the first byte, store 6 bits each 249 uint32_t remain_bits = i * 6; 250 // Store first byte: 251 (*out) += static_cast<char>((0xFE << (max_bits - remain_bits)) | 252 (ucc >> remain_bits)); 253 // Store remaining bytes: 254 for (int j = i - 1; j >= 0; j--) { 255 (*out) += static_cast<char>(((ucc >> (j * 6)) & 0x3F) | 0x80); 256 } 257 return i + 1; // Return the number of bytes added. 258 } 259 } 260 assert(0); // Impossible to arrive here. 261 return -1; 262 } 263 264 // Converts whatever prefix of the incoming string corresponds to a valid 265 // UTF-8 sequence into a unicode code. The incoming pointer will have been 266 // advanced past all bytes parsed. 267 // returns -1 upon corrupt UTF-8 encoding (ignore the incoming pointer in 268 // this case). 269 inline int FromUTF8(const char **in) { 270 int len = 0; 271 // Count leading 1 bits. 272 for (int mask = 0x80; mask >= 0x04; mask >>= 1) { 273 if (**in & mask) { 274 len++; 275 } else { 276 break; 277 } 278 } 279 if ((**in << len) & 0x80) return -1; // Bit after leading 1's must be 0. 280 if (!len) return *(*in)++; 281 // UTF-8 encoded values with a length are between 2 and 4 bytes. 282 if (len < 2 || len > 4) { 283 return -1; 284 } 285 // Grab initial bits of the code. 286 int ucc = *(*in)++ & ((1 << (7 - len)) - 1); 287 for (int i = 0; i < len - 1; i++) { 288 if ((**in & 0xC0) != 0x80) return -1; // Upper bits must 1 0. 289 ucc <<= 6; 290 ucc |= *(*in)++ & 0x3F; // Grab 6 more bits of the code. 291 } 292 // UTF-8 cannot encode values between 0xD800 and 0xDFFF (reserved for 293 // UTF-16 surrogate pairs). 294 if (ucc >= 0xD800 && ucc <= 0xDFFF) { 295 return -1; 296 } 297 // UTF-8 must represent code points in their shortest possible encoding. 298 switch (len) { 299 case 2: 300 // Two bytes of UTF-8 can represent code points from U+0080 to U+07FF. 301 if (ucc < 0x0080 || ucc > 0x07FF) { 302 return -1; 303 } 304 break; 305 case 3: 306 // Three bytes of UTF-8 can represent code points from U+0800 to U+FFFF. 307 if (ucc < 0x0800 || ucc > 0xFFFF) { 308 return -1; 309 } 310 break; 311 case 4: 312 // Four bytes of UTF-8 can represent code points from U+10000 to U+10FFFF. 313 if (ucc < 0x10000 || ucc > 0x10FFFF) { 314 return -1; 315 } 316 break; 317 } 318 return ucc; 319 } 320 321 // Wraps a string to a maximum length, inserting new lines where necessary. Any 322 // existing whitespace will be collapsed down to a single space. A prefix or 323 // suffix can be provided, which will be inserted before or after a wrapped 324 // line, respectively. 325 inline std::string WordWrap(const std::string in, size_t max_length, 326 const std::string wrapped_line_prefix, 327 const std::string wrapped_line_suffix) { 328 std::istringstream in_stream(in); 329 std::string wrapped, line, word; 330 331 in_stream >> word; 332 line = word; 333 334 while (in_stream >> word) { 335 if ((line.length() + 1 + word.length() + wrapped_line_suffix.length()) < 336 max_length) { 337 line += " " + word; 338 } else { 339 wrapped += line + wrapped_line_suffix + "\n"; 340 line = wrapped_line_prefix + word; 341 } 342 } 343 wrapped += line; 344 345 return wrapped; 346 } 347 348 } // namespace flatbuffers 349 350 #endif // FLATBUFFERS_UTIL_H_ 351