Back to index

lightning-sunbird  0.9+nobinonly
nsLocalFileCommon.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Doug Turner <dougt@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "nsIServiceManager.h"
00039 
00040 #include "nsLocalFile.h" // includes platform-specific headers
00041 #include "nsLocalFileUnicode.h"
00042 
00043 #include "nsString.h"
00044 #include "nsCOMPtr.h"
00045 #include "nsReadableUtils.h"
00046 #include "nsPrintfCString.h"
00047 #include "nsCRT.h"
00048 
00049 #ifdef XP_WIN
00050 #include <string.h>
00051 #endif
00052 
00053 
00054 void NS_StartupLocalFile()
00055 {
00056     nsLocalFile::GlobalInit();
00057 }
00058 
00059 void NS_ShutdownLocalFile()
00060 {
00061     nsLocalFile::GlobalShutdown();
00062 }
00063 
00064 #if !defined(XP_MAC) && !defined(XP_MACOSX) && !defined(XP_WIN)
00065 NS_IMETHODIMP
00066 nsLocalFile::InitWithFile(nsILocalFile *aFile)
00067 {
00068     NS_ENSURE_ARG(aFile);
00069     
00070     nsCAutoString path;
00071     aFile->GetNativePath(path);
00072     if (path.IsEmpty())
00073         return NS_ERROR_INVALID_ARG;
00074     return InitWithNativePath(path); 
00075 }
00076 #endif
00077 
00078 #if defined(XP_MAC)
00079 #define kMaxFilenameLength 31
00080 #define kMaxExtensionLength 10
00081 #else
00082 #define kMaxFilenameLength 255
00083 #define kMaxExtensionLength 100
00084 #endif  
00085 // requirement: kMaxExtensionLength < kMaxFilenameLength - 4
00086 
00087 NS_IMETHODIMP
00088 nsLocalFile::CreateUnique(PRUint32 type, PRUint32 attributes)
00089 {
00090     nsresult rv = Create(type, attributes);
00091     if (rv != NS_ERROR_FILE_ALREADY_EXISTS)
00092         return rv;
00093 
00094     nsCAutoString leafName; 
00095     rv = GetNativeLeafName(leafName);
00096     if (NS_FAILED(rv))
00097         return rv;
00098 
00099     const char* lastDot = strrchr(leafName.get(), '.');
00100     char suffix[kMaxExtensionLength] = "";
00101     if (lastDot)
00102     {
00103         PL_strncpyz(suffix, lastDot, sizeof(suffix)); // include '.'
00104         leafName.SetLength(lastDot - leafName.get()); // strip suffix and dot.
00105     }
00106 
00107     PRUint32 maxRootLength = (kMaxFilenameLength - 4) - strlen(suffix) - 1;
00108 
00109     if (leafName.Length() > maxRootLength)
00110         leafName.SetLength(maxRootLength);
00111 
00112     for (int indx = 1; indx < 10000; indx++)
00113     {
00114         // start with "Picture-1.jpg" after "Picture.jpg" exists
00115         SetNativeLeafName(leafName +
00116                           nsPrintfCString("-%d", indx) +
00117                           nsDependentCString(suffix));
00118 
00119         rv = Create(type, attributes);
00120         if (NS_SUCCEEDED(rv) || rv != NS_ERROR_FILE_ALREADY_EXISTS) 
00121             return rv;
00122     }
00123  
00124     // The disk is full, sort of
00125     return NS_ERROR_FILE_TOO_BIG;
00126 }
00127 
00128 #if defined(XP_MAC)
00129 static const PRUnichar kPathSeparatorChar       = ':';
00130 #elif defined(XP_WIN) || defined(XP_OS2)
00131 static const PRUnichar kPathSeparatorChar       = '\\';
00132 #elif defined(XP_UNIX) || defined(XP_BEOS)
00133 static const PRUnichar kPathSeparatorChar       = '/';
00134 #else
00135 #error Need to define file path separator for your platform
00136 #endif
00137 
00138 #if defined(XP_MAC)
00139 static const char kSlashStr[] = "/";
00140 static const char kESCSlashStr[] = "%2F";
00141 #endif
00142 
00143 static PRInt32 SplitPath(PRUnichar *path, PRUnichar **nodeArray, PRInt32 arrayLen)
00144 {
00145     if (*path == 0)
00146       return 0;
00147 
00148     PRUnichar **nodePtr = nodeArray;
00149     if (*path == kPathSeparatorChar)
00150       path++;    
00151     *nodePtr++ = path;
00152     
00153     for (PRUnichar *cp = path; *cp != 0; cp++) {
00154       if (*cp == kPathSeparatorChar) {
00155         *cp++ = 0;
00156         if (*cp == 0)
00157           break;
00158         if (nodePtr - nodeArray >= arrayLen)
00159           return -1;
00160         *nodePtr++ = cp;
00161       }
00162     }
00163     return nodePtr - nodeArray;
00164 }
00165 
00166  
00167 NS_IMETHODIMP
00168 nsLocalFile::GetRelativeDescriptor(nsILocalFile *fromFile, nsACString& _retval)
00169 {
00170     NS_ENSURE_ARG_POINTER(fromFile);
00171     const PRInt32 kMaxNodesInPath = 32;
00172 
00173     //
00174     // _retval will be UTF-8 encoded
00175     // 
00176         
00177     nsresult rv;
00178     _retval.Truncate(0);
00179 
00180     nsAutoString thisPath, fromPath;
00181     PRUnichar *thisNodes[kMaxNodesInPath], *fromNodes[kMaxNodesInPath];
00182     PRInt32  thisNodeCnt, fromNodeCnt, nodeIndex;
00183     
00184     rv = GetPath(thisPath);
00185     if (NS_FAILED(rv))
00186         return rv;
00187     rv = fromFile->GetPath(fromPath);
00188     if (NS_FAILED(rv))
00189         return rv;
00190 
00191     // get raw pointer to mutable string buffer
00192     PRUnichar *thisPathPtr; thisPath.BeginWriting(thisPathPtr);
00193     PRUnichar *fromPathPtr; fromPath.BeginWriting(fromPathPtr);
00194     
00195     thisNodeCnt = SplitPath(thisPathPtr, thisNodes, kMaxNodesInPath);
00196     fromNodeCnt = SplitPath(fromPathPtr, fromNodes, kMaxNodesInPath);
00197     if (thisNodeCnt < 0 || fromNodeCnt < 0)
00198       return NS_ERROR_FAILURE;
00199     
00200     for (nodeIndex = 0; nodeIndex < thisNodeCnt && nodeIndex < fromNodeCnt; ++nodeIndex) {
00201 #ifdef XP_WIN
00202       if (_wcsicmp(thisNodes[nodeIndex], fromNodes[nodeIndex]))
00203         break;
00204 #else
00205       if (nsCRT::strcmp(thisNodes[nodeIndex], fromNodes[nodeIndex]))
00206         break;
00207 #endif
00208     }
00209     
00210     PRInt32 branchIndex = nodeIndex;
00211     for (nodeIndex = branchIndex; nodeIndex < fromNodeCnt; nodeIndex++) 
00212       _retval.AppendLiteral("../");
00213     for (nodeIndex = branchIndex; nodeIndex < thisNodeCnt; nodeIndex++) {
00214       NS_ConvertUCS2toUTF8 nodeStr(thisNodes[nodeIndex]);
00215 #ifdef XP_MAC
00216       nodeStr.ReplaceSubstring(kSlashStr, kESCSlashStr);
00217 #endif
00218       _retval.Append(nodeStr);
00219       if (nodeIndex + 1 < thisNodeCnt)
00220         _retval.Append('/');
00221     }
00222         
00223     return NS_OK;
00224 }
00225 
00226 NS_IMETHODIMP
00227 nsLocalFile::SetRelativeDescriptor(nsILocalFile *fromFile, const nsACString& relativeDesc)
00228 {
00229     NS_NAMED_LITERAL_CSTRING(kParentDirStr, "../");
00230  
00231     nsCOMPtr<nsIFile> targetFile;
00232     nsresult rv = fromFile->Clone(getter_AddRefs(targetFile));
00233     if (NS_FAILED(rv))
00234         return rv;
00235 
00236     //
00237     // relativeDesc is UTF-8 encoded
00238     // 
00239 
00240     nsCString::const_iterator strBegin, strEnd;
00241     relativeDesc.BeginReading(strBegin);
00242     relativeDesc.EndReading(strEnd);
00243     
00244     nsCString::const_iterator nodeBegin(strBegin), nodeEnd(strEnd);
00245     nsCString::const_iterator pos(strBegin);
00246     
00247     nsCOMPtr<nsIFile> parentDir;
00248     while (FindInReadable(kParentDirStr, nodeBegin, nodeEnd)) {
00249         rv = targetFile->GetParent(getter_AddRefs(parentDir));
00250         if (NS_FAILED(rv))
00251             return rv;
00252         if (!parentDir)
00253             return NS_ERROR_FILE_UNRECOGNIZED_PATH;
00254         targetFile = parentDir;
00255 
00256         nodeBegin = nodeEnd;
00257         pos = nodeEnd;
00258         nodeEnd = strEnd;
00259     }
00260 
00261     nodeBegin = nodeEnd = pos;
00262     while (nodeEnd != strEnd) {
00263       FindCharInReadable('/', nodeEnd, strEnd);
00264 #ifdef XP_MAC
00265       nsCAutoString nodeString(Substring(nodeBegin, nodeEnd));      
00266       nodeString.ReplaceSubstring(kESCSlashStr, kSlashStr);
00267       targetFile->Append(NS_ConvertUTF8toUCS2(nodeString));
00268 #else
00269       targetFile->Append(NS_ConvertUTF8toUCS2(Substring(nodeBegin, nodeEnd)));
00270 #endif
00271       if (nodeEnd != strEnd) // If there's more left in the string, inc over the '/' nodeEnd is on.
00272         ++nodeEnd;
00273       nodeBegin = nodeEnd;
00274     }
00275 
00276     nsCOMPtr<nsILocalFile> targetLocalFile(do_QueryInterface(targetFile));
00277     return InitWithFile(targetLocalFile);
00278 }