1/*
2 * Copyright (C) 2010 Company 100, Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "FileSystem.h"
31
32#include "NotImplemented.h"
33
34#include <AEEAppGen.h>
35#include <AEEFile.h>
36#include <AEEStdLib.h>
37
38#include <wtf/RandomNumber.h>
39#include <wtf/brew/RefPtrBrew.h>
40#include <wtf/brew/ShellBrew.h>
41#include <wtf/text/CString.h>
42#include <wtf/text/StringBuilder.h>
43#include <wtf/text/WTFString.h>
44
45namespace WebCore {
46
47bool getFileSize(const String& path, long long& result)
48{
49    RefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
50    FileInfo info;
51
52    if (IFILEMGR_GetInfo(fileMgr.get(), path.utf8().data(), &info) == SUCCESS) {
53        result = info.dwSize;
54        return true;
55    }
56
57    return false;
58}
59
60bool getFileModificationTime(const String& path, time_t& result)
61{
62    // There is no way to get file modification time in BREW. IFILEMGR_GetInfoEx() returns
63    // only file creation time.
64    return false;
65}
66
67bool fileExists(const String& path)
68{
69    RefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
70
71    return (IFILEMGR_Test(fileMgr.get(), path.utf8().data()) == SUCCESS);
72}
73
74bool deleteFile(const String& path)
75{
76    RefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
77
78    return (IFILEMGR_Remove(fileMgr.get(), path.utf8().data()) == SUCCESS);
79}
80
81bool deleteEmptyDirectory(const String& path)
82{
83    RefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
84
85    return (IFILEMGR_RmDir(fileMgr.get(), path.utf8().data()) == SUCCESS);
86}
87
88String pathByAppendingComponent(const String& path, const String& component)
89{
90    if (component.isEmpty())
91        return path;
92
93    Vector<UChar, 1024> buffer;
94
95    buffer.append(path.characters(), path.length());
96
97    if (buffer.last() != L'/' && component[0] != L'/')
98        buffer.append(L'/');
99
100    buffer.append(component.characters(), component.length());
101
102    return String(buffer.data(), buffer.size());
103}
104
105CString fileSystemRepresentation(const String& path)
106{
107    return path.utf8();
108}
109
110static String canonicalPath(const String& path)
111{
112    RefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
113
114    // Get the buffer size required to resolve the path.
115    int canonPathLen;
116    IFILEMGR_ResolvePath(fileMgr.get(), path.utf8().data(), 0, &canonPathLen);
117
118    // Resolve the path to the canonical path.
119    Vector<char> canonPathBuffer(canonPathLen);
120    IFILEMGR_ResolvePath(fileMgr.get(), path.utf8().data(), canonPathBuffer.data(), &canonPathLen);
121
122    String canonPath(canonPathBuffer.data());
123
124    // Remove the trailing '/'.
125    int lastDivPos = canonPath.reverseFind('/');
126    int endPos = canonPath.length();
127    if (lastDivPos == endPos - 1)
128        canonPath = canonPath.substring(0, canonPath.length() - 1);
129
130    return canonPath;
131}
132
133static bool makeAllDirectories(IFileMgr* fileManager, const String& path)
134{
135    if (path == canonicalPath(AEEFS_HOME_DIR))
136        return true;
137
138    int lastDivPos = path.reverseFind('/');
139    int endPos = path.length();
140    if (lastDivPos == path.length() - 1) {
141        endPos -= 1;
142        lastDivPos = path.reverseFind('/', lastDivPos);
143    }
144
145    if (lastDivPos > 0) {
146        if (!makeAllDirectories(fileManager, path.substring(0, lastDivPos)))
147            return false;
148    }
149
150    String folder(path.substring(0, endPos));
151
152    // IFILEMGR_MkDir return SUCCESS when the file is successfully created or if file already exists.
153    // So we need to check fileinfo.attrib.
154    IFILEMGR_MkDir(fileManager, folder.utf8().data());
155
156    FileInfo fileInfo;
157    if (IFILEMGR_GetInfo(fileManager, folder.utf8().data(), &fileInfo) != SUCCESS)
158        return false;
159
160    return fileInfo.attrib & _FA_DIR;
161}
162
163bool makeAllDirectories(const String& path)
164{
165    RefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
166
167    return makeAllDirectories(fileMgr.get(), canonicalPath(path));
168}
169
170String homeDirectoryPath()
171{
172    const int webViewClassId = 0x010aa04c;
173    return String::format("fs:/~0X%08X/", webViewClassId);
174}
175
176String pathGetFileName(const String& path)
177{
178    return path.substring(path.reverseFind('/') + 1);
179}
180
181String directoryName(const String& path)
182{
183    String fileName = pathGetFileName(path);
184    String dirName = String(path);
185    dirName.truncate(dirName.length() - pathGetFileName(path).length());
186    return dirName;
187}
188
189String openTemporaryFile(const String& prefix, PlatformFileHandle& handle)
190{
191    // BREW does not have a system-wide temporary directory,
192    // use "fs:/~/tmp" as our temporary directory.
193    String tempPath("fs:/~/tmp");
194
195    RefPtr<IFileMgr> fileMgr = createRefPtrInstance<IFileMgr>(AEECLSID_FILEMGR);
196
197    // Create the temporary directory if it does not exist.
198    IFILEMGR_MkDir(fileMgr.get(), tempPath.utf8().data());
199
200    // Loop until we find a temporary filename that does not exist.
201    int number = static_cast<int>(randomNumber() * 10000);
202    String filename;
203    do {
204        StringBuilder builder;
205        builder.append(tempPath);
206        builder.append('/');
207        builder.append(prefix);
208        builder.append(String::number(number));
209        filename = builder.toString();
210        number++;
211    } while (IFILEMGR_Test(fileMgr.get(), filename.utf8().data()) == SUCCESS);
212
213    IFile* tempFile = IFILEMGR_OpenFile(fileMgr.get(), filename.utf8().data(), _OFM_CREATE);
214    if (tempFile) {
215        handle = tempFile;
216        return filename;
217    }
218
219    return String();
220}
221
222void closeFile(PlatformFileHandle& handle)
223{
224    if (isHandleValid(handle)) {
225        IFILE_Release(handle);
226        handle = invalidPlatformFileHandle;
227    }
228}
229
230int writeToFile(PlatformFileHandle handle, const char* data, int length)
231{
232    if (!isHandleValid(handle))
233        return -1;
234
235    int bytesWritten = IFILE_Write(handle, data, length);
236    if (!bytesWritten)
237        return -1;
238    return bytesWritten;
239}
240
241bool unloadModule(PlatformModule module)
242{
243    notImplemented();
244
245    return false;
246}
247
248Vector<String> listDirectory(const String& path, const String& filter)
249{
250    Vector<String> entries;
251
252    // OK to not implement listDirectory, because it's only used for plug-ins and
253    // Brew MP does not support the plug-in at the moment.
254    notImplemented();
255
256    return entries;
257}
258
259}
260