blob: 60e2b8bf47e51d6ffd0e9db7a8d04a68f0f9eb8d [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#if defined(WEBRTC_WIN)
12#include "webrtc/base/win32.h"
13#include <shellapi.h>
14#include <shlobj.h>
15#include <tchar.h>
kjellander470dd372016-04-19 03:03:23 -070016#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000017
18#include "webrtc/base/common.h"
19#include "webrtc/base/fileutils.h"
20#include "webrtc/base/logging.h"
21#include "webrtc/base/pathutils.h"
22#include "webrtc/base/stringutils.h"
23#include "webrtc/base/urlencode.h"
24
25namespace rtc {
26
27static const char EMPTY_STR[] = "";
28
29// EXT_DELIM separates a file basename from extension
30const char EXT_DELIM = '.';
31
32// FOLDER_DELIMS separate folder segments and the filename
33const char* const FOLDER_DELIMS = "/\\";
34
35// DEFAULT_FOLDER_DELIM is the preferred delimiter for this platform
36#if WEBRTC_WIN
37const char DEFAULT_FOLDER_DELIM = '\\';
kjellander470dd372016-04-19 03:03:23 -070038#else // !WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000039const char DEFAULT_FOLDER_DELIM = '/';
kjellander470dd372016-04-19 03:03:23 -070040#endif // !WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000041
42///////////////////////////////////////////////////////////////////////////////
43// Pathname - parsing of pathnames into components, and vice versa
44///////////////////////////////////////////////////////////////////////////////
45
46bool Pathname::IsFolderDelimiter(char ch) {
47 return (NULL != ::strchr(FOLDER_DELIMS, ch));
48}
49
50char Pathname::DefaultFolderDelimiter() {
51 return DEFAULT_FOLDER_DELIM;
52}
53
54Pathname::Pathname()
55 : folder_delimiter_(DEFAULT_FOLDER_DELIM) {
56}
57
kjellander470dd372016-04-19 03:03:23 -070058Pathname::Pathname(const Pathname&) = default;
59
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000060Pathname::Pathname(const std::string& pathname)
61 : folder_delimiter_(DEFAULT_FOLDER_DELIM) {
62 SetPathname(pathname);
63}
64
65Pathname::Pathname(const std::string& folder, const std::string& filename)
66 : folder_delimiter_(DEFAULT_FOLDER_DELIM) {
67 SetPathname(folder, filename);
68}
69
70void Pathname::SetFolderDelimiter(char delimiter) {
71 ASSERT(IsFolderDelimiter(delimiter));
72 folder_delimiter_ = delimiter;
73}
74
75void Pathname::Normalize() {
76 for (size_t i=0; i<folder_.length(); ++i) {
77 if (IsFolderDelimiter(folder_[i])) {
78 folder_[i] = folder_delimiter_;
79 }
80 }
81}
82
83void Pathname::clear() {
84 folder_.clear();
85 basename_.clear();
86 extension_.clear();
87}
88
89bool Pathname::empty() const {
90 return folder_.empty() && basename_.empty() && extension_.empty();
91}
92
93std::string Pathname::pathname() const {
94 std::string pathname(folder_);
95 pathname.append(basename_);
96 pathname.append(extension_);
97 if (pathname.empty()) {
98 // Instead of the empty pathname, return the current working directory.
99 pathname.push_back('.');
100 pathname.push_back(folder_delimiter_);
101 }
102 return pathname;
103}
104
105std::string Pathname::url() const {
106 std::string s = "file:///";
107 for (size_t i=0; i<folder_.length(); ++i) {
108 if (IsFolderDelimiter(folder_[i]))
109 s += '/';
110 else
111 s += folder_[i];
112 }
113 s += basename_;
114 s += extension_;
115 return UrlEncodeStringForOnlyUnsafeChars(s);
116}
117
118void Pathname::SetPathname(const std::string& pathname) {
119 std::string::size_type pos = pathname.find_last_of(FOLDER_DELIMS);
120 if (pos != std::string::npos) {
121 SetFolder(pathname.substr(0, pos + 1));
122 SetFilename(pathname.substr(pos + 1));
123 } else {
124 SetFolder(EMPTY_STR);
125 SetFilename(pathname);
126 }
127}
128
129void Pathname::SetPathname(const std::string& folder,
130 const std::string& filename) {
131 SetFolder(folder);
132 SetFilename(filename);
133}
134
135void Pathname::AppendPathname(const std::string& pathname) {
136 std::string full_pathname(folder_);
137 full_pathname.append(pathname);
138 SetPathname(full_pathname);
139}
140
141std::string Pathname::folder() const {
142 return folder_;
143}
144
145std::string Pathname::folder_name() const {
146 std::string::size_type pos = std::string::npos;
147 if (folder_.size() >= 2) {
148 pos = folder_.find_last_of(FOLDER_DELIMS, folder_.length() - 2);
149 }
150 if (pos != std::string::npos) {
151 return folder_.substr(pos + 1);
152 } else {
153 return folder_;
154 }
155}
156
157std::string Pathname::parent_folder() const {
158 std::string::size_type pos = std::string::npos;
159 if (folder_.size() >= 2) {
160 pos = folder_.find_last_of(FOLDER_DELIMS, folder_.length() - 2);
161 }
162 if (pos != std::string::npos) {
163 return folder_.substr(0, pos + 1);
164 } else {
165 return EMPTY_STR;
166 }
167}
168
169void Pathname::SetFolder(const std::string& folder) {
170 folder_.assign(folder);
171 // Ensure folder ends in a path delimiter
172 if (!folder_.empty() && !IsFolderDelimiter(folder_[folder_.length()-1])) {
173 folder_.push_back(folder_delimiter_);
174 }
175}
176
177void Pathname::AppendFolder(const std::string& folder) {
178 folder_.append(folder);
179 // Ensure folder ends in a path delimiter
180 if (!folder_.empty() && !IsFolderDelimiter(folder_[folder_.length()-1])) {
181 folder_.push_back(folder_delimiter_);
182 }
183}
184
185std::string Pathname::basename() const {
186 return basename_;
187}
188
189bool Pathname::SetBasename(const std::string& basename) {
190 if(basename.find_first_of(FOLDER_DELIMS) != std::string::npos) {
191 return false;
192 }
193 basename_.assign(basename);
194 return true;
195}
196
197std::string Pathname::extension() const {
198 return extension_;
199}
200
201bool Pathname::SetExtension(const std::string& extension) {
202 if (extension.find_first_of(FOLDER_DELIMS) != std::string::npos ||
203 extension.find_first_of(EXT_DELIM, 1) != std::string::npos) {
204 return false;
205 }
206 extension_.assign(extension);
207 // Ensure extension begins with the extension delimiter
208 if (!extension_.empty() && (extension_[0] != EXT_DELIM)) {
209 extension_.insert(extension_.begin(), EXT_DELIM);
210 }
211 return true;
212}
213
214std::string Pathname::filename() const {
215 std::string filename(basename_);
216 filename.append(extension_);
217 return filename;
218}
219
220bool Pathname::SetFilename(const std::string& filename) {
221 std::string::size_type pos = filename.rfind(EXT_DELIM);
222 if ((pos == std::string::npos) || (pos == 0)) {
223 return SetExtension(EMPTY_STR) && SetBasename(filename);
224 } else {
225 return SetExtension(filename.substr(pos)) && SetBasename(filename.substr(0, pos));
226 }
227}
228
229#if defined(WEBRTC_WIN)
Peter Boström0c4e06b2015-10-07 12:23:21 +0200230bool Pathname::GetDrive(char* drive, uint32_t bytes) const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000231 return GetDrive(drive, bytes, folder_);
232}
233
234// static
Peter Boström0c4e06b2015-10-07 12:23:21 +0200235bool Pathname::GetDrive(char* drive,
236 uint32_t bytes,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000237 const std::string& pathname) {
238 // need at lease 4 bytes to save c:
239 if (bytes < 4 || pathname.size() < 3) {
240 return false;
241 }
242
243 memcpy(drive, pathname.c_str(), 3);
244 drive[3] = 0;
245 // sanity checking
246 return (isalpha(drive[0]) &&
247 drive[1] == ':' &&
248 drive[2] == '\\');
249}
250#endif
251
252///////////////////////////////////////////////////////////////////////////////
253
254} // namespace rtc