1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SkOSFile.h"
9
10#ifdef SK_BUILD_FOR_WIN
11
12static uint16_t* concat_to_16(const char src[], const char suffix[])
13{
14    size_t  i, len = strlen(src);
15    size_t  len2 = 3 + (suffix ? strlen(suffix) : 0);
16    uint16_t* dst = (uint16_t*)sk_malloc_throw((len + len2) * sizeof(uint16_t));
17
18    for (i = 0; i < len; i++)
19        dst[i] = src[i];
20
21    if (i > 0 && dst[i-1] != '/')
22        dst[i++] = '/';
23    dst[i++] = '*';
24
25    if (suffix)
26    {
27        while (*suffix)
28            dst[i++] = *suffix++;
29    }
30    dst[i] = 0;
31    SkASSERT(i + 1 <= len + len2);
32
33    return dst;
34}
35
36SkUTF16_Str::SkUTF16_Str(const char src[])
37{
38    size_t  len = strlen(src);
39
40    fStr = (uint16_t*)sk_malloc_throw((len + 1) * sizeof(uint16_t));
41    size_t i;
42    for (i = 0; i < len; i++)
43        fStr[i] = src[i];
44    fStr[i] = 0;
45}
46
47////////////////////////////////////////////////////////////////////////////
48
49SkOSFile::Iter::Iter() : fHandle(0), fPath16(NULL)
50{
51}
52
53SkOSFile::Iter::Iter(const char path[], const char suffix[]) : fHandle(0), fPath16(NULL)
54{
55    this->reset(path, suffix);
56}
57
58SkOSFile::Iter::~Iter()
59{
60    sk_free(fPath16);
61    if (fHandle)
62        ::FindClose(fHandle);
63}
64
65void SkOSFile::Iter::reset(const char path[], const char suffix[])
66{
67    if (fHandle)
68    {
69        ::FindClose(fHandle);
70        fHandle = 0;
71    }
72    if (NULL == path)
73        path = "";
74
75    sk_free(fPath16);
76    fPath16 = concat_to_16(path, suffix);
77}
78
79static bool is_magic_dir(const uint16_t dir[])
80{
81    // return true for "." and ".."
82    return dir[0] == '.' && (dir[1] == 0 || dir[1] == '.' && dir[2] == 0);
83}
84
85static bool get_the_file(HANDLE handle, SkString* name, WIN32_FIND_DATAW* dataPtr, bool getDir)
86{
87    WIN32_FIND_DATAW    data;
88
89    if (NULL == dataPtr)
90    {
91        if (::FindNextFileW(handle, &data))
92            dataPtr = &data;
93        else
94            return false;
95    }
96
97    for (;;)
98    {
99        if (getDir)
100        {
101            if ((dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !is_magic_dir((uint16_t*)dataPtr->cFileName))
102                break;
103        }
104        else
105        {
106            if (!(dataPtr->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
107                break;
108        }
109        if (!::FindNextFileW(handle, dataPtr))
110            return false;
111    }
112    // if we get here, we've found a file/dir
113    if (name)
114        name->setUTF16((uint16_t*)dataPtr->cFileName);
115    return true;
116}
117
118bool SkOSFile::Iter::next(SkString* name, bool getDir)
119{
120    WIN32_FIND_DATAW    data;
121    WIN32_FIND_DATAW*   dataPtr = NULL;
122
123    if (fHandle == 0)   // our first time
124    {
125        if (fPath16 == NULL || *fPath16 == 0)    // check for no path
126            return false;
127
128        fHandle = ::FindFirstFileW((LPCWSTR)fPath16, &data);
129        if (fHandle != 0 && fHandle != (HANDLE)~0)
130            dataPtr = &data;
131    }
132    return fHandle != (HANDLE)~0 && get_the_file(fHandle, name, dataPtr, getDir);
133}
134
135#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
136
137#if 0
138OSStatus FSPathMakeRef (
139   const UInt8 * path,
140   FSRef * ref,
141   Boolean * isDirectory
142);
143#endif
144
145SkOSFile::Iter::Iter() : fDIR(0)
146{
147}
148
149SkOSFile::Iter::Iter(const char path[], const char suffix[]) : fDIR(0)
150{
151    this->reset(path, suffix);
152}
153
154SkOSFile::Iter::~Iter()
155{
156    if (fDIR)
157        ::closedir(fDIR);
158}
159
160void SkOSFile::Iter::reset(const char path[], const char suffix[])
161{
162    if (fDIR)
163    {
164        ::closedir(fDIR);
165        fDIR = 0;
166    }
167
168    fPath.set(path);
169    if (path)
170    {
171        fDIR = ::opendir(path);
172        fSuffix.set(suffix);
173    }
174    else
175        fSuffix.reset();
176}
177
178// returns true if suffix is empty, or if str ends with suffix
179static bool issuffixfor(const SkString& suffix, const char str[])
180{
181    size_t  suffixLen = suffix.size();
182    size_t  strLen = strlen(str);
183
184    return  strLen >= suffixLen &&
185            memcmp(suffix.c_str(), str + strLen - suffixLen, suffixLen) == 0;
186}
187
188#include <sys/stat.h>
189
190bool SkOSFile::Iter::next(SkString* name, bool getDir)
191{
192    if (fDIR)
193    {
194        dirent* entry;
195
196        while ((entry = ::readdir(fDIR)) != NULL)
197        {
198            struct stat s;
199            SkString    str(fPath);
200
201            if (!str.endsWith("/") && !str.endsWith("\\"))
202                str.append("/");
203            str.append(entry->d_name);
204
205            if (0 == stat(str.c_str(), &s))
206            {
207                if (getDir)
208                {
209                    if (s.st_mode & S_IFDIR)
210                        break;
211                }
212                else
213                {
214                    if (!(s.st_mode & S_IFDIR) && issuffixfor(fSuffix, entry->d_name))
215                        break;
216                }
217            }
218        }
219        if (entry)  // we broke out with a file
220        {
221            if (name)
222                name->set(entry->d_name);
223            return true;
224        }
225    }
226    return false;
227}
228
229#endif
230
231