blob: 8baf08ffdd394068e0dcc065964dcf54b45ff62a [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00007#include "SkOSFile.h"
8
tfarinaa8e2e152014-07-28 19:26:58 -07009SkString SkOSPath::Join(const char *rootPath, const char *relativePath) {
scroggo@google.comccd7afb2013-05-28 16:45:07 +000010 SkString result(rootPath);
11 if (!result.endsWith(SkPATH_SEPARATOR)) {
12 result.appendUnichar(SkPATH_SEPARATOR);
13 }
14 result.append(relativePath);
15 return result;
16}
17
tfarinaa8e2e152014-07-28 19:26:58 -070018SkString SkOSPath::Basename(const char* fullPath) {
scroggo@google.comccd7afb2013-05-28 16:45:07 +000019 if (!fullPath) {
20 return SkString();
21 }
22 const char* filename = strrchr(fullPath, SkPATH_SEPARATOR);
23 if (NULL == filename) {
24 filename = fullPath;
25 } else {
26 ++filename;
27 }
28 return SkString(filename);
29}
30
reed@android.com8a1c16f2008-12-17 15:59:43 +000031#ifdef SK_BUILD_FOR_WIN
32
reed@android.comb50a60c2009-01-14 17:51:08 +000033static uint16_t* concat_to_16(const char src[], const char suffix[])
reed@android.com8a1c16f2008-12-17 15:59:43 +000034{
reed@android.com6f252972009-01-14 16:46:16 +000035 size_t i, len = strlen(src);
36 size_t len2 = 3 + (suffix ? strlen(suffix) : 0);
reed@android.comb50a60c2009-01-14 17:51:08 +000037 uint16_t* dst = (uint16_t*)sk_malloc_throw((len + len2) * sizeof(uint16_t));
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
reed@android.com6f252972009-01-14 16:46:16 +000039 for (i = 0; i < len; i++)
40 dst[i] = src[i];
reed@android.com8a1c16f2008-12-17 15:59:43 +000041
reed@android.com6f252972009-01-14 16:46:16 +000042 if (i > 0 && dst[i-1] != '/')
43 dst[i++] = '/';
44 dst[i++] = '*';
reed@android.com8a1c16f2008-12-17 15:59:43 +000045
reed@android.com6f252972009-01-14 16:46:16 +000046 if (suffix)
47 {
48 while (*suffix)
49 dst[i++] = *suffix++;
50 }
51 dst[i] = 0;
52 SkASSERT(i + 1 <= len + len2);
reed@android.com8a1c16f2008-12-17 15:59:43 +000053
reed@android.com6f252972009-01-14 16:46:16 +000054 return dst;
reed@android.com8a1c16f2008-12-17 15:59:43 +000055}
56
reed@android.com8a1c16f2008-12-17 15:59:43 +000057////////////////////////////////////////////////////////////////////////////
58
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +000059SkOSFile::Iter::Iter() : fHandle(0), fPath16(NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +000060{
61}
62
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +000063SkOSFile::Iter::Iter(const char path[], const char suffix[]) : fHandle(0), fPath16(NULL)
reed@android.com8a1c16f2008-12-17 15:59:43 +000064{
reed@android.com6f252972009-01-14 16:46:16 +000065 this->reset(path, suffix);
reed@android.com8a1c16f2008-12-17 15:59:43 +000066}
67
68SkOSFile::Iter::~Iter()
69{
reed@android.com6f252972009-01-14 16:46:16 +000070 sk_free(fPath16);
71 if (fHandle)
72 ::FindClose(fHandle);
reed@android.com8a1c16f2008-12-17 15:59:43 +000073}
74
75void SkOSFile::Iter::reset(const char path[], const char suffix[])
76{
reed@android.com6f252972009-01-14 16:46:16 +000077 if (fHandle)
78 {
79 ::FindClose(fHandle);
80 fHandle = 0;
81 }
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +000082 if (NULL == path)
reed@android.com6f252972009-01-14 16:46:16 +000083 path = "";
reed@android.com8a1c16f2008-12-17 15:59:43 +000084
reed@android.com6f252972009-01-14 16:46:16 +000085 sk_free(fPath16);
86 fPath16 = concat_to_16(path, suffix);
reed@android.com8a1c16f2008-12-17 15:59:43 +000087}
88
reed@android.comb50a60c2009-01-14 17:51:08 +000089static bool is_magic_dir(const uint16_t dir[])
reed@android.com8a1c16f2008-12-17 15:59:43 +000090{
reed@android.com6f252972009-01-14 16:46:16 +000091 // return true for "." and ".."
92 return dir[0] == '.' && (dir[1] == 0 || dir[1] == '.' && dir[2] == 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000093}
94
95static bool get_the_file(HANDLE handle, SkString* name, WIN32_FIND_DATAW* dataPtr, bool getDir)
96{
reed@android.com6f252972009-01-14 16:46:16 +000097 WIN32_FIND_DATAW data;
reed@android.com8a1c16f2008-12-17 15:59:43 +000098
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +000099 if (NULL == dataPtr)
reed@android.com6f252972009-01-14 16:46:16 +0000100 {
101 if (::FindNextFileW(handle, &data))
102 dataPtr = &data;
103 else
104 return false;
105 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106
reed@android.com6f252972009-01-14 16:46:16 +0000107 for (;;)
108 {
109 if (getDir)
110 {
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +0000111 if ((dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !is_magic_dir((uint16_t*)dataPtr->cFileName))
reed@android.com6f252972009-01-14 16:46:16 +0000112 break;
113 }
114 else
115 {
116 if (!(dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
117 break;
118 }
119 if (!::FindNextFileW(handle, dataPtr))
120 return false;
121 }
122 // if we get here, we've found a file/dir
123 if (name)
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +0000124 name->setUTF16((uint16_t*)dataPtr->cFileName);
reed@android.com6f252972009-01-14 16:46:16 +0000125 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126}
127
128bool SkOSFile::Iter::next(SkString* name, bool getDir)
129{
reed@android.com6f252972009-01-14 16:46:16 +0000130 WIN32_FIND_DATAW data;
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +0000131 WIN32_FIND_DATAW* dataPtr = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132
reed@android.com6f252972009-01-14 16:46:16 +0000133 if (fHandle == 0) // our first time
134 {
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +0000135 if (fPath16 == NULL || *fPath16 == 0) // check for no path
reed@android.com6f252972009-01-14 16:46:16 +0000136 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +0000138 fHandle = ::FindFirstFileW((LPCWSTR)fPath16, &data);
reed@android.com6f252972009-01-14 16:46:16 +0000139 if (fHandle != 0 && fHandle != (HANDLE)~0)
140 dataPtr = &data;
141 }
142 return fHandle != (HANDLE)~0 && get_the_file(fHandle, name, dataPtr, getDir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143}
144
caryclark@google.com867cbd82012-09-20 15:45:41 +0000145#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146
147#if 0
148OSStatus FSPathMakeRef (
149 const UInt8 * path,
150 FSRef * ref,
151 Boolean * isDirectory
152);
153#endif
154
155SkOSFile::Iter::Iter() : fDIR(0)
156{
157}
158
159SkOSFile::Iter::Iter(const char path[], const char suffix[]) : fDIR(0)
160{
reed@android.com6f252972009-01-14 16:46:16 +0000161 this->reset(path, suffix);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162}
163
164SkOSFile::Iter::~Iter()
165{
reed@android.com6f252972009-01-14 16:46:16 +0000166 if (fDIR)
167 ::closedir(fDIR);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168}
169
170void SkOSFile::Iter::reset(const char path[], const char suffix[])
171{
reed@android.com6f252972009-01-14 16:46:16 +0000172 if (fDIR)
173 {
174 ::closedir(fDIR);
175 fDIR = 0;
176 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177
reed@android.com6f252972009-01-14 16:46:16 +0000178 fPath.set(path);
179 if (path)
180 {
181 fDIR = ::opendir(path);
182 fSuffix.set(suffix);
183 }
184 else
185 fSuffix.reset();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186}
187
188// returns true if suffix is empty, or if str ends with suffix
189static bool issuffixfor(const SkString& suffix, const char str[])
190{
reed@android.com6f252972009-01-14 16:46:16 +0000191 size_t suffixLen = suffix.size();
192 size_t strLen = strlen(str);
agl@chromium.org0afaf9b2010-07-28 17:10:28 +0000193
reed@android.com6f252972009-01-14 16:46:16 +0000194 return strLen >= suffixLen &&
reed@android.com6f252972009-01-14 16:46:16 +0000195 memcmp(suffix.c_str(), str + strLen - suffixLen, suffixLen) == 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196}
197
198#include <sys/stat.h>
199
200bool SkOSFile::Iter::next(SkString* name, bool getDir)
201{
reed@android.com6f252972009-01-14 16:46:16 +0000202 if (fDIR)
203 {
204 dirent* entry;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
reed@android.com6f252972009-01-14 16:46:16 +0000206 while ((entry = ::readdir(fDIR)) != NULL)
207 {
208 struct stat s;
209 SkString str(fPath);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210
reed@android.com6f252972009-01-14 16:46:16 +0000211 if (!str.endsWith("/") && !str.endsWith("\\"))
212 str.append("/");
213 str.append(entry->d_name);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214
reed@android.com6f252972009-01-14 16:46:16 +0000215 if (0 == stat(str.c_str(), &s))
216 {
217 if (getDir)
218 {
219 if (s.st_mode & S_IFDIR)
220 break;
221 }
222 else
223 {
224 if (!(s.st_mode & S_IFDIR) && issuffixfor(fSuffix, entry->d_name))
225 break;
226 }
227 }
228 }
229 if (entry) // we broke out with a file
230 {
231 if (name)
232 name->set(entry->d_name);
233 return true;
234 }
235 }
236 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237}
scroggo@google.comccd7afb2013-05-28 16:45:07 +0000238#endif // if one of:SK_BUILD_FOR_MAC, SK_BUILD_FOR_UNIX, SK_BUILD_FOR_ANDROID,SK_BUILD_FOR_IOS