Support configurable autocapitalization.
[WebKit-https.git] / Source / WebCore / platform / FileSystem.cpp
1 /*
2  * Copyright (C) 2007, 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2015 Canon Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "FileSystem.h"
29
30 #include "ScopeGuard.h"
31 #include <wtf/HexNumber.h>
32 #include <wtf/text/CString.h>
33 #include <wtf/text/StringBuilder.h>
34
35 #if !OS(WINDOWS)
36 #include <fcntl.h>
37 #include <sys/mman.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40 #endif
41
42 namespace WebCore {
43
44 // The following lower-ASCII characters need escaping to be used in a filename
45 // across all systems, including Windows:
46 //     - Unprintable ASCII (00-1F)
47 //     - Space             (20)
48 //     - Double quote      (22)
49 //     - Percent           (25) (escaped because it is our escape character)
50 //     - Asterisk          (2A)
51 //     - Slash             (2F)
52 //     - Colon             (3A)
53 //     - Less-than         (3C)
54 //     - Greater-than      (3E)
55 //     - Question Mark     (3F)
56 //     - Backslash         (5C)
57 //     - Pipe              (7C)
58 //     - Delete            (7F)
59
60 static const bool needsEscaping[128] = {
61     /* 00-07 */ true,  true,  true,  true,  true,  true,  true,  true, 
62     /* 08-0F */ true,  true,  true,  true,  true,  true,  true,  true, 
63
64     /* 10-17 */ true,  true,  true,  true,  true,  true,  true,  true, 
65     /* 18-1F */ true,  true,  true,  true,  true,  true,  true,  true, 
66
67     /* 20-27 */ true,  false, true,  false, false, true,  false, false, 
68     /* 28-2F */ false, false, true,  false, false, false, false, true, 
69     
70     /* 30-37 */ false, false, false, false, false, false, false, false, 
71     /* 38-3F */ false, false, true,  false, true,  false, true,  true, 
72     
73     /* 40-47 */ false, false, false, false, false, false, false, false, 
74     /* 48-4F */ false, false, false, false, false, false, false, false,
75     
76     /* 50-57 */ false, false, false, false, false, false, false, false, 
77     /* 58-5F */ false, false, false, false, true,  false, false, false,
78     
79     /* 60-67 */ false, false, false, false, false, false, false, false, 
80     /* 68-6F */ false, false, false, false, false, false, false, false,
81     
82     /* 70-77 */ false, false, false, false, false, false, false, false, 
83     /* 78-7F */ false, false, false, false, true,  false, false, true, 
84 };
85
86 static inline bool shouldEscapeUChar(UChar character, UChar previousCharacter, UChar nextCharacter)
87 {
88     if (character <= 127)
89         return needsEscaping[character];
90
91     if (U16_IS_LEAD(character) && !U16_IS_TRAIL(nextCharacter))
92         return true;
93
94     if (U16_IS_TRAIL(character) && !U16_IS_LEAD(previousCharacter))
95         return true;
96
97     return false;
98 }
99
100 String encodeForFileName(const String& inputString)
101 {
102     unsigned length = inputString.length();
103     if (!length)
104         return inputString;
105
106     StringBuilder result;
107     result.reserveCapacity(length);
108
109     UChar previousCharacter;
110     UChar character = 0;
111     UChar nextCharacter = inputString[0];
112     for (unsigned i = 0; i < length; ++i) {
113         previousCharacter = character;
114         character = nextCharacter;
115         nextCharacter = i + 1 < length ? inputString[i + 1] : 0;
116
117         if (shouldEscapeUChar(character, previousCharacter, nextCharacter)) {
118             if (character <= 255) {
119                 result.append('%');
120                 appendByteAsHex(character, result);
121             } else {
122                 result.appendLiteral("%+");
123                 appendByteAsHex(character >> 8, result);
124                 appendByteAsHex(character, result);
125             }
126         } else
127             result.append(character);
128     }
129
130     return result.toString();
131 }
132
133 String decodeFromFilename(const String& inputString)
134 {
135     unsigned length = inputString.length();
136     if (!length)
137         return inputString;
138
139     StringBuilder result;
140     result.reserveCapacity(length);
141
142     for (unsigned i = 0; i < length; ++i) {
143         if (inputString[i] != '%') {
144             result.append(inputString[i]);
145             continue;
146         }
147
148         // If the input string is a valid encoded filename, it must be at least 2 characters longer
149         // than the current index to account for this percent encoded value.
150         if (i + 2 >= length)
151             return { };
152
153         if (inputString[i+1] != '+') {
154             char value;
155             if (!hexDigitValue(inputString[i + 1], value))
156                 return { };
157             LChar character = value << 4;
158
159             if (!hexDigitValue(inputString[i + 2], value))
160                 return { };
161
162             result.append(character | value);
163             i += 2;
164
165             continue;
166         }
167
168         // If the input string is a valid encoded filename, it must be at least 5 characters longer
169         // than the current index to account for this percent encoded value.
170         if (i + 5 >= length)
171             return { };
172
173         char value;
174         if (!hexDigitValue(inputString[i + 2], value))
175             return { };
176         UChar character = value << 12;
177
178         if (!hexDigitValue(inputString[i + 3], value))
179             return { };
180         character = character | (value << 8);
181
182         if (!hexDigitValue(inputString[i + 4], value))
183             return { };
184         character = character | (value << 4);
185
186         if (!hexDigitValue(inputString[i + 5], value))
187             return { };
188
189         result.append(character | value);
190         i += 5;
191     }
192
193     return result.toString();
194 }
195
196 String lastComponentOfPathIgnoringTrailingSlash(const String& path)
197 {
198 #if OS(WINDOWS)
199     char pathSeparator = '\\';
200 #else
201     char pathSeparator = '/';
202 #endif
203
204     auto position = path.reverseFind(pathSeparator);
205     if (position == notFound)
206         return path;
207
208     size_t endOfSubstring = path.length() - 1;
209     if (position == endOfSubstring) {
210         --endOfSubstring;
211         position = path.reverseFind(pathSeparator, endOfSubstring);
212     }
213
214     return path.substring(position + 1, endOfSubstring - position);
215 }
216
217 bool appendFileContentsToFileHandle(const String& path, PlatformFileHandle& target)
218 {
219     auto source = openFile(path, OpenForRead);
220
221     if (!isHandleValid(source))
222         return false;
223
224     static int bufferSize = 1 << 19;
225     Vector<char> buffer(bufferSize);
226
227     ScopeGuard fileCloser([source]() {
228         PlatformFileHandle handle = source;
229         closeFile(handle);
230     });
231
232     do {
233         int readBytes = readFromFile(source, buffer.data(), bufferSize);
234         
235         if (readBytes < 0)
236             return false;
237
238         if (writeToFile(target, buffer.data(), readBytes) != readBytes)
239             return false;
240
241         if (readBytes < bufferSize)
242             return true;
243     } while (true);
244
245     ASSERT_NOT_REACHED();
246 }
247
248 #if !PLATFORM(MAC)
249
250 void setMetadataURL(String&, const String&, const String&)
251 {
252 }
253
254 bool canExcludeFromBackup()
255 {
256     return false;
257 }
258
259 bool excludeFromBackup(const String&)
260 {
261     return false;
262 }
263
264 #endif
265
266 MappedFileData::~MappedFileData()
267 {
268 #if !OS(WINDOWS)
269     if (!m_fileData)
270         return;
271     munmap(m_fileData, m_fileSize);
272 #endif
273 }
274
275 MappedFileData::MappedFileData(const String& filePath, bool& success)
276 {
277 #if OS(WINDOWS)
278     // FIXME: Implement mapping
279     success = false;
280 #else
281     CString fsRep = fileSystemRepresentation(filePath);
282     int fd = !fsRep.isNull() ? open(fsRep.data(), O_RDONLY) : -1;
283     if (fd < 0) {
284         success = false;
285         return;
286     }
287
288     struct stat fileStat;
289     if (fstat(fd, &fileStat)) {
290         close(fd);
291         success = false;
292         return;
293     }
294
295     unsigned size;
296     if (!WTF::convertSafely(fileStat.st_size, size)) {
297         close(fd);
298         success = false;
299         return;
300     }
301
302     if (!size) {
303         close(fd);
304         success = true;
305         return;
306     }
307
308     void* data = mmap(0, size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);
309     close(fd);
310
311     if (data == MAP_FAILED) {
312         success = false;
313         return;
314     }
315
316     success = true;
317     m_fileData = data;
318     m_fileSize = size;
319 #endif
320 }
321
322 } // namespace WebCore