On x86 compilers without fastcall, simulate it when invoking traces and un-simulate...
[wine-gecko.git] / xpcom / io / nsLocalFileCommon.cpp
blob3002046c8b55494efc3945e8c4f0f9dcf1db9674
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1999
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Doug Turner <dougt@netscape.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
38 #include "nsIServiceManager.h"
40 #include "nsLocalFile.h" // includes platform-specific headers
41 #include "nsLocalFileUnicode.h"
43 #include "nsString.h"
44 #include "nsCOMPtr.h"
45 #include "nsReadableUtils.h"
46 #include "nsPrintfCString.h"
47 #include "nsCRT.h"
48 #include "nsNativeCharsetUtils.h"
49 #include "nsUTF8Utils.h"
51 #ifdef XP_WIN
52 #include <string.h>
53 #endif
56 void NS_StartupLocalFile()
58 nsLocalFile::GlobalInit();
61 void NS_ShutdownLocalFile()
63 nsLocalFile::GlobalShutdown();
66 #if !defined(XP_MACOSX) && !defined(XP_WIN)
67 NS_IMETHODIMP
68 nsLocalFile::InitWithFile(nsILocalFile *aFile)
70 NS_ENSURE_ARG(aFile);
72 nsCAutoString path;
73 aFile->GetNativePath(path);
74 if (path.IsEmpty())
75 return NS_ERROR_INVALID_ARG;
76 return InitWithNativePath(path);
78 #endif
80 #define kMaxFilenameLength 255
81 #define kMaxExtensionLength 100
82 #define kMaxSequenceNumberLength 5 // "-9999"
83 // requirement: kMaxExtensionLength < kMaxFilenameLength - kMaxSequenceNumberLength
85 NS_IMETHODIMP
86 nsLocalFile::CreateUnique(PRUint32 type, PRUint32 attributes)
88 nsresult rv;
89 PRBool longName;
91 #ifdef XP_WIN
92 nsAutoString pathName, leafName, rootName, suffix;
93 rv = GetPath(pathName);
94 #else
95 nsCAutoString pathName, leafName, rootName, suffix;
96 rv = GetNativePath(pathName);
97 #endif
98 if (NS_FAILED(rv))
99 return rv;
101 longName = (pathName.Length() + kMaxSequenceNumberLength >
102 kMaxFilenameLength);
103 if (!longName)
105 rv = Create(type, attributes);
106 if (rv != NS_ERROR_FILE_ALREADY_EXISTS)
107 return rv;
110 #ifdef XP_WIN
111 rv = GetLeafName(leafName);
112 if (NS_FAILED(rv))
113 return rv;
115 const PRInt32 lastDot = leafName.RFindChar(PRUnichar('.'));
116 #else
117 rv = GetNativeLeafName(leafName);
118 if (NS_FAILED(rv))
119 return rv;
121 const PRInt32 lastDot = leafName.RFindChar('.');
122 #endif
124 if (lastDot == kNotFound)
126 rootName = leafName;
128 else
130 suffix = Substring(leafName, lastDot); // include '.'
131 rootName = Substring(leafName, 0, lastDot); // strip suffix and dot
134 if (longName)
136 PRUint32 maxRootLength = (kMaxFilenameLength -
137 (pathName.Length() - leafName.Length()) -
138 suffix.Length() - kMaxSequenceNumberLength);
139 #ifdef XP_WIN
140 // ensure that we don't cut the name in mid-UTF16-character
141 rootName.SetLength(NS_IS_LOW_SURROGATE(rootName[maxRootLength]) ?
142 maxRootLength - 1 : maxRootLength);
143 SetLeafName(rootName + suffix);
144 #else
145 if (NS_IsNativeUTF8())
146 // ensure that we don't cut the name in mid-UTF8-character
147 while (UTF8traits::isInSeq(rootName[maxRootLength]))
148 --maxRootLength;
149 rootName.SetLength(maxRootLength);
150 SetNativeLeafName(rootName + suffix);
151 #endif
152 nsresult rv = Create(type, attributes);
153 if (rv != NS_ERROR_FILE_ALREADY_EXISTS)
154 return rv;
157 for (int indx = 1; indx < 10000; indx++)
159 // start with "Picture-1.jpg" after "Picture.jpg" exists
160 #ifdef XP_WIN
161 SetLeafName(rootName +
162 NS_ConvertASCIItoUTF16(nsPrintfCString("-%d", indx)) +
163 suffix);
164 #else
165 SetNativeLeafName(rootName + nsPrintfCString("-%d", indx) + suffix);
166 #endif
167 rv = Create(type, attributes);
168 if (NS_SUCCEEDED(rv) || rv != NS_ERROR_FILE_ALREADY_EXISTS)
169 return rv;
172 // The disk is full, sort of
173 return NS_ERROR_FILE_TOO_BIG;
176 #if defined(XP_WIN) || defined(XP_OS2)
177 static const PRUnichar kPathSeparatorChar = '\\';
178 #elif defined(XP_UNIX) || defined(XP_BEOS)
179 static const PRUnichar kPathSeparatorChar = '/';
180 #else
181 #error Need to define file path separator for your platform
182 #endif
184 static PRInt32 SplitPath(PRUnichar *path, PRUnichar **nodeArray, PRInt32 arrayLen)
186 if (*path == 0)
187 return 0;
189 PRUnichar **nodePtr = nodeArray;
190 if (*path == kPathSeparatorChar)
191 path++;
192 *nodePtr++ = path;
194 for (PRUnichar *cp = path; *cp != 0; cp++) {
195 if (*cp == kPathSeparatorChar) {
196 *cp++ = 0;
197 if (*cp == 0)
198 break;
199 if (nodePtr - nodeArray >= arrayLen)
200 return -1;
201 *nodePtr++ = cp;
204 return nodePtr - nodeArray;
208 NS_IMETHODIMP
209 nsLocalFile::GetRelativeDescriptor(nsILocalFile *fromFile, nsACString& _retval)
211 NS_ENSURE_ARG_POINTER(fromFile);
212 const PRInt32 kMaxNodesInPath = 32;
215 // _retval will be UTF-8 encoded
218 nsresult rv;
219 _retval.Truncate(0);
221 nsAutoString thisPath, fromPath;
222 PRUnichar *thisNodes[kMaxNodesInPath], *fromNodes[kMaxNodesInPath];
223 PRInt32 thisNodeCnt, fromNodeCnt, nodeIndex;
225 rv = GetPath(thisPath);
226 if (NS_FAILED(rv))
227 return rv;
228 rv = fromFile->GetPath(fromPath);
229 if (NS_FAILED(rv))
230 return rv;
232 // get raw pointer to mutable string buffer
233 PRUnichar *thisPathPtr; thisPath.BeginWriting(thisPathPtr);
234 PRUnichar *fromPathPtr; fromPath.BeginWriting(fromPathPtr);
236 thisNodeCnt = SplitPath(thisPathPtr, thisNodes, kMaxNodesInPath);
237 fromNodeCnt = SplitPath(fromPathPtr, fromNodes, kMaxNodesInPath);
238 if (thisNodeCnt < 0 || fromNodeCnt < 0)
239 return NS_ERROR_FAILURE;
241 for (nodeIndex = 0; nodeIndex < thisNodeCnt && nodeIndex < fromNodeCnt; ++nodeIndex) {
242 #ifdef XP_WIN
243 if (_wcsicmp(thisNodes[nodeIndex], fromNodes[nodeIndex]))
244 break;
245 #else
246 if (nsCRT::strcmp(thisNodes[nodeIndex], fromNodes[nodeIndex]))
247 break;
248 #endif
251 PRInt32 branchIndex = nodeIndex;
252 for (nodeIndex = branchIndex; nodeIndex < fromNodeCnt; nodeIndex++)
253 _retval.AppendLiteral("../");
254 for (nodeIndex = branchIndex; nodeIndex < thisNodeCnt; nodeIndex++) {
255 NS_ConvertUTF16toUTF8 nodeStr(thisNodes[nodeIndex]);
256 _retval.Append(nodeStr);
257 if (nodeIndex + 1 < thisNodeCnt)
258 _retval.Append('/');
261 return NS_OK;
264 NS_IMETHODIMP
265 nsLocalFile::SetRelativeDescriptor(nsILocalFile *fromFile, const nsACString& relativeDesc)
267 NS_NAMED_LITERAL_CSTRING(kParentDirStr, "../");
269 nsCOMPtr<nsIFile> targetFile;
270 nsresult rv = fromFile->Clone(getter_AddRefs(targetFile));
271 if (NS_FAILED(rv))
272 return rv;
275 // relativeDesc is UTF-8 encoded
278 nsCString::const_iterator strBegin, strEnd;
279 relativeDesc.BeginReading(strBegin);
280 relativeDesc.EndReading(strEnd);
282 nsCString::const_iterator nodeBegin(strBegin), nodeEnd(strEnd);
283 nsCString::const_iterator pos(strBegin);
285 nsCOMPtr<nsIFile> parentDir;
286 while (FindInReadable(kParentDirStr, nodeBegin, nodeEnd)) {
287 rv = targetFile->GetParent(getter_AddRefs(parentDir));
288 if (NS_FAILED(rv))
289 return rv;
290 if (!parentDir)
291 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
292 targetFile = parentDir;
294 nodeBegin = nodeEnd;
295 pos = nodeEnd;
296 nodeEnd = strEnd;
299 nodeBegin = nodeEnd = pos;
300 while (nodeEnd != strEnd) {
301 FindCharInReadable('/', nodeEnd, strEnd);
302 targetFile->Append(NS_ConvertUTF8toUTF16(Substring(nodeBegin, nodeEnd)));
303 if (nodeEnd != strEnd) // If there's more left in the string, inc over the '/' nodeEnd is on.
304 ++nodeEnd;
305 nodeBegin = nodeEnd;
308 nsCOMPtr<nsILocalFile> targetLocalFile(do_QueryInterface(targetFile));
309 return InitWithFile(targetLocalFile);