1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/webrtc/trunk/testing/gtest/src/gtest-filepath.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,380 @@ 1.4 +// Copyright 2008, Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 +// 1.33 +// Authors: keith.ray@gmail.com (Keith Ray) 1.34 + 1.35 +#include "gtest/internal/gtest-filepath.h" 1.36 +#include "gtest/internal/gtest-port.h" 1.37 + 1.38 +#include <stdlib.h> 1.39 + 1.40 +#if GTEST_OS_WINDOWS_MOBILE 1.41 +# include <windows.h> 1.42 +#elif GTEST_OS_WINDOWS 1.43 +# include <direct.h> 1.44 +# include <io.h> 1.45 +#elif GTEST_OS_SYMBIAN 1.46 +// Symbian OpenC has PATH_MAX in sys/syslimits.h 1.47 +# include <sys/syslimits.h> 1.48 +#else 1.49 +# include <limits.h> 1.50 +# include <climits> // Some Linux distributions define PATH_MAX here. 1.51 +#endif // GTEST_OS_WINDOWS_MOBILE 1.52 + 1.53 +#if GTEST_OS_WINDOWS 1.54 +# define GTEST_PATH_MAX_ _MAX_PATH 1.55 +#elif defined(PATH_MAX) 1.56 +# define GTEST_PATH_MAX_ PATH_MAX 1.57 +#elif defined(_XOPEN_PATH_MAX) 1.58 +# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX 1.59 +#else 1.60 +# define GTEST_PATH_MAX_ _POSIX_PATH_MAX 1.61 +#endif // GTEST_OS_WINDOWS 1.62 + 1.63 +#include "gtest/internal/gtest-string.h" 1.64 + 1.65 +namespace testing { 1.66 +namespace internal { 1.67 + 1.68 +#if GTEST_OS_WINDOWS 1.69 +// On Windows, '\\' is the standard path separator, but many tools and the 1.70 +// Windows API also accept '/' as an alternate path separator. Unless otherwise 1.71 +// noted, a file path can contain either kind of path separators, or a mixture 1.72 +// of them. 1.73 +const char kPathSeparator = '\\'; 1.74 +const char kAlternatePathSeparator = '/'; 1.75 +const char kPathSeparatorString[] = "\\"; 1.76 +const char kAlternatePathSeparatorString[] = "/"; 1.77 +# if GTEST_OS_WINDOWS_MOBILE 1.78 +// Windows CE doesn't have a current directory. You should not use 1.79 +// the current directory in tests on Windows CE, but this at least 1.80 +// provides a reasonable fallback. 1.81 +const char kCurrentDirectoryString[] = "\\"; 1.82 +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES 1.83 +const DWORD kInvalidFileAttributes = 0xffffffff; 1.84 +# else 1.85 +const char kCurrentDirectoryString[] = ".\\"; 1.86 +# endif // GTEST_OS_WINDOWS_MOBILE 1.87 +#else 1.88 +const char kPathSeparator = '/'; 1.89 +const char kPathSeparatorString[] = "/"; 1.90 +const char kCurrentDirectoryString[] = "./"; 1.91 +#endif // GTEST_OS_WINDOWS 1.92 + 1.93 +// Returns whether the given character is a valid path separator. 1.94 +static bool IsPathSeparator(char c) { 1.95 +#if GTEST_HAS_ALT_PATH_SEP_ 1.96 + return (c == kPathSeparator) || (c == kAlternatePathSeparator); 1.97 +#else 1.98 + return c == kPathSeparator; 1.99 +#endif 1.100 +} 1.101 + 1.102 +// Returns the current working directory, or "" if unsuccessful. 1.103 +FilePath FilePath::GetCurrentDir() { 1.104 +#if GTEST_OS_WINDOWS_MOBILE 1.105 + // Windows CE doesn't have a current directory, so we just return 1.106 + // something reasonable. 1.107 + return FilePath(kCurrentDirectoryString); 1.108 +#elif GTEST_OS_WINDOWS 1.109 + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; 1.110 + return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); 1.111 +#else 1.112 + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; 1.113 + return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); 1.114 +#endif // GTEST_OS_WINDOWS_MOBILE 1.115 +} 1.116 + 1.117 +// Returns a copy of the FilePath with the case-insensitive extension removed. 1.118 +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns 1.119 +// FilePath("dir/file"). If a case-insensitive extension is not 1.120 +// found, returns a copy of the original FilePath. 1.121 +FilePath FilePath::RemoveExtension(const char* extension) const { 1.122 + String dot_extension(String::Format(".%s", extension)); 1.123 + if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { 1.124 + return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); 1.125 + } 1.126 + return *this; 1.127 +} 1.128 + 1.129 +// Returns a pointer to the last occurence of a valid path separator in 1.130 +// the FilePath. On Windows, for example, both '/' and '\' are valid path 1.131 +// separators. Returns NULL if no path separator was found. 1.132 +const char* FilePath::FindLastPathSeparator() const { 1.133 + const char* const last_sep = strrchr(c_str(), kPathSeparator); 1.134 +#if GTEST_HAS_ALT_PATH_SEP_ 1.135 + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); 1.136 + // Comparing two pointers of which only one is NULL is undefined. 1.137 + if (last_alt_sep != NULL && 1.138 + (last_sep == NULL || last_alt_sep > last_sep)) { 1.139 + return last_alt_sep; 1.140 + } 1.141 +#endif 1.142 + return last_sep; 1.143 +} 1.144 + 1.145 +// Returns a copy of the FilePath with the directory part removed. 1.146 +// Example: FilePath("path/to/file").RemoveDirectoryName() returns 1.147 +// FilePath("file"). If there is no directory part ("just_a_file"), it returns 1.148 +// the FilePath unmodified. If there is no file part ("just_a_dir/") it 1.149 +// returns an empty FilePath (""). 1.150 +// On Windows platform, '\' is the path separator, otherwise it is '/'. 1.151 +FilePath FilePath::RemoveDirectoryName() const { 1.152 + const char* const last_sep = FindLastPathSeparator(); 1.153 + return last_sep ? FilePath(String(last_sep + 1)) : *this; 1.154 +} 1.155 + 1.156 +// RemoveFileName returns the directory path with the filename removed. 1.157 +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". 1.158 +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns 1.159 +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does 1.160 +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. 1.161 +// On Windows platform, '\' is the path separator, otherwise it is '/'. 1.162 +FilePath FilePath::RemoveFileName() const { 1.163 + const char* const last_sep = FindLastPathSeparator(); 1.164 + String dir; 1.165 + if (last_sep) { 1.166 + dir = String(c_str(), last_sep + 1 - c_str()); 1.167 + } else { 1.168 + dir = kCurrentDirectoryString; 1.169 + } 1.170 + return FilePath(dir); 1.171 +} 1.172 + 1.173 +// Helper functions for naming files in a directory for xml output. 1.174 + 1.175 +// Given directory = "dir", base_name = "test", number = 0, 1.176 +// extension = "xml", returns "dir/test.xml". If number is greater 1.177 +// than zero (e.g., 12), returns "dir/test_12.xml". 1.178 +// On Windows platform, uses \ as the separator rather than /. 1.179 +FilePath FilePath::MakeFileName(const FilePath& directory, 1.180 + const FilePath& base_name, 1.181 + int number, 1.182 + const char* extension) { 1.183 + String file; 1.184 + if (number == 0) { 1.185 + file = String::Format("%s.%s", base_name.c_str(), extension); 1.186 + } else { 1.187 + file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); 1.188 + } 1.189 + return ConcatPaths(directory, FilePath(file)); 1.190 +} 1.191 + 1.192 +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". 1.193 +// On Windows, uses \ as the separator rather than /. 1.194 +FilePath FilePath::ConcatPaths(const FilePath& directory, 1.195 + const FilePath& relative_path) { 1.196 + if (directory.IsEmpty()) 1.197 + return relative_path; 1.198 + const FilePath dir(directory.RemoveTrailingPathSeparator()); 1.199 + return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, 1.200 + relative_path.c_str())); 1.201 +} 1.202 + 1.203 +// Returns true if pathname describes something findable in the file-system, 1.204 +// either a file, directory, or whatever. 1.205 +bool FilePath::FileOrDirectoryExists() const { 1.206 +#if GTEST_OS_WINDOWS_MOBILE 1.207 + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); 1.208 + const DWORD attributes = GetFileAttributes(unicode); 1.209 + delete [] unicode; 1.210 + return attributes != kInvalidFileAttributes; 1.211 +#else 1.212 + posix::StatStruct file_stat; 1.213 + return posix::Stat(pathname_.c_str(), &file_stat) == 0; 1.214 +#endif // GTEST_OS_WINDOWS_MOBILE 1.215 +} 1.216 + 1.217 +// Returns true if pathname describes a directory in the file-system 1.218 +// that exists. 1.219 +bool FilePath::DirectoryExists() const { 1.220 + bool result = false; 1.221 +#if GTEST_OS_WINDOWS 1.222 + // Don't strip off trailing separator if path is a root directory on 1.223 + // Windows (like "C:\\"). 1.224 + const FilePath& path(IsRootDirectory() ? *this : 1.225 + RemoveTrailingPathSeparator()); 1.226 +#else 1.227 + const FilePath& path(*this); 1.228 +#endif 1.229 + 1.230 +#if GTEST_OS_WINDOWS_MOBILE 1.231 + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); 1.232 + const DWORD attributes = GetFileAttributes(unicode); 1.233 + delete [] unicode; 1.234 + if ((attributes != kInvalidFileAttributes) && 1.235 + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { 1.236 + result = true; 1.237 + } 1.238 +#else 1.239 + posix::StatStruct file_stat; 1.240 + result = posix::Stat(path.c_str(), &file_stat) == 0 && 1.241 + posix::IsDir(file_stat); 1.242 +#endif // GTEST_OS_WINDOWS_MOBILE 1.243 + 1.244 + return result; 1.245 +} 1.246 + 1.247 +// Returns true if pathname describes a root directory. (Windows has one 1.248 +// root directory per disk drive.) 1.249 +bool FilePath::IsRootDirectory() const { 1.250 +#if GTEST_OS_WINDOWS 1.251 + // TODO(wan@google.com): on Windows a network share like 1.252 + // \\server\share can be a root directory, although it cannot be the 1.253 + // current directory. Handle this properly. 1.254 + return pathname_.length() == 3 && IsAbsolutePath(); 1.255 +#else 1.256 + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); 1.257 +#endif 1.258 +} 1.259 + 1.260 +// Returns true if pathname describes an absolute path. 1.261 +bool FilePath::IsAbsolutePath() const { 1.262 + const char* const name = pathname_.c_str(); 1.263 +#if GTEST_OS_WINDOWS 1.264 + return pathname_.length() >= 3 && 1.265 + ((name[0] >= 'a' && name[0] <= 'z') || 1.266 + (name[0] >= 'A' && name[0] <= 'Z')) && 1.267 + name[1] == ':' && 1.268 + IsPathSeparator(name[2]); 1.269 +#else 1.270 + return IsPathSeparator(name[0]); 1.271 +#endif 1.272 +} 1.273 + 1.274 +// Returns a pathname for a file that does not currently exist. The pathname 1.275 +// will be directory/base_name.extension or 1.276 +// directory/base_name_<number>.extension if directory/base_name.extension 1.277 +// already exists. The number will be incremented until a pathname is found 1.278 +// that does not already exist. 1.279 +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. 1.280 +// There could be a race condition if two or more processes are calling this 1.281 +// function at the same time -- they could both pick the same filename. 1.282 +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, 1.283 + const FilePath& base_name, 1.284 + const char* extension) { 1.285 + FilePath full_pathname; 1.286 + int number = 0; 1.287 + do { 1.288 + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); 1.289 + } while (full_pathname.FileOrDirectoryExists()); 1.290 + return full_pathname; 1.291 +} 1.292 + 1.293 +// Returns true if FilePath ends with a path separator, which indicates that 1.294 +// it is intended to represent a directory. Returns false otherwise. 1.295 +// This does NOT check that a directory (or file) actually exists. 1.296 +bool FilePath::IsDirectory() const { 1.297 + return !pathname_.empty() && 1.298 + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); 1.299 +} 1.300 + 1.301 +// Create directories so that path exists. Returns true if successful or if 1.302 +// the directories already exist; returns false if unable to create directories 1.303 +// for any reason. 1.304 +bool FilePath::CreateDirectoriesRecursively() const { 1.305 + if (!this->IsDirectory()) { 1.306 + return false; 1.307 + } 1.308 + 1.309 + if (pathname_.length() == 0 || this->DirectoryExists()) { 1.310 + return true; 1.311 + } 1.312 + 1.313 + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); 1.314 + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); 1.315 +} 1.316 + 1.317 +// Create the directory so that path exists. Returns true if successful or 1.318 +// if the directory already exists; returns false if unable to create the 1.319 +// directory for any reason, including if the parent directory does not 1.320 +// exist. Not named "CreateDirectory" because that's a macro on Windows. 1.321 +bool FilePath::CreateFolder() const { 1.322 +#if GTEST_OS_WINDOWS_MOBILE 1.323 + FilePath removed_sep(this->RemoveTrailingPathSeparator()); 1.324 + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); 1.325 + int result = CreateDirectory(unicode, NULL) ? 0 : -1; 1.326 + delete [] unicode; 1.327 +#elif GTEST_OS_WINDOWS 1.328 + int result = _mkdir(pathname_.c_str()); 1.329 +#else 1.330 + int result = mkdir(pathname_.c_str(), 0777); 1.331 +#endif // GTEST_OS_WINDOWS_MOBILE 1.332 + 1.333 + if (result == -1) { 1.334 + return this->DirectoryExists(); // An error is OK if the directory exists. 1.335 + } 1.336 + return true; // No error. 1.337 +} 1.338 + 1.339 +// If input name has a trailing separator character, remove it and return the 1.340 +// name, otherwise return the name string unmodified. 1.341 +// On Windows platform, uses \ as the separator, other platforms use /. 1.342 +FilePath FilePath::RemoveTrailingPathSeparator() const { 1.343 + return IsDirectory() 1.344 + ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) 1.345 + : *this; 1.346 +} 1.347 + 1.348 +// Removes any redundant separators that might be in the pathname. 1.349 +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other 1.350 +// redundancies that might be in a pathname involving "." or "..". 1.351 +// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). 1.352 +void FilePath::Normalize() { 1.353 + if (pathname_.c_str() == NULL) { 1.354 + pathname_ = ""; 1.355 + return; 1.356 + } 1.357 + const char* src = pathname_.c_str(); 1.358 + char* const dest = new char[pathname_.length() + 1]; 1.359 + char* dest_ptr = dest; 1.360 + memset(dest_ptr, 0, pathname_.length() + 1); 1.361 + 1.362 + while (*src != '\0') { 1.363 + *dest_ptr = *src; 1.364 + if (!IsPathSeparator(*src)) { 1.365 + src++; 1.366 + } else { 1.367 +#if GTEST_HAS_ALT_PATH_SEP_ 1.368 + if (*dest_ptr == kAlternatePathSeparator) { 1.369 + *dest_ptr = kPathSeparator; 1.370 + } 1.371 +#endif 1.372 + while (IsPathSeparator(*src)) 1.373 + src++; 1.374 + } 1.375 + dest_ptr++; 1.376 + } 1.377 + *dest_ptr = '\0'; 1.378 + pathname_ = dest; 1.379 + delete[] dest; 1.380 +} 1.381 + 1.382 +} // namespace internal 1.383 +} // namespace testing