Back to index

lightning-sunbird  0.9+nobinonly
nsFileSpec.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037  
00038 #include "nsFileSpec.h"
00039 
00040 #include "nsDebug.h"
00041 #include "nsEscape.h"
00042 #include "nsMemory.h"
00043 
00044 #include "prtypes.h"
00045 #include "plstr.h"
00046 #include "plbase64.h"
00047 #include "prmem.h"
00048 
00049 #include "nsCOMPtr.h"
00050 #include "nsIServiceManager.h"
00051 #include "nsILocalFile.h"
00052 
00053 #include <string.h>
00054 #include <stdio.h>
00055 
00056 #if defined(XP_WIN)
00057 #include <mbstring.h>
00058 #endif
00059 
00060 #ifdef XP_OS2
00061 extern unsigned char* _mbsrchr( const unsigned char*, int);
00062 #endif
00063 
00064 // return pointer to last instance of the given separator
00065 static inline char *GetLastSeparator(const char *str, char sep)
00066 {
00067 #if defined(XP_WIN) || defined(XP_OS2)
00068     return (char*) _mbsrchr((const unsigned char *) str, sep);
00069 #else
00070     return (char*) strrchr(str, sep);
00071 #endif
00072 }
00073 
00074 #if defined(XP_MACOSX)
00075 #include <sys/stat.h>
00076 #endif
00077 
00078 #if defined(XP_MAC) || defined(XP_MACOSX)
00079 #include <Aliases.h>
00080 #include <TextUtils.h>
00081 #endif
00082 
00083 //========================================================================================
00084 //            class nsSimpleCharString
00085 //========================================================================================
00086 
00087 //----------------------------------------------------------------------------------------
00088 nsSimpleCharString::nsSimpleCharString()
00089 //----------------------------------------------------------------------------------------
00090 :   mData(nsnull)
00091 {
00092     
00093 } // nsSimpleCharString::nsSimpleCharString
00094 
00095 //----------------------------------------------------------------------------------------
00096 nsSimpleCharString::nsSimpleCharString(const char* inString)
00097 //----------------------------------------------------------------------------------------
00098 :   mData(nsnull)
00099 {
00100     if (inString)
00101         CopyFrom(inString, strlen(inString));
00102 } // nsSimpleCharString::nsSimpleCharString
00103 
00104 //----------------------------------------------------------------------------------------
00105 nsSimpleCharString::nsSimpleCharString(const nsString& inString)
00106 //----------------------------------------------------------------------------------------
00107 :   mData(nsnull)
00108 {
00109     *this = inString;
00110 } // nsSimpleCharString::nsSimpleCharString
00111 
00112 //----------------------------------------------------------------------------------------
00113 nsSimpleCharString::nsSimpleCharString(const nsSimpleCharString& inOther)
00114 //----------------------------------------------------------------------------------------
00115 {
00116     mData = inOther.mData;
00117     AddRefData();
00118 } // nsSimpleCharString::nsSimpleCharString
00119 
00120 //----------------------------------------------------------------------------------------
00121 nsSimpleCharString::nsSimpleCharString(const char* inData, PRUint32 inLength)
00122 //----------------------------------------------------------------------------------------
00123 :   mData(nsnull)
00124 {
00125     CopyFrom(inData, inLength);
00126 } // nsSimpleCharString::nsSimpleCharString
00127 
00128 //----------------------------------------------------------------------------------------
00129 nsSimpleCharString::~nsSimpleCharString()
00130 //----------------------------------------------------------------------------------------
00131 {
00132     ReleaseData();
00133 } // nsSimpleCharString::nsSimpleCharString
00134 
00135 //----------------------------------------------------------------------------------------
00136 void nsSimpleCharString::operator = (const char* inString)
00137 //----------------------------------------------------------------------------------------
00138 {
00139     if (inString)
00140         CopyFrom(inString, strlen(inString));
00141     else
00142         SetToEmpty();
00143 } // nsSimpleCharString::operator =
00144 
00145 //----------------------------------------------------------------------------------------
00146 void nsSimpleCharString::operator = (const nsString& inString)
00147 //----------------------------------------------------------------------------------------
00148 {
00149     PRUint32 len = inString.Length();
00150     ReallocData(len);
00151     if (!mData)
00152         return;
00153     inString.ToCString(mData->mString, len + 1);  
00154 } // nsSimpleCharString::operator =
00155 
00156 //----------------------------------------------------------------------------------------
00157 void nsSimpleCharString::operator = (const nsSimpleCharString& inOther)
00158 //----------------------------------------------------------------------------------------
00159 {
00160     if (mData == inOther.mData)
00161         return;
00162     ReleaseData();
00163     mData = inOther.mData;
00164     AddRefData();
00165 } // nsSimpleCharString::operator =
00166 
00167 //----------------------------------------------------------------------------------------
00168 void nsSimpleCharString::operator += (const char* inOther)
00169 //----------------------------------------------------------------------------------------
00170 {
00171     if (!inOther)
00172         return;
00173     int newLength = Length() + strlen(inOther);
00174     ReallocData(newLength);
00175     strcat(mData->mString, inOther);
00176 } // nsSimpleCharString::operator =
00177 
00178 //----------------------------------------------------------------------------------------
00179 nsSimpleCharString nsSimpleCharString::operator + (const char* inOther) const
00180 //----------------------------------------------------------------------------------------
00181 {
00182     nsSimpleCharString result(*this);
00183     result += inOther;
00184     return result;
00185 } // nsSimpleCharString::operator =
00186 
00187 //----------------------------------------------------------------------------------------
00188 void nsSimpleCharString::Catenate(const char* inString1, const char* inString2)
00189 //----------------------------------------------------------------------------------------
00190 {
00191     if (!inString2)
00192     {
00193         *this += inString1;
00194         return;
00195     }
00196     int newLength = Length() + strlen(inString1) + strlen(inString2);
00197     ReallocData(newLength);
00198     strcat(mData->mString, inString1);
00199     strcat(mData->mString, inString2);
00200 } // nsSimpleCharString::operator =
00201 
00202 //----------------------------------------------------------------------------------------
00203 void nsSimpleCharString::CopyFrom(const char* inData, PRUint32 inLength)
00204 //----------------------------------------------------------------------------------------
00205 {
00206     if (!inData)
00207         return;
00208     ReallocData(inLength);
00209     if (!mData)
00210         return;
00211     if (inLength != 0) {
00212         memcpy(mData->mString, inData, inLength);
00213     }
00214     mData->mString[inLength] = '\0';
00215 } // nsSimpleCharString::CopyFrom
00216 
00217 //----------------------------------------------------------------------------------------
00218 void nsSimpleCharString::SetToEmpty()
00219 //----------------------------------------------------------------------------------------
00220 {
00221     ReleaseData();
00222 } // nsSimpleCharString::SetToEmpty
00223 
00224 //----------------------------------------------------------------------------------------
00225 void nsSimpleCharString::Unescape()
00226 //----------------------------------------------------------------------------------------
00227 {
00228     if (!mData)
00229         return;
00230     ReallocData(mData->mLength);
00231     if (!mData)
00232         return;
00233     nsUnescape(mData->mString);
00234     mData->mLength = strlen(mData->mString);       
00235 } // nsSimpleCharString::Unescape
00236 
00237 
00238 //----------------------------------------------------------------------------------------
00239 void nsSimpleCharString::AddRefData()
00240 //----------------------------------------------------------------------------------------
00241 {
00242     if (mData)
00243         ++mData->mRefCount;
00244 } // nsSimpleCharString::AddRefData
00245 
00246 //----------------------------------------------------------------------------------------
00247 void nsSimpleCharString::ReleaseData()
00248 //----------------------------------------------------------------------------------------
00249 {
00250     if (!mData)
00251         return;
00252     NS_ASSERTION(mData->mRefCount > 0, "String deleted too many times!");
00253     if (--mData->mRefCount == 0)
00254         PR_Free(mData);
00255     mData = nsnull;
00256 } // nsSimpleCharString::ReleaseData
00257 
00258 //----------------------------------------------------------------------------------------
00259 inline PRUint32 CalculateAllocLength(PRUint32 logicalLength)
00260 // Round up to the next multiple of 256.
00261 //----------------------------------------------------------------------------------------
00262 {
00263     return ((1 + (logicalLength >> 8)) << 8);
00264 }
00265 
00266 //----------------------------------------------------------------------------------------
00267 void nsSimpleCharString::ReallocData(PRUint32 inLength)
00268 // Reallocate mData to a new length.  Since this presumably precedes a change to the string,
00269 // we want to detach ourselves if the data is shared by another string, even if the length
00270 // requested would not otherwise require a reallocation.
00271 //----------------------------------------------------------------------------------------
00272 {
00273     PRUint32 newAllocLength = CalculateAllocLength(inLength);
00274     PRUint32 oldAllocLength = CalculateAllocLength(Length());
00275     if (mData)
00276     {
00277         NS_ASSERTION(mData->mRefCount > 0, "String deleted too many times!");
00278         if (mData->mRefCount == 1)
00279         {
00280             // We are the sole owner, so just change its length, if necessary.
00281             if (newAllocLength > oldAllocLength)
00282                 mData = (Data*)PR_Realloc(mData, newAllocLength + sizeof(Data));
00283             mData->mLength = inLength;
00284             mData->mString[inLength] = '\0'; // we may be truncating
00285             return;
00286         }
00287     }
00288     PRUint32 copyLength = Length();
00289     if (inLength < copyLength)
00290         copyLength = inLength;
00291     Data* newData = (Data*)PR_Malloc(newAllocLength + sizeof(Data));
00292     // If data was already allocated when we get to here, then we are cloning the data
00293     // from a shared pointer.
00294     if (mData)
00295     {
00296         memcpy(newData, mData, sizeof(Data) + copyLength);
00297         mData->mRefCount--; // Say goodbye
00298     }
00299     else
00300         newData->mString[0] = '\0';
00301 
00302     mData = newData;
00303     mData->mRefCount = 1;
00304     mData->mLength = inLength;
00305 } // nsSimpleCharString::ReleaseData
00306 
00307 
00308 //========================================================================================
00309 NS_NAMESPACE nsFileSpecHelpers
00310 //========================================================================================
00311 {
00312     enum
00313     {    kMaxFilenameLength = 31                // should work on Macintosh, Unix, and Win32.
00314     ,    kMaxAltDigitLength    = 5
00315     ,    kMaxCoreLeafNameLength    = (kMaxFilenameLength - (kMaxAltDigitLength + 1))
00316     };
00317 #if !defined(XP_MAC)
00318     NS_NAMESPACE_PROTOTYPE void Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs);
00319     NS_NAMESPACE_PROTOTYPE void MakeAllDirectories(const char* inPath, int mode);
00320 #endif
00321 #if defined(XP_WIN) || defined(XP_OS2)
00322     NS_NAMESPACE_PROTOTYPE void NativeToUnix(nsSimpleCharString& ioPath);
00323     NS_NAMESPACE_PROTOTYPE void UnixToNative(nsSimpleCharString& ioPath);
00324 #endif
00325 } NS_NAMESPACE_END
00326 
00327 //----------------------------------------------------------------------------------------
00328 nsresult ns_file_convert_result(PRInt32 nativeErr)
00329 //----------------------------------------------------------------------------------------
00330 {
00331     return nativeErr ?
00332         NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,((nativeErr)&0xFFFF))
00333         : NS_OK;
00334 }
00335 
00336 //----------------------------------------------------------------------------------------
00337 void nsSimpleCharString::LeafReplace(char inSeparator, const char* inLeafName)
00338 //----------------------------------------------------------------------------------------
00339 {
00340     // Find the existing leaf name
00341     if (IsEmpty())
00342         return;
00343     if (!inLeafName)
00344     {
00345         SetToEmpty();
00346         return;
00347     }
00348     char* chars = mData->mString;
00349     char* lastSeparator = GetLastSeparator(chars, inSeparator);
00350     int oldLength = Length();
00351     PRBool trailingSeparator = (lastSeparator + 1 == chars + oldLength);
00352     if (trailingSeparator)
00353     {
00354         char savedCh = *lastSeparator;
00355         char *savedLastSeparator = lastSeparator;
00356         *lastSeparator = '\0';
00357         lastSeparator = GetLastSeparator(chars, inSeparator);
00358         *savedLastSeparator = savedCh;
00359     }
00360     if (lastSeparator)
00361         lastSeparator++; // point at the trailing string
00362     else
00363         lastSeparator = chars; // the full monty
00364 
00365     PRUint32 savedLastSeparatorOffset = (lastSeparator - chars);
00366     int newLength =
00367         (lastSeparator - chars) + strlen(inLeafName) + (trailingSeparator != 0);
00368     ReallocData(newLength);
00369 
00370     chars = mData->mString; // it might have moved.
00371     chars[savedLastSeparatorOffset] = '\0'; // strip the current leaf name
00372 
00373     strcat(chars, inLeafName);
00374     if (trailingSeparator)
00375     {
00376         // If the original ended in a slash, then the new one should, too.
00377         char sepStr[2] = "/";
00378         *sepStr = inSeparator;
00379         strcat(chars, sepStr);
00380     }
00381 } // nsSimpleCharString::LeafReplace
00382 
00383 //----------------------------------------------------------------------------------------
00384 char* nsSimpleCharString::GetLeaf(char inSeparator) const
00385 // Returns a pointer to an allocated string representing the leaf.
00386 //----------------------------------------------------------------------------------------
00387 {
00388     if (IsEmpty())
00389         return nsnull;
00390 
00391     char* chars = mData->mString;
00392     const char* lastSeparator = GetLastSeparator(chars, inSeparator);
00393     // If there was no separator, then return a copy of our path.
00394     if (!lastSeparator)
00395         return nsCRT::strdup(*this);
00396 
00397     // So there's at least one separator.  What's just after it?
00398     // If the separator was not the last character, return the trailing string.
00399     const char* leafPointer = lastSeparator + 1;
00400     if (*leafPointer)
00401         return nsCRT::strdup(leafPointer);
00402 
00403     // So now, separator was the last character. Poke in a null instead.
00404     *(char*)lastSeparator = '\0'; // Should use const_cast, but Unix has old compiler.
00405     leafPointer = GetLastSeparator(chars, inSeparator);
00406     char* result = leafPointer ? nsCRT::strdup(++leafPointer) : nsCRT::strdup(chars);
00407     // Restore the poked null before returning.
00408     *(char*)lastSeparator = inSeparator;
00409 #if defined(XP_WIN) || defined(XP_OS2)
00410     // If it's a drive letter use the colon notation.
00411     if (!leafPointer && result[1] == '|' && result[2] == 0)
00412         result[1] = ':';
00413 #endif
00414     return result;
00415 } // nsSimpleCharString::GetLeaf
00416 
00417 
00418 #if 0
00419 #pragma mark -
00420 #endif
00421 
00422 #if (defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS))
00423 
00424 //----------------------------------------------------------------------------------------
00425 void nsFileSpecHelpers::MakeAllDirectories(const char* inPath, int mode)
00426 // Make the path a valid one by creating all the intermediate directories.  Does NOT
00427 // make the leaf into a directory.  This should be a unix path.
00428 //----------------------------------------------------------------------------------------
00429 {
00430     if (!inPath)
00431         return;
00432         
00433     char* pathCopy = nsCRT::strdup( inPath );
00434     if (!pathCopy)
00435         return;
00436 
00437     const char kSeparator = '/'; // I repeat: this should be a unix-style path.
00438     const int kSkipFirst = 1;
00439 
00440 #if defined(XP_WIN) || defined(XP_OS2)
00441     // Either this is a relative path, or we ensure that it has
00442     // a drive letter specifier.
00443     NS_ASSERTION( pathCopy[0] != '/' || (pathCopy[1] && (pathCopy[2] == '|' || pathCopy[2] == '/')),
00444         "Not a UNC path and no drive letter!" );
00445 #endif
00446     char* currentStart = pathCopy;
00447     char* currentEnd = strchr(currentStart + kSkipFirst, kSeparator);
00448     if (currentEnd)
00449     {
00450         nsFileSpec spec;
00451         *currentEnd = '\0';
00452         
00453 #if defined(XP_WIN) || defined(XP_OS2)
00454         /* 
00455            if we have a drive letter path, we must make sure that the inital path has a '/' on it, or
00456            Canonify will turn "/c|" into a path relative to the running executable.
00457         */
00458         if (pathCopy[0] == '/' && pathCopy[1] && pathCopy[2] == '|')
00459         {
00460             char* startDir = (char*)PR_Malloc(strlen(pathCopy) + 2);
00461             strcpy(startDir, pathCopy);
00462             strcat(startDir, "/");
00463 
00464             spec = nsFilePath(startDir, PR_FALSE);
00465             
00466             PR_Free(startDir);
00467         }
00468         else
00469         {
00470             // move after server name and share name in UNC path
00471             if (pathCopy[0] == '/' &&
00472                 currentEnd == currentStart+kSkipFirst)
00473             {
00474                 *currentEnd = '/';
00475                 currentStart = strchr(pathCopy+2, kSeparator);
00476                 currentStart = strchr(currentStart+1, kSeparator);
00477                 currentEnd = strchr(currentStart+1, kSeparator);
00478                 if (currentEnd)
00479                     *currentEnd = '\0';
00480             }
00481             spec = nsFilePath(pathCopy, PR_FALSE);
00482         }
00483 #else
00484         spec = nsFilePath(pathCopy, PR_FALSE);
00485 #endif        
00486         do
00487         {
00488             // If the node doesn't exist, and it is not the initial node in a full path,
00489             // then make a directory (We cannot make the initial (volume) node).
00490             if (!spec.Exists() && *currentStart != kSeparator)
00491                 spec.CreateDirectory(mode);
00492             
00493             currentStart = ++currentEnd;
00494             currentEnd = strchr(currentStart, kSeparator);
00495             if (!currentEnd)
00496                 break;
00497             
00498             *currentEnd = '\0';
00499 
00500             spec += currentStart; // "lengthen" the path, adding the next node.
00501         } while (currentEnd);
00502     }
00503     nsCRT::free(pathCopy);
00504 } // nsFileSpecHelpers::MakeAllDirectories
00505 
00506 #endif // XP_UNIX || XP_WIN || XP_OS2 || XP_BEOS
00507 
00508 #if 0
00509 #pragma mark -
00510 #endif
00511 
00512 #if defined(XP_WIN)
00513 #include "nsFileSpecWin.cpp" // Windows-specific implementations
00514 #elif defined(XP_MAC)
00515 //#include "nsFileSpecMac.cpp" // Macintosh-specific implementations
00516 // we include the .cpp file in the project now.
00517 #elif defined(XP_BEOS)
00518 #include "nsFileSpecBeOS.cpp" // BeOS-specific implementations
00519 #elif defined(XP_UNIX) || defined(XP_MACOSX)
00520 #include "nsFileSpecUnix.cpp" // Unix-specific implementations
00521 #elif defined(XP_OS2)
00522 #include "nsFileSpecOS2.cpp" // OS/2-specific implementations
00523 #endif
00524 
00525 //========================================================================================
00526 //                                nsFileURL implementation
00527 //========================================================================================
00528 
00529 #if !defined(XP_MAC)
00530 //----------------------------------------------------------------------------------------
00531 nsFileURL::nsFileURL(const char* inString, PRBool inCreateDirs)
00532 //----------------------------------------------------------------------------------------
00533 {
00534     if (!inString)
00535         return;
00536     NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!");
00537     // Make canonical and absolute. Since it's a parameter to this constructor,
00538     // inString is escaped. We want to make an nsFilePath, which requires
00539     // an unescaped string.
00540     nsSimpleCharString unescapedPath(inString + kFileURLPrefixLength);
00541     unescapedPath.Unescape();
00542     nsFilePath path(unescapedPath, inCreateDirs);
00543     *this = path;
00544 } // nsFileURL::nsFileURL
00545 #endif
00546 
00547 #if !defined(XP_MAC)
00548 //----------------------------------------------------------------------------------------
00549 nsFileURL::nsFileURL(const nsString& inString, PRBool inCreateDirs)
00550 //----------------------------------------------------------------------------------------
00551 {
00552     NS_LossyConvertUCS2toASCII cstring(inString);
00553     if (!inString.Length())
00554         return;
00555     NS_ASSERTION(strstr(cstring.get(), kFileURLPrefix) == cstring.get(),
00556                  "Not a URL!");
00557     // Make canonical and absolute. Since it's a parameter to this constructor,
00558     // inString is escaped. We want to make an nsFilePath, which requires
00559     // an unescaped string.
00560     nsSimpleCharString unescapedPath(cstring.get() + kFileURLPrefixLength);
00561     unescapedPath.Unescape();
00562     nsFilePath path(unescapedPath, inCreateDirs);
00563     *this = path;
00564 } // nsFileURL::nsFileURL
00565 #endif
00566 
00567 //----------------------------------------------------------------------------------------
00568 nsFileURL::nsFileURL(const nsFileURL& inOther)
00569 //----------------------------------------------------------------------------------------
00570 :    mURL(inOther.mURL)
00571 #if defined(XP_MAC)
00572 ,    mFileSpec(inOther.GetFileSpec())
00573 #endif
00574 {
00575 } // nsFileURL::nsFileURL
00576 
00577 #if !defined(XP_MAC)
00578 //----------------------------------------------------------------------------------------
00579 nsFileURL::nsFileURL(const nsFilePath& inOther)
00580 //----------------------------------------------------------------------------------------
00581 {
00582     *this = inOther;
00583 } // nsFileURL::nsFileURL
00584 #endif
00585 
00586 #if !defined(XP_MAC)
00587 //----------------------------------------------------------------------------------------
00588 nsFileURL::nsFileURL(const nsFileSpec& inOther)
00589 //----------------------------------------------------------------------------------------
00590 {
00591     *this = inOther;
00592 } // nsFileURL::nsFileURL
00593 #endif
00594 
00595 //----------------------------------------------------------------------------------------
00596 nsFileURL::~nsFileURL()
00597 //----------------------------------------------------------------------------------------
00598 {
00599 }
00600 
00601 #if !defined(XP_MAC)
00602 //----------------------------------------------------------------------------------------
00603 void nsFileURL::operator = (const char* inString)
00604 //----------------------------------------------------------------------------------------
00605 {
00606     // XXX is this called by nsFileSpecImpl.cpp::SetURLString?
00607     // if so, there's a bug...
00608 
00609     mURL = inString;
00610     NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!");
00611 } // nsFileURL::operator =
00612 #endif
00613 
00614 //----------------------------------------------------------------------------------------
00615 void nsFileURL::operator +=(const char* inRelativeUnixPath)
00616 //----------------------------------------------------------------------------------------
00617 {
00618     char* escapedPath = nsEscape(inRelativeUnixPath, url_Path);
00619     mURL += escapedPath;
00620     nsCRT::free(escapedPath);
00621 #if defined(XP_MAC)
00622     mFileSpec += inRelativeUnixPath;
00623 #endif
00624 } // nsFileURL::operator +=
00625 
00626 //----------------------------------------------------------------------------------------
00627 nsFileURL nsFileURL::operator +(const char* inRelativeUnixPath) const
00628 //----------------------------------------------------------------------------------------
00629 {
00630    nsFileURL result(*this);
00631    result += inRelativeUnixPath;
00632    return result;
00633 }  // nsFileURL::operator +
00634 
00635 //----------------------------------------------------------------------------------------
00636 void nsFileURL::operator = (const nsFileURL& inOther)
00637 //----------------------------------------------------------------------------------------
00638 {
00639     mURL = inOther.mURL;
00640 #if defined(XP_MAC)
00641     mFileSpec = inOther.GetFileSpec();
00642 #endif
00643 } // nsFileURL::operator =
00644 
00645 #if !defined(XP_MAC)
00646 //----------------------------------------------------------------------------------------
00647 void nsFileURL::operator = (const nsFilePath& inOther)
00648 //----------------------------------------------------------------------------------------
00649 {
00650     mURL = kFileURLPrefix;
00651     char* original = (char*)(const char*)inOther; // we shall modify, but restore.
00652     if (!original || !*original) return;
00653 #if defined(XP_WIN) || defined(XP_OS2)
00654     // because we don't want to escape the '|' character, change it to a letter.
00655     // Note that a UNC path will not have a '|' character.
00656     char oldchar = original[2];
00657     original[2] = 'x';
00658     char* escapedPath = nsEscape(original, url_Path);
00659     original[2] = escapedPath[2] = oldchar; // restore it
00660 #else
00661     char* escapedPath = nsEscape(original, url_Path);
00662 #endif
00663     if (escapedPath)
00664         mURL += escapedPath;
00665     nsCRT::free(escapedPath);
00666 } // nsFileURL::operator =
00667 #endif
00668 
00669 #if !defined(XP_MAC)
00670 //----------------------------------------------------------------------------------------
00671 void nsFileURL::operator = (const nsFileSpec& inOther)
00672 //----------------------------------------------------------------------------------------
00673 {
00674     *this = nsFilePath(inOther);
00675     if (mURL[mURL.Length() - 1] != '/' && inOther.IsDirectory())
00676         mURL += "/";
00677 } // nsFileURL::operator =
00678 #endif
00679 
00680 #if 0
00681 #pragma mark -
00682 #endif
00683 
00684 //========================================================================================
00685 //                                nsFilePath implementation
00686 //========================================================================================
00687 
00688 //----------------------------------------------------------------------------------------
00689 nsFilePath::nsFilePath(const nsFilePath& inPath)
00690 //----------------------------------------------------------------------------------------
00691     : mPath(inPath.mPath)
00692 #if defined(XP_MAC)
00693     , mFileSpec(inPath.mFileSpec)
00694 #endif
00695 {
00696 }
00697 
00698 #if !defined(XP_MAC)
00699 //----------------------------------------------------------------------------------------
00700 nsFilePath::nsFilePath(const char* inString, PRBool inCreateDirs)
00701 //----------------------------------------------------------------------------------------
00702 :    mPath(inString)
00703 {
00704     if (mPath.IsEmpty())
00705        return;
00706        
00707     NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path");
00708 
00709 #if defined(XP_WIN) || defined(XP_OS2)
00710     nsFileSpecHelpers::UnixToNative(mPath);
00711 #endif
00712     // Make canonical and absolute.
00713     nsFileSpecHelpers::Canonify(mPath, inCreateDirs);
00714 #if defined(XP_WIN) || defined(XP_OS2)
00715     // Assert native path is of one of these forms:
00716     //    -  regular: X:\some\path
00717     //    -  UNC: \\some_machine\some\path
00718     NS_ASSERTION( mPath[1] == ':' || (mPath[0] == '\\' && mPath[1] == '\\'),
00719                  "unexpected canonical path" );
00720     nsFileSpecHelpers::NativeToUnix(mPath);
00721 #endif
00722 }
00723 #endif
00724 
00725 #if !defined(XP_MAC)
00726 //----------------------------------------------------------------------------------------
00727 nsFilePath::nsFilePath(const nsString& inString, PRBool inCreateDirs)
00728 //----------------------------------------------------------------------------------------
00729 :    mPath(inString)
00730 {
00731     if (mPath.IsEmpty())
00732        return;
00733 
00734     NS_ASSERTION(strstr((const char*)mPath, kFileURLPrefix) != (const char*)mPath, "URL passed as path");
00735 #if defined(XP_WIN) || defined(XP_OS2)
00736     nsFileSpecHelpers::UnixToNative(mPath);
00737 #endif
00738     // Make canonical and absolute.
00739     nsFileSpecHelpers::Canonify(mPath, inCreateDirs);
00740 #if defined(XP_WIN) || defined(XP_OS2)
00741     NS_ASSERTION( mPath[1] == ':' || (mPath[0] == '\\' && mPath[1] == '\\'),
00742                  "unexpected canonical path" );
00743     nsFileSpecHelpers::NativeToUnix(mPath);
00744 #endif
00745 }
00746 #endif
00747 
00748 #if !defined(XP_MAC)
00749 //----------------------------------------------------------------------------------------
00750 nsFilePath::nsFilePath(const nsFileURL& inOther)
00751 //----------------------------------------------------------------------------------------
00752 {
00753     mPath = (const char*)inOther.mURL + kFileURLPrefixLength;
00754     mPath.Unescape();
00755 }
00756 #endif
00757 
00758 #if (defined XP_UNIX || defined XP_BEOS)
00759 //----------------------------------------------------------------------------------------
00760 nsFilePath::nsFilePath(const nsFileSpec& inOther)
00761 //----------------------------------------------------------------------------------------
00762 :    mPath(inOther.mPath)
00763 {
00764 }
00765 #endif // XP_UNIX
00766 
00767 //----------------------------------------------------------------------------------------
00768 nsFilePath::~nsFilePath()
00769 //----------------------------------------------------------------------------------------
00770 {
00771 }
00772 
00773 #if (defined XP_UNIX || defined XP_BEOS)
00774 //----------------------------------------------------------------------------------------
00775 void nsFilePath::operator = (const nsFileSpec& inOther)
00776 //----------------------------------------------------------------------------------------
00777 {
00778     // XXX bug here, again if.
00779 
00780     mPath = inOther.mPath;
00781 }
00782 #endif // XP_UNIX
00783 
00784 #if !defined(XP_MAC)
00785 //----------------------------------------------------------------------------------------
00786 void nsFilePath::operator = (const char* inString)
00787 //----------------------------------------------------------------------------------------
00788 {
00789 
00790     NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path");
00791     mPath = inString;
00792     if (mPath.IsEmpty())
00793        return;
00794 #if defined(XP_WIN) || defined(XP_OS2)
00795     nsFileSpecHelpers::UnixToNative(mPath);
00796 #endif
00797     // Make canonical and absolute.
00798     nsFileSpecHelpers::Canonify(mPath, PR_FALSE /* XXX? */);
00799 #if defined(XP_WIN) || defined(XP_OS2)
00800     nsFileSpecHelpers::NativeToUnix(mPath);
00801 #endif
00802 }
00803 #endif // XP_MAC
00804 
00805 #if !defined(XP_MAC)
00806 //----------------------------------------------------------------------------------------
00807 void nsFilePath::operator = (const nsFileURL& inOther)
00808 //----------------------------------------------------------------------------------------
00809 {
00810     mPath = (const char*)nsFilePath(inOther);
00811 }
00812 #endif
00813 
00814 //----------------------------------------------------------------------------------------
00815 void nsFilePath::operator = (const nsFilePath& inOther)
00816 //----------------------------------------------------------------------------------------
00817 {
00818     mPath = inOther.mPath;
00819 #if defined(XP_MAC)
00820     mFileSpec = inOther.GetFileSpec();
00821 #endif
00822 }
00823 
00824 //----------------------------------------------------------------------------------------
00825 void nsFilePath::operator +=(const char* inRelativeUnixPath)
00826 //----------------------------------------------------------------------------------------
00827 {
00828        NS_ASSERTION(inRelativeUnixPath, "Attempt append relative path with null path");
00829 
00830     char* escapedPath = nsEscape(inRelativeUnixPath, url_Path);
00831     mPath += escapedPath;
00832     nsCRT::free(escapedPath);
00833 #if defined(XP_MAC)
00834     mFileSpec += inRelativeUnixPath;
00835 #endif
00836 } // nsFilePath::operator +=
00837 
00838 //----------------------------------------------------------------------------------------
00839 nsFilePath nsFilePath::operator +(const char* inRelativeUnixPath) const
00840 //----------------------------------------------------------------------------------------
00841 {
00842    NS_ASSERTION(inRelativeUnixPath, "Attempt append relative path with null path");
00843 
00844    nsFilePath resultPath(*this);
00845    resultPath += inRelativeUnixPath;
00846    return resultPath;
00847 }  // nsFilePath::operator +
00848 
00849 
00850 #if 0
00851 #pragma mark -
00852 #endif
00853 
00854 //========================================================================================
00855 //                                nsFileSpec implementation
00856 //========================================================================================
00857 
00858 #if !defined(XP_MAC)
00859 //----------------------------------------------------------------------------------------
00860 nsFileSpec::nsFileSpec()
00861 //----------------------------------------------------------------------------------------
00862 :    mError(NS_OK)          // XXX shouldn't this be NS_ERROR_NOT_INITIALIZED?
00863 {
00864 //    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
00865 }
00866 
00867 //----------------------------------------------------------------------------------------
00868 void nsFileSpec::Clear()
00869 //----------------------------------------------------------------------------------------
00870 {
00871     mPath.SetToEmpty();
00872     mError = NS_ERROR_NOT_INITIALIZED;
00873 }
00874 
00875 #endif
00876 
00877 //----------------------------------------------------------------------------------------
00878 nsFileSpec::~nsFileSpec()
00879 //----------------------------------------------------------------------------------------
00880 {
00881     // mPath cleans itself up
00882 }
00883 
00884 //----------------------------------------------------------------------------------------
00885 nsFileSpec::nsFileSpec(const nsPersistentFileDescriptor& inDescriptor)
00886 //----------------------------------------------------------------------------------------
00887 {
00888     *this = inDescriptor;
00889 }
00890 
00891 //----------------------------------------------------------------------------------------
00892 nsFileSpec::nsFileSpec(const nsFileURL& inURL)
00893 //----------------------------------------------------------------------------------------
00894 {
00895     *this = nsFilePath(inURL); // convert to unix path first
00896 }
00897 
00898 //----------------------------------------------------------------------------------------
00899 void nsFileSpec::MakeUnique(const char* inSuggestedLeafName, PRBool inCreateFile)
00900 //----------------------------------------------------------------------------------------
00901 {
00902     if (inSuggestedLeafName && *inSuggestedLeafName)
00903         SetLeafName(inSuggestedLeafName);
00904     MakeUnique(inCreateFile);
00905 } // nsFileSpec::MakeUnique
00906 
00907 //----------------------------------------------------------------------------------------
00908 void nsFileSpec::MakeUnique(PRBool inCreateFile)
00909 //----------------------------------------------------------------------------------------
00910 {
00911     // XXX: updated path starts empty. In case of error this will cause
00912     // any callers to fail badly, but that seems better than letting them
00913     // re-use the default name which has failed to be unique.
00914     nsCAutoString path;
00915     nsCOMPtr<nsILocalFile> localFile;
00916     NS_NewNativeLocalFile(nsDependentCString(*this), PR_TRUE, getter_AddRefs(localFile));
00917     if (localFile)
00918     {
00919         nsresult rv;
00920 
00921         if (inCreateFile)
00922             rv = localFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
00923         else
00924             rv = localFile->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
00925 
00926         if (NS_SUCCEEDED(rv))
00927             localFile->GetNativePath(path);
00928     }
00929 
00930     NS_WARN_IF_FALSE(!path.IsEmpty(), "MakeUnique() failed!");
00931     *this = path.get(); // reset the filepath to point to the unique location
00932 
00933 } // nsFileSpec::MakeUnique
00934 
00935 //----------------------------------------------------------------------------------------
00936 void nsFileSpec::operator = (const nsFileURL& inURL)
00937 //----------------------------------------------------------------------------------------
00938 {
00939     *this = nsFilePath(inURL); // convert to unix path first
00940 }
00941 
00942 //----------------------------------------------------------------------------------------
00943 void nsFileSpec::operator = (const nsPersistentFileDescriptor& inDescriptor)
00944 //----------------------------------------------------------------------------------------
00945 {
00946 
00947     nsCAutoString data;
00948     inDescriptor.GetData(data);
00949 
00950 #if defined (XP_MAC) || defined(XP_MACOSX)
00951     // Decode descriptor into a Handle (which is actually an AliasHandle)
00952     char* decodedData = PL_Base64Decode(data.get(), data.Length(), nsnull);
00953     Handle aliasH = nsnull;
00954     mError = NS_FILE_RESULT(::PtrToHand(decodedData, &aliasH, (data.Length() * 3) / 4));
00955     PR_Free(decodedData);
00956     if (NS_FAILED(mError))
00957         return; // not enough memory?
00958 #endif
00959 
00960 #if defined(XP_MAC)
00961     Boolean changed;
00962     mError = NS_FILE_RESULT(::ResolveAlias(nsnull, (AliasHandle)aliasH, &mSpec, &changed));
00963     DisposeHandle((Handle) aliasH);
00964     mPath.SetToEmpty();
00965 #elif defined(XP_MACOSX)
00966     Boolean changed;
00967     FSRef fileRef;
00968     mError = NS_FILE_RESULT(::FSResolveAlias(nsnull, (AliasHandle)aliasH, &fileRef, &changed));
00969     ::DisposeHandle(aliasH);
00970 
00971     UInt8 pathBuf[PATH_MAX];
00972     mError = NS_FILE_RESULT(::FSRefMakePath(&fileRef, pathBuf, PATH_MAX));
00973     if (NS_FAILED(mError))
00974       return;
00975     mPath = (const char*)pathBuf;
00976 #else
00977     mPath = data.get();
00978     mError = NS_OK;
00979 #endif
00980 }
00981 
00982 //========================================================================================
00983 //                                UNIX & WIN nsFileSpec implementation
00984 //========================================================================================
00985 
00986 #if (defined XP_UNIX || defined XP_BEOS)
00987 //----------------------------------------------------------------------------------------
00988 nsFileSpec::nsFileSpec(const nsFilePath& inPath)
00989 //----------------------------------------------------------------------------------------
00990 :    mPath((const char*)inPath)
00991 ,    mError(NS_OK)
00992 {
00993 //    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
00994 }
00995 
00996 //----------------------------------------------------------------------------------------
00997 void nsFileSpec::operator = (const nsFilePath& inPath)
00998 //----------------------------------------------------------------------------------------
00999 {
01000     mPath = (const char*)inPath;
01001     mError = NS_OK;
01002 }
01003 #endif //XP_UNIX
01004 
01005 #if (defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS))
01006 //----------------------------------------------------------------------------------------
01007 nsFileSpec::nsFileSpec(const nsFileSpec& inSpec)
01008 //----------------------------------------------------------------------------------------
01009 :    mPath(inSpec.mPath)
01010 ,    mError(NS_OK)
01011 {
01012 //    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
01013 }
01014 
01015 //----------------------------------------------------------------------------------------
01016 nsFileSpec::nsFileSpec(const char* inString, PRBool inCreateDirs)
01017 //----------------------------------------------------------------------------------------
01018 :    mPath(inString)
01019 ,    mError(NS_OK)
01020 {
01021 //    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
01022     // Make canonical and absolute.
01023     nsFileSpecHelpers::Canonify(mPath, inCreateDirs);
01024 }
01025 
01026 //----------------------------------------------------------------------------------------
01027 nsFileSpec::nsFileSpec(const nsString& inString, PRBool inCreateDirs)
01028 //----------------------------------------------------------------------------------------
01029 :    mPath(inString)
01030 ,    mError(NS_OK)
01031 {
01032 //    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
01033     // Make canonical and absolute.
01034     nsFileSpecHelpers::Canonify(mPath, inCreateDirs);
01035 }
01036 
01037 //----------------------------------------------------------------------------------------
01038 void nsFileSpec::operator = (const nsFileSpec& inSpec)
01039 //----------------------------------------------------------------------------------------
01040 {
01041     mPath = inSpec.mPath;
01042     mError = inSpec.Error();
01043 }
01044 
01045 //----------------------------------------------------------------------------------------
01046 void nsFileSpec::operator = (const char* inString)
01047 //----------------------------------------------------------------------------------------
01048 {
01049     mPath = inString;
01050     // Make canonical and absolute.
01051     nsFileSpecHelpers::Canonify(mPath, PR_FALSE /* XXX? */);
01052     mError = NS_OK;
01053 }
01054 #endif //XP_UNIX,XP_WIN,XP_OS2,XP_BEOS
01055 
01056 //----------------------------------------------------------------------------------------
01057 nsFileSpec nsFileSpec::operator + (const char* inRelativePath) const
01058 //----------------------------------------------------------------------------------------
01059 {
01060        NS_ASSERTION(inRelativePath, "Attempt to append name with a null string");
01061 
01062     nsFileSpec resultSpec = *this;
01063     resultSpec += inRelativePath;
01064     return resultSpec;
01065 } // nsFileSpec::operator +
01066 
01067 //----------------------------------------------------------------------------------------
01068 PRBool nsFileSpec::operator == (const nsFileSpec& inOther) const
01069 //----------------------------------------------------------------------------------------
01070 {
01071 
01072 #if defined(XP_MAC)
01073     if ( inOther.mSpec.vRefNum == mSpec.vRefNum &&
01074         inOther.mSpec.parID   == mSpec.parID &&
01075         EqualString(inOther.mSpec.name, mSpec.name, false, true))
01076         return PR_TRUE;
01077 #else
01078     PRBool amEmpty = mPath.IsEmpty();
01079     PRBool heEmpty = inOther.mPath.IsEmpty();
01080     if (amEmpty) // we're the same if he's empty...
01081         return heEmpty;
01082     if (heEmpty) // ('cuz I'm not...)
01083         return PR_FALSE;
01084     
01085     nsSimpleCharString      str = mPath;
01086     nsSimpleCharString      inStr = inOther.mPath;
01087     
01088     // Length() is size of buffer, not length of string
01089     PRUint32 strLast = str.Length() - 1, inLast = inStr.Length() - 1;
01090 #if defined(XP_WIN) || defined(XP_OS2)
01091 #define DIR_SEPARATOR '\\'      // XXX doesn't NSPR have this?
01092     /* windows does not care about case. */
01093 #ifdef XP_OS2
01094 #define DIR_STRCMP     strcmp
01095 #else
01096 #define DIR_STRCMP    _stricmp
01097 #endif
01098 #else
01099 #define DIR_SEPARATOR '/'
01100 #if defined(VMS)
01101 #define DIR_STRCMP     strcasecmp
01102 #else
01103 #define DIR_STRCMP     strcmp
01104 #endif
01105 #endif
01106     
01107     if(str[strLast] == DIR_SEPARATOR)
01108         str[strLast] = '\0';
01109 
01110     if(inStr[inLast] == DIR_SEPARATOR)
01111         inStr[inLast] = '\0';
01112 
01113     if (DIR_STRCMP(str, inStr ) == 0)
01114            return PR_TRUE;
01115 #undef DIR_SEPARATOR
01116 #undef DIR_STRCMP
01117 #endif
01118    return PR_FALSE;
01119 }
01120 
01121 //----------------------------------------------------------------------------------------
01122 PRBool nsFileSpec::operator != (const nsFileSpec& inOther) const
01123 //----------------------------------------------------------------------------------------
01124 {
01125     return (! (*this == inOther) );
01126 }
01127 
01128 #if !defined(XP_MAC)
01129 //----------------------------------------------------------------------------------------
01130 // This is the only automatic conversion to const char*
01131 // that is provided, and it allows the
01132 // path to be "passed" to NSPR file routines.  This practice
01133 // is VERY EVIL and should only be used to support legacy
01134 // code.  Using it guarantees bugs on Macintosh. The path is NOT allocated, so do
01135 // not even think of deleting (or freeing) it.
01136 const char* nsFileSpec::GetCString() const
01137 //----------------------------------------------------------------------------------------
01138 {
01139     return mPath;
01140 }
01141 #endif
01142 
01143 //----------------------------------------------------------------------------------------
01144 // Is our spec a child of the provided parent?
01145 PRBool nsFileSpec::IsChildOf(nsFileSpec &possibleParent)
01146 //----------------------------------------------------------------------------------------
01147 {
01148     nsFileSpec iter = *this, parent;
01149 #ifdef DEBUG
01150     int depth = 0;
01151 #endif
01152     while (1) {
01153 #ifdef DEBUG
01154         // sanity
01155         NS_ASSERTION(depth < 100, "IsChildOf has lost its little mind");
01156         if (depth > 100)
01157             return PR_FALSE;
01158 #endif
01159         if (iter == possibleParent)
01160             return PR_TRUE;
01161 
01162         iter.GetParent(parent); // shouldn't this be an error on parent?
01163         if (iter.Failed())
01164             return PR_FALSE;
01165 
01166         if (iter == parent)     // hit bottom
01167             return PR_FALSE;
01168         
01169         iter = parent;
01170 #ifdef DEBUG
01171         depth++;
01172 #endif
01173     }
01174 
01175     // not reached, but I bet some compiler will whine
01176     return PR_FALSE;
01177 }
01178 
01179 #if 0 
01180 #pragma mark -
01181 #endif
01182 
01183 //========================================================================================
01184 //    class nsPersistentFileDescriptor
01185 //========================================================================================
01186 
01187 //----------------------------------------------------------------------------------------
01188 nsPersistentFileDescriptor::nsPersistentFileDescriptor(const nsPersistentFileDescriptor& inDesc)
01189 //----------------------------------------------------------------------------------------
01190     : mDescriptorString(inDesc.mDescriptorString)
01191 {
01192 } // nsPersistentFileDescriptor::nsPersistentFileDescriptor
01193 
01194 //----------------------------------------------------------------------------------------
01195 void nsPersistentFileDescriptor::operator = (const nsPersistentFileDescriptor& inDesc)
01196 //----------------------------------------------------------------------------------------
01197 {
01198     mDescriptorString = inDesc.mDescriptorString;
01199 } // nsPersistentFileDescriptor::operator =
01200 
01201 //----------------------------------------------------------------------------------------
01202 nsPersistentFileDescriptor::nsPersistentFileDescriptor(const nsFileSpec& inSpec)
01203 //----------------------------------------------------------------------------------------
01204 {
01205     *this = inSpec;
01206 } // nsPersistentFileDescriptor::nsPersistentFileDescriptor
01207 
01208 //----------------------------------------------------------------------------------------
01209 void nsPersistentFileDescriptor::operator = (const nsFileSpec& inSpec)
01210 //----------------------------------------------------------------------------------------
01211 {
01212 #if defined(XP_MAC)
01213     if (inSpec.Error())
01214         return;
01215     AliasHandle    aliasH;
01216     OSErr err = NewAlias(nil, inSpec.GetFSSpecPtr(), &aliasH);
01217     if (err != noErr)
01218         return;
01219 
01220     PRUint32 bytes = GetHandleSize((Handle) aliasH);
01221     HLock((Handle) aliasH);
01222     char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull);
01223     DisposeHandle((Handle) aliasH);
01224 
01225     mDescriptorString = buf;
01226     PR_Free(buf);
01227 #elif  defined(XP_MACOSX)
01228     if (inSpec.Error())
01229         return;
01230     
01231     FSRef fileRef;
01232     Boolean isDir;
01233     OSErr err = ::FSPathMakeRef((const UInt8*)inSpec.GetCString(), &fileRef, &isDir);
01234     if (err != noErr)
01235         return;
01236     
01237     AliasHandle    aliasH;
01238     err = ::FSNewAlias(nsnull, &fileRef, &aliasH);
01239     if (err != noErr)
01240         return;
01241 
01242     PRUint32 bytes = ::GetHandleSize((Handle) aliasH);
01243     ::HLock((Handle)aliasH);
01244     char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull);
01245     ::DisposeHandle((Handle) aliasH);
01246 
01247     mDescriptorString = buf;
01248     PR_Free(buf);
01249 #else
01250     mDescriptorString = inSpec.GetCString();
01251 #endif // XP_MAC
01252 } // nsPersistentFileDescriptor::operator =
01253 
01254 //----------------------------------------------------------------------------------------
01255 nsPersistentFileDescriptor::~nsPersistentFileDescriptor()
01256 //----------------------------------------------------------------------------------------
01257 {
01258 } // nsPersistentFileDescriptor::~nsPersistentFileDescriptor
01259 
01260 //----------------------------------------------------------------------------------------
01261 void nsPersistentFileDescriptor::GetData(nsAFlatCString& outData) const
01262 //----------------------------------------------------------------------------------------
01263 {
01264     outData.Assign(mDescriptorString, mDescriptorString.Length());
01265 }
01266 
01267 //----------------------------------------------------------------------------------------
01268 void nsPersistentFileDescriptor::SetData(const nsAFlatCString& inData)
01269 //----------------------------------------------------------------------------------------
01270 {
01271     mDescriptorString.CopyFrom(inData.get(), inData.Length());
01272 }
01273 
01274 //----------------------------------------------------------------------------------------
01275 void nsPersistentFileDescriptor::SetData(const char* inData, PRInt32 inSize)
01276 //----------------------------------------------------------------------------------------
01277 {
01278     mDescriptorString.CopyFrom(inData, inSize);
01279 }
01280 
01281 //========================================================================================
01282 //    class nsNSPRPath
01283 //========================================================================================
01284 
01285 //----------------------------------------------------------------------------------------
01286 nsNSPRPath::operator const char*() const
01287 // NSPR expects a UNIX path on unix and Macintosh, but a native path on windows. NSPR
01288 // cannot be changed, so we have to do the dirty work.
01289 //----------------------------------------------------------------------------------------
01290 {
01291 #if defined(XP_WIN) || defined(XP_OS2)
01292     if (!modifiedNSPRPath)
01293     {
01294         // If this is the first call, initialize modifiedNSPRPath. Start by cloning
01295         // mFilePath, but strip the leading separator, if present
01296         const char* unixPath = (const char*)mFilePath;
01297         if (!unixPath)
01298             return nsnull;
01299 
01300         ((nsNSPRPath*)this)->modifiedNSPRPath
01301                 = nsCRT::strdup(*unixPath == '/' ? unixPath + 1: unixPath);
01302         
01303         // Replace the bar
01304         if (modifiedNSPRPath[1] == '|')
01305              modifiedNSPRPath[1] = ':';
01306         
01307         // Remove the ending separator only if it is not the last separator
01308         int len = strlen(modifiedNSPRPath);
01309         if (modifiedNSPRPath[len - 1 ] == '/' && modifiedNSPRPath[len - 2 ] != ':')
01310             modifiedNSPRPath[len - 1 ] = '\0';     
01311     }
01312     return modifiedNSPRPath;    
01313 #else
01314     return (const char*)mFilePath;
01315 #endif
01316 }
01317 
01318 //----------------------------------------------------------------------------------------
01319 nsNSPRPath::~nsNSPRPath()
01320 //----------------------------------------------------------------------------------------
01321 {
01322 #if defined(XP_WIN) || defined(XP_OS2)
01323     if (modifiedNSPRPath)
01324         nsCRT::free(modifiedNSPRPath);
01325 #endif
01326 }
01327 
01328 
01329 nsresult 
01330 NS_FileSpecToIFile(nsFileSpec* fileSpec, nsILocalFile* *result)
01331 {
01332     nsresult rv;
01333 
01334     nsCOMPtr<nsILocalFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
01335 
01336     if (!file) return NS_ERROR_FAILURE;
01337 
01338 #if defined(XP_MAC)
01339     {
01340         FSSpec spec  = fileSpec->GetFSSpec();
01341         nsCOMPtr<nsILocalFileMac> psmAppMacFile = do_QueryInterface(file, &rv);
01342         if (NS_FAILED(rv)) return rv;
01343         rv = psmAppMacFile->InitWithFSSpec(&spec);
01344         if (NS_FAILED(rv)) return rv;
01345         file = do_QueryInterface(psmAppMacFile, &rv);
01346     }
01347 #else
01348     // XP_MACOSX: do this for OS X to preserve long filenames
01349     rv = file->InitWithNativePath(nsDependentCString(fileSpec->GetNativePathCString()));
01350 #endif
01351     if (NS_FAILED(rv)) return rv;
01352 
01353     *result = file;
01354     NS_ADDREF(*result);
01355     return NS_OK;
01356 }
01357 
01358 
01359 
01360