Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsIServiceManager.h"
7 #include "nsLocalFile.h" // includes platform-specific headers
9 #include "nsString.h"
10 #include "nsCOMPtr.h"
11 #include "nsReadableUtils.h"
12 #include "nsPrintfCString.h"
13 #include "nsCRT.h"
14 #include "nsNativeCharsetUtils.h"
15 #include "nsUTF8Utils.h"
17 #ifdef XP_WIN
18 #include <string.h>
19 #endif
22 void NS_StartupLocalFile()
23 {
24 nsLocalFile::GlobalInit();
25 }
27 void NS_ShutdownLocalFile()
28 {
29 nsLocalFile::GlobalShutdown();
30 }
32 #if !defined(MOZ_WIDGET_COCOA) && !defined(XP_WIN)
33 NS_IMETHODIMP
34 nsLocalFile::InitWithFile(nsIFile *aFile)
35 {
36 if (NS_WARN_IF(!aFile))
37 return NS_ERROR_INVALID_ARG;
39 nsAutoCString path;
40 aFile->GetNativePath(path);
41 if (path.IsEmpty())
42 return NS_ERROR_INVALID_ARG;
43 return InitWithNativePath(path);
44 }
45 #endif
47 #define kMaxFilenameLength 255
48 #define kMaxExtensionLength 100
49 #define kMaxSequenceNumberLength 5 // "-9999"
50 // requirement: kMaxExtensionLength < kMaxFilenameLength - kMaxSequenceNumberLength
52 NS_IMETHODIMP
53 nsLocalFile::CreateUnique(uint32_t type, uint32_t attributes)
54 {
55 nsresult rv;
56 bool longName;
58 #ifdef XP_WIN
59 nsAutoString pathName, leafName, rootName, suffix;
60 rv = GetPath(pathName);
61 #else
62 nsAutoCString pathName, leafName, rootName, suffix;
63 rv = GetNativePath(pathName);
64 #endif
65 if (NS_FAILED(rv))
66 return rv;
68 longName = (pathName.Length() + kMaxSequenceNumberLength >
69 kMaxFilenameLength);
70 if (!longName)
71 {
72 rv = Create(type, attributes);
73 if (rv != NS_ERROR_FILE_ALREADY_EXISTS)
74 return rv;
75 }
77 #ifdef XP_WIN
78 rv = GetLeafName(leafName);
79 if (NS_FAILED(rv))
80 return rv;
82 const int32_t lastDot = leafName.RFindChar(char16_t('.'));
83 #else
84 rv = GetNativeLeafName(leafName);
85 if (NS_FAILED(rv))
86 return rv;
88 const int32_t lastDot = leafName.RFindChar('.');
89 #endif
91 if (lastDot == kNotFound)
92 {
93 rootName = leafName;
94 }
95 else
96 {
97 suffix = Substring(leafName, lastDot); // include '.'
98 rootName = Substring(leafName, 0, lastDot); // strip suffix and dot
99 }
101 if (longName)
102 {
103 int32_t maxRootLength = (kMaxFilenameLength -
104 (pathName.Length() - leafName.Length()) -
105 suffix.Length() - kMaxSequenceNumberLength);
107 // We cannot create an item inside a directory whose name is too long.
108 // Also, ensure that at least one character remains after we truncate
109 // the root name, as we don't want to end up with an empty leaf name.
110 if (maxRootLength < 2)
111 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
113 #ifdef XP_WIN
114 // ensure that we don't cut the name in mid-UTF16-character
115 rootName.SetLength(NS_IS_LOW_SURROGATE(rootName[maxRootLength]) ?
116 maxRootLength - 1 : maxRootLength);
117 SetLeafName(rootName + suffix);
118 #else
119 if (NS_IsNativeUTF8())
120 {
121 // ensure that we don't cut the name in mid-UTF8-character
122 // (assume the name is valid UTF8 to begin with)
123 while (UTF8traits::isInSeq(rootName[maxRootLength]))
124 --maxRootLength;
126 // Another check to avoid ending up with an empty leaf name.
127 if (maxRootLength == 0 && suffix.IsEmpty())
128 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
129 }
131 rootName.SetLength(maxRootLength);
132 SetNativeLeafName(rootName + suffix);
133 #endif
134 nsresult rv = Create(type, attributes);
135 if (rv != NS_ERROR_FILE_ALREADY_EXISTS)
136 return rv;
137 }
139 for (int indx = 1; indx < 10000; indx++)
140 {
141 // start with "Picture-1.jpg" after "Picture.jpg" exists
142 #ifdef XP_WIN
143 SetLeafName(rootName +
144 NS_ConvertASCIItoUTF16(nsPrintfCString("-%d", indx)) +
145 suffix);
146 #else
147 SetNativeLeafName(rootName + nsPrintfCString("-%d", indx) + suffix);
148 #endif
149 rv = Create(type, attributes);
150 if (NS_SUCCEEDED(rv) || rv != NS_ERROR_FILE_ALREADY_EXISTS)
151 return rv;
152 }
154 // The disk is full, sort of
155 return NS_ERROR_FILE_TOO_BIG;
156 }
158 #if defined(XP_WIN)
159 static const char16_t kPathSeparatorChar = '\\';
160 #elif defined(XP_UNIX)
161 static const char16_t kPathSeparatorChar = '/';
162 #else
163 #error Need to define file path separator for your platform
164 #endif
166 static int32_t SplitPath(char16_t *path, char16_t **nodeArray, int32_t arrayLen)
167 {
168 if (*path == 0)
169 return 0;
171 char16_t **nodePtr = nodeArray;
172 if (*path == kPathSeparatorChar)
173 path++;
174 *nodePtr++ = path;
176 for (char16_t *cp = path; *cp != 0; cp++) {
177 if (*cp == kPathSeparatorChar) {
178 *cp++ = 0;
179 if (*cp == 0)
180 break;
181 if (nodePtr - nodeArray >= arrayLen)
182 return -1;
183 *nodePtr++ = cp;
184 }
185 }
186 return nodePtr - nodeArray;
187 }
190 NS_IMETHODIMP
191 nsLocalFile::GetRelativeDescriptor(nsIFile *fromFile, nsACString& _retval)
192 {
193 if (NS_WARN_IF(!fromFile))
194 return NS_ERROR_INVALID_ARG;
195 const int32_t kMaxNodesInPath = 32;
197 //
198 // _retval will be UTF-8 encoded
199 //
201 nsresult rv;
202 _retval.Truncate(0);
204 nsAutoString thisPath, fromPath;
205 char16_t *thisNodes[kMaxNodesInPath], *fromNodes[kMaxNodesInPath];
206 int32_t thisNodeCnt, fromNodeCnt, nodeIndex;
208 rv = GetPath(thisPath);
209 if (NS_FAILED(rv))
210 return rv;
211 rv = fromFile->GetPath(fromPath);
212 if (NS_FAILED(rv))
213 return rv;
215 // get raw pointer to mutable string buffer
216 char16_t *thisPathPtr; thisPath.BeginWriting(thisPathPtr);
217 char16_t *fromPathPtr; fromPath.BeginWriting(fromPathPtr);
219 thisNodeCnt = SplitPath(thisPathPtr, thisNodes, kMaxNodesInPath);
220 fromNodeCnt = SplitPath(fromPathPtr, fromNodes, kMaxNodesInPath);
221 if (thisNodeCnt < 0 || fromNodeCnt < 0)
222 return NS_ERROR_FAILURE;
224 for (nodeIndex = 0; nodeIndex < thisNodeCnt && nodeIndex < fromNodeCnt; ++nodeIndex) {
225 #ifdef XP_WIN
226 if (_wcsicmp(char16ptr_t(thisNodes[nodeIndex]), char16ptr_t(fromNodes[nodeIndex])))
227 break;
228 #else
229 if (nsCRT::strcmp(thisNodes[nodeIndex], fromNodes[nodeIndex]))
230 break;
231 #endif
232 }
234 int32_t branchIndex = nodeIndex;
235 for (nodeIndex = branchIndex; nodeIndex < fromNodeCnt; nodeIndex++)
236 _retval.AppendLiteral("../");
237 for (nodeIndex = branchIndex; nodeIndex < thisNodeCnt; nodeIndex++) {
238 NS_ConvertUTF16toUTF8 nodeStr(thisNodes[nodeIndex]);
239 _retval.Append(nodeStr);
240 if (nodeIndex + 1 < thisNodeCnt)
241 _retval.Append('/');
242 }
244 return NS_OK;
245 }
247 NS_IMETHODIMP
248 nsLocalFile::SetRelativeDescriptor(nsIFile *fromFile, const nsACString& relativeDesc)
249 {
250 NS_NAMED_LITERAL_CSTRING(kParentDirStr, "../");
252 nsCOMPtr<nsIFile> targetFile;
253 nsresult rv = fromFile->Clone(getter_AddRefs(targetFile));
254 if (NS_FAILED(rv))
255 return rv;
257 //
258 // relativeDesc is UTF-8 encoded
259 //
261 nsCString::const_iterator strBegin, strEnd;
262 relativeDesc.BeginReading(strBegin);
263 relativeDesc.EndReading(strEnd);
265 nsCString::const_iterator nodeBegin(strBegin), nodeEnd(strEnd);
266 nsCString::const_iterator pos(strBegin);
268 nsCOMPtr<nsIFile> parentDir;
269 while (FindInReadable(kParentDirStr, nodeBegin, nodeEnd)) {
270 rv = targetFile->GetParent(getter_AddRefs(parentDir));
271 if (NS_FAILED(rv))
272 return rv;
273 if (!parentDir)
274 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
275 targetFile = parentDir;
277 nodeBegin = nodeEnd;
278 pos = nodeEnd;
279 nodeEnd = strEnd;
280 }
282 nodeBegin = nodeEnd = pos;
283 while (nodeEnd != strEnd) {
284 FindCharInReadable('/', nodeEnd, strEnd);
285 targetFile->Append(NS_ConvertUTF8toUTF16(Substring(nodeBegin, nodeEnd)));
286 if (nodeEnd != strEnd) // If there's more left in the string, inc over the '/' nodeEnd is on.
287 ++nodeEnd;
288 nodeBegin = nodeEnd;
289 }
291 return InitWithFile(targetFile);
292 }