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
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) 1998
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsFileSpec.h"
50 #include "nsIServiceManager.h"
51 #include "nsILocalFile.h"
61 extern unsigned char* _mbsrchr( const unsigned char*, int);
64 // return pointer to last instance of the given separator
65 static inline char *GetLastSeparator(const char *str
, char sep
)
67 #if defined(XP_WIN) || defined(XP_OS2)
68 return (char*) _mbsrchr((const unsigned char *) str
, sep
);
70 return (char*) strrchr(str
, sep
);
77 #include <TextUtils.h>
80 //========================================================================================
81 // class nsSimpleCharString
82 //========================================================================================
84 //----------------------------------------------------------------------------------------
85 nsSimpleCharString::nsSimpleCharString()
86 //----------------------------------------------------------------------------------------
90 } // nsSimpleCharString::nsSimpleCharString
92 //----------------------------------------------------------------------------------------
93 nsSimpleCharString::nsSimpleCharString(const char* inString
)
94 //----------------------------------------------------------------------------------------
98 CopyFrom(inString
, strlen(inString
));
99 } // nsSimpleCharString::nsSimpleCharString
101 //----------------------------------------------------------------------------------------
102 nsSimpleCharString::nsSimpleCharString(const nsString
& inString
)
103 //----------------------------------------------------------------------------------------
107 } // nsSimpleCharString::nsSimpleCharString
109 //----------------------------------------------------------------------------------------
110 nsSimpleCharString::nsSimpleCharString(const nsSimpleCharString
& inOther
)
111 //----------------------------------------------------------------------------------------
113 mData
= inOther
.mData
;
115 } // nsSimpleCharString::nsSimpleCharString
117 //----------------------------------------------------------------------------------------
118 nsSimpleCharString::nsSimpleCharString(const char* inData
, PRUint32 inLength
)
119 //----------------------------------------------------------------------------------------
122 CopyFrom(inData
, inLength
);
123 } // nsSimpleCharString::nsSimpleCharString
125 //----------------------------------------------------------------------------------------
126 nsSimpleCharString::~nsSimpleCharString()
127 //----------------------------------------------------------------------------------------
130 } // nsSimpleCharString::nsSimpleCharString
132 //----------------------------------------------------------------------------------------
133 void nsSimpleCharString::operator = (const char* inString
)
134 //----------------------------------------------------------------------------------------
137 CopyFrom(inString
, strlen(inString
));
140 } // nsSimpleCharString::operator =
142 //----------------------------------------------------------------------------------------
143 void nsSimpleCharString::operator = (const nsString
& inString
)
144 //----------------------------------------------------------------------------------------
146 PRUint32 len
= inString
.Length();
150 nsFixedCString
dataString(mData
->mString
, len
+ 1);
151 LossyCopyUTF16toASCII(inString
, dataString
);
152 NS_ASSERTION(dataString
.get() == mData
->mString
, "buffer too small");
153 } // nsSimpleCharString::operator =
155 //----------------------------------------------------------------------------------------
156 void nsSimpleCharString::operator = (const nsSimpleCharString
& inOther
)
157 //----------------------------------------------------------------------------------------
159 if (mData
== inOther
.mData
)
162 mData
= inOther
.mData
;
164 } // nsSimpleCharString::operator =
166 //----------------------------------------------------------------------------------------
167 void nsSimpleCharString::operator += (const char* inOther
)
168 //----------------------------------------------------------------------------------------
172 int newLength
= Length() + strlen(inOther
);
173 ReallocData(newLength
);
174 strcat(mData
->mString
, inOther
);
175 } // nsSimpleCharString::operator =
177 //----------------------------------------------------------------------------------------
178 nsSimpleCharString
nsSimpleCharString::operator + (const char* inOther
) const
179 //----------------------------------------------------------------------------------------
181 nsSimpleCharString
result(*this);
184 } // nsSimpleCharString::operator =
186 //----------------------------------------------------------------------------------------
187 void nsSimpleCharString::Catenate(const char* inString1
, const char* inString2
)
188 //----------------------------------------------------------------------------------------
195 int newLength
= Length() + strlen(inString1
) + strlen(inString2
);
196 ReallocData(newLength
);
197 strcat(mData
->mString
, inString1
);
198 strcat(mData
->mString
, inString2
);
199 } // nsSimpleCharString::operator =
201 //----------------------------------------------------------------------------------------
202 void nsSimpleCharString::CopyFrom(const char* inData
, PRUint32 inLength
)
203 //----------------------------------------------------------------------------------------
207 ReallocData(inLength
);
211 memcpy(mData
->mString
, inData
, inLength
);
213 mData
->mString
[inLength
] = '\0';
214 } // nsSimpleCharString::CopyFrom
216 //----------------------------------------------------------------------------------------
217 void nsSimpleCharString::SetToEmpty()
218 //----------------------------------------------------------------------------------------
221 } // nsSimpleCharString::SetToEmpty
223 //----------------------------------------------------------------------------------------
224 void nsSimpleCharString::Unescape()
225 //----------------------------------------------------------------------------------------
229 ReallocData(mData
->mLength
);
232 nsUnescape(mData
->mString
);
233 mData
->mLength
= strlen(mData
->mString
);
234 } // nsSimpleCharString::Unescape
237 //----------------------------------------------------------------------------------------
238 void nsSimpleCharString::AddRefData()
239 //----------------------------------------------------------------------------------------
243 } // nsSimpleCharString::AddRefData
245 //----------------------------------------------------------------------------------------
246 void nsSimpleCharString::ReleaseData()
247 //----------------------------------------------------------------------------------------
251 NS_ASSERTION(mData
->mRefCount
> 0, "String deleted too many times!");
252 if (--mData
->mRefCount
== 0)
255 } // nsSimpleCharString::ReleaseData
257 //----------------------------------------------------------------------------------------
258 inline PRUint32
CalculateAllocLength(PRUint32 logicalLength
)
259 // Round up to the next multiple of 256.
260 //----------------------------------------------------------------------------------------
262 return ((1 + (logicalLength
>> 8)) << 8);
265 //----------------------------------------------------------------------------------------
266 void nsSimpleCharString::ReallocData(PRUint32 inLength
)
267 // Reallocate mData to a new length. Since this presumably precedes a change to the string,
268 // we want to detach ourselves if the data is shared by another string, even if the length
269 // requested would not otherwise require a reallocation.
270 //----------------------------------------------------------------------------------------
272 PRUint32 newAllocLength
= CalculateAllocLength(inLength
);
273 PRUint32 oldAllocLength
= CalculateAllocLength(Length());
276 NS_ASSERTION(mData
->mRefCount
> 0, "String deleted too many times!");
277 if (mData
->mRefCount
== 1)
279 // We are the sole owner, so just change its length, if necessary.
280 if (newAllocLength
> oldAllocLength
)
281 mData
= (Data
*)PR_Realloc(mData
, newAllocLength
+ sizeof(Data
));
282 mData
->mLength
= inLength
;
283 mData
->mString
[inLength
] = '\0'; // we may be truncating
287 PRUint32 copyLength
= Length();
288 if (inLength
< copyLength
)
289 copyLength
= inLength
;
290 Data
* newData
= (Data
*)PR_Malloc(newAllocLength
+ sizeof(Data
));
291 // If data was already allocated when we get to here, then we are cloning the data
292 // from a shared pointer.
295 memcpy(newData
, mData
, sizeof(Data
) + copyLength
);
296 mData
->mRefCount
--; // Say goodbye
299 newData
->mString
[0] = '\0';
302 mData
->mRefCount
= 1;
303 mData
->mLength
= inLength
;
304 } // nsSimpleCharString::ReleaseData
307 //========================================================================================
308 NS_NAMESPACE nsFileSpecHelpers
309 //========================================================================================
312 { kMaxFilenameLength
= 31 // should work on Macintosh, Unix, and Win32.
313 , kMaxAltDigitLength
= 5
314 , kMaxCoreLeafNameLength
= (kMaxFilenameLength
- (kMaxAltDigitLength
+ 1))
316 NS_NAMESPACE_PROTOTYPE
void Canonify(nsSimpleCharString
& ioPath
, PRBool inMakeDirs
);
317 NS_NAMESPACE_PROTOTYPE
void MakeAllDirectories(const char* inPath
, int mode
);
318 #if defined(XP_WIN) || defined(XP_OS2)
319 NS_NAMESPACE_PROTOTYPE
void NativeToUnix(nsSimpleCharString
& ioPath
);
320 NS_NAMESPACE_PROTOTYPE
void UnixToNative(nsSimpleCharString
& ioPath
);
324 //----------------------------------------------------------------------------------------
325 nsresult
ns_file_convert_result(PRInt32 nativeErr
)
326 //----------------------------------------------------------------------------------------
329 NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES
,((nativeErr
)&0xFFFF))
333 //----------------------------------------------------------------------------------------
334 void nsSimpleCharString::LeafReplace(char inSeparator
, const char* inLeafName
)
335 //----------------------------------------------------------------------------------------
337 // Find the existing leaf name
345 char* chars
= mData
->mString
;
346 char* lastSeparator
= GetLastSeparator(chars
, inSeparator
);
347 int oldLength
= Length();
348 PRBool trailingSeparator
= (lastSeparator
+ 1 == chars
+ oldLength
);
349 if (trailingSeparator
)
351 char savedCh
= *lastSeparator
;
352 char *savedLastSeparator
= lastSeparator
;
353 *lastSeparator
= '\0';
354 lastSeparator
= GetLastSeparator(chars
, inSeparator
);
355 *savedLastSeparator
= savedCh
;
358 lastSeparator
++; // point at the trailing string
360 lastSeparator
= chars
; // the full monty
362 PRUint32 savedLastSeparatorOffset
= (lastSeparator
- chars
);
364 (lastSeparator
- chars
) + strlen(inLeafName
) + (trailingSeparator
!= 0);
365 ReallocData(newLength
);
367 chars
= mData
->mString
; // it might have moved.
368 chars
[savedLastSeparatorOffset
] = '\0'; // strip the current leaf name
370 strcat(chars
, inLeafName
);
371 if (trailingSeparator
)
373 // If the original ended in a slash, then the new one should, too.
374 char sepStr
[2] = "/";
375 *sepStr
= inSeparator
;
376 strcat(chars
, sepStr
);
378 } // nsSimpleCharString::LeafReplace
380 //----------------------------------------------------------------------------------------
381 char* nsSimpleCharString::GetLeaf(char inSeparator
) const
382 // Returns a pointer to an allocated string representing the leaf.
383 //----------------------------------------------------------------------------------------
388 char* chars
= mData
->mString
;
389 const char* lastSeparator
= GetLastSeparator(chars
, inSeparator
);
390 // If there was no separator, then return a copy of our path.
392 return nsCRT::strdup(*this);
394 // So there's at least one separator. What's just after it?
395 // If the separator was not the last character, return the trailing string.
396 const char* leafPointer
= lastSeparator
+ 1;
398 return nsCRT::strdup(leafPointer
);
400 // So now, separator was the last character. Poke in a null instead.
401 *(char*)lastSeparator
= '\0'; // Should use const_cast, but Unix has old compiler.
402 leafPointer
= GetLastSeparator(chars
, inSeparator
);
403 char* result
= leafPointer
? nsCRT::strdup(++leafPointer
) : nsCRT::strdup(chars
);
404 // Restore the poked null before returning.
405 *(char*)lastSeparator
= inSeparator
;
406 #if defined(XP_WIN) || defined(XP_OS2)
407 // If it's a drive letter use the colon notation.
408 if (!leafPointer
&& result
[1] == '|' && result
[2] == 0)
412 } // nsSimpleCharString::GetLeaf
414 #if (defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS))
416 //----------------------------------------------------------------------------------------
417 void nsFileSpecHelpers::MakeAllDirectories(const char* inPath
, int mode
)
418 // Make the path a valid one by creating all the intermediate directories. Does NOT
419 // make the leaf into a directory. This should be a unix path.
420 //----------------------------------------------------------------------------------------
425 char* pathCopy
= nsCRT::strdup( inPath
);
429 const char kSeparator
= '/'; // I repeat: this should be a unix-style path.
430 const int kSkipFirst
= 1;
432 #if defined(XP_WIN) || defined(XP_OS2)
433 // Either this is a relative path, or we ensure that it has
434 // a drive letter specifier.
435 NS_ASSERTION( pathCopy
[0] != '/' || (pathCopy
[1] && (pathCopy
[2] == '|' || pathCopy
[2] == '/')),
436 "Not a UNC path and no drive letter!" );
438 char* currentStart
= pathCopy
;
439 char* currentEnd
= strchr(currentStart
+ kSkipFirst
, kSeparator
);
445 #if defined(XP_WIN) || defined(XP_OS2)
447 if we have a drive letter path, we must make sure that the inital path has a '/' on it, or
448 Canonify will turn "/c|" into a path relative to the running executable.
450 if (pathCopy
[0] == '/' && pathCopy
[1] && pathCopy
[2] == '|')
452 char* startDir
= (char*)PR_Malloc(strlen(pathCopy
) + 2);
453 strcpy(startDir
, pathCopy
);
454 strcat(startDir
, "/");
456 spec
= nsFilePath(startDir
, PR_FALSE
);
462 // move after server name and share name in UNC path
463 if (pathCopy
[0] == '/' &&
464 currentEnd
== currentStart
+kSkipFirst
)
467 currentStart
= strchr(pathCopy
+2, kSeparator
);
468 currentStart
= strchr(currentStart
+1, kSeparator
);
469 currentEnd
= strchr(currentStart
+1, kSeparator
);
473 spec
= nsFilePath(pathCopy
, PR_FALSE
);
476 spec
= nsFilePath(pathCopy
, PR_FALSE
);
480 // If the node doesn't exist, and it is not the initial node in a full path,
481 // then make a directory (We cannot make the initial (volume) node).
482 if (!spec
.Exists() && *currentStart
!= kSeparator
)
483 spec
.CreateDirectory(mode
);
485 currentStart
= ++currentEnd
;
486 currentEnd
= strchr(currentStart
, kSeparator
);
492 spec
+= currentStart
; // "lengthen" the path, adding the next node.
493 } while (currentEnd
);
495 nsCRT::free(pathCopy
);
496 } // nsFileSpecHelpers::MakeAllDirectories
498 #endif // XP_UNIX || XP_WIN || XP_OS2 || XP_BEOS
501 #include "nsFileSpecWin.cpp" // Windows-specific implementations
502 #elif defined(XP_BEOS)
503 #include "nsFileSpecBeOS.cpp" // BeOS-specific implementations
504 #elif defined(XP_UNIX)
505 #include "nsFileSpecUnix.cpp" // Unix-specific implementations
506 #elif defined(XP_OS2)
507 #include "nsFileSpecOS2.cpp" // OS/2-specific implementations
510 //========================================================================================
511 // nsFileURL implementation
512 //========================================================================================
514 //----------------------------------------------------------------------------------------
515 nsFileURL::nsFileURL(const char* inString
, PRBool inCreateDirs
)
516 //----------------------------------------------------------------------------------------
520 NS_ASSERTION(strstr(inString
, kFileURLPrefix
) == inString
, "Not a URL!");
521 // Make canonical and absolute. Since it's a parameter to this constructor,
522 // inString is escaped. We want to make an nsFilePath, which requires
523 // an unescaped string.
524 nsSimpleCharString
unescapedPath(inString
+ kFileURLPrefixLength
);
525 unescapedPath
.Unescape();
526 nsFilePath
path(unescapedPath
, inCreateDirs
);
528 } // nsFileURL::nsFileURL
530 //----------------------------------------------------------------------------------------
531 nsFileURL::nsFileURL(const nsString
& inString
, PRBool inCreateDirs
)
532 //----------------------------------------------------------------------------------------
534 NS_LossyConvertUTF16toASCII
cstring(inString
);
535 if (!inString
.Length())
537 NS_ASSERTION(strstr(cstring
.get(), kFileURLPrefix
) == cstring
.get(),
539 // Make canonical and absolute. Since it's a parameter to this constructor,
540 // inString is escaped. We want to make an nsFilePath, which requires
541 // an unescaped string.
542 nsSimpleCharString
unescapedPath(cstring
.get() + kFileURLPrefixLength
);
543 unescapedPath
.Unescape();
544 nsFilePath
path(unescapedPath
, inCreateDirs
);
546 } // nsFileURL::nsFileURL
548 //----------------------------------------------------------------------------------------
549 nsFileURL::nsFileURL(const nsFileURL
& inOther
)
550 //----------------------------------------------------------------------------------------
553 } // nsFileURL::nsFileURL
555 //----------------------------------------------------------------------------------------
556 nsFileURL::nsFileURL(const nsFilePath
& inOther
)
557 //----------------------------------------------------------------------------------------
560 } // nsFileURL::nsFileURL
562 //----------------------------------------------------------------------------------------
563 nsFileURL::nsFileURL(const nsFileSpec
& inOther
)
564 //----------------------------------------------------------------------------------------
567 } // nsFileURL::nsFileURL
569 //----------------------------------------------------------------------------------------
570 nsFileURL::~nsFileURL()
571 //----------------------------------------------------------------------------------------
575 //----------------------------------------------------------------------------------------
576 void nsFileURL::operator = (const char* inString
)
577 //----------------------------------------------------------------------------------------
579 // XXX is this called by nsFileSpecImpl.cpp::SetURLString?
580 // if so, there's a bug...
583 NS_ASSERTION(strstr(inString
, kFileURLPrefix
) == inString
, "Not a URL!");
584 } // nsFileURL::operator =
586 //----------------------------------------------------------------------------------------
587 void nsFileURL::operator +=(const char* inRelativeUnixPath
)
588 //----------------------------------------------------------------------------------------
590 char* escapedPath
= nsEscape(inRelativeUnixPath
, url_Path
);
592 nsCRT::free(escapedPath
);
593 } // nsFileURL::operator +=
595 //----------------------------------------------------------------------------------------
596 nsFileURL
nsFileURL::operator +(const char* inRelativeUnixPath
) const
597 //----------------------------------------------------------------------------------------
599 nsFileURL
result(*this);
600 result
+= inRelativeUnixPath
;
602 } // nsFileURL::operator +
604 //----------------------------------------------------------------------------------------
605 void nsFileURL::operator = (const nsFileURL
& inOther
)
606 //----------------------------------------------------------------------------------------
609 } // nsFileURL::operator =
611 //----------------------------------------------------------------------------------------
612 void nsFileURL::operator = (const nsFilePath
& inOther
)
613 //----------------------------------------------------------------------------------------
615 mURL
= kFileURLPrefix
;
616 char* original
= (char*)(const char*)inOther
; // we shall modify, but restore.
617 if (!original
|| !*original
) return;
618 #if defined(XP_WIN) || defined(XP_OS2)
619 // because we don't want to escape the '|' character, change it to a letter.
620 // Note that a UNC path will not have a '|' character.
621 char oldchar
= original
[2];
623 char* escapedPath
= nsEscape(original
, url_Path
);
624 original
[2] = escapedPath
[2] = oldchar
; // restore it
626 char* escapedPath
= nsEscape(original
, url_Path
);
630 nsCRT::free(escapedPath
);
631 } // nsFileURL::operator =
633 //----------------------------------------------------------------------------------------
634 void nsFileURL::operator = (const nsFileSpec
& inOther
)
635 //----------------------------------------------------------------------------------------
637 *this = nsFilePath(inOther
);
638 if (mURL
[mURL
.Length() - 1] != '/' && inOther
.IsDirectory())
640 } // nsFileURL::operator =
643 //========================================================================================
644 // nsFilePath implementation
645 //========================================================================================
647 //----------------------------------------------------------------------------------------
648 nsFilePath::nsFilePath(const nsFilePath
& inPath
)
649 //----------------------------------------------------------------------------------------
650 : mPath(inPath
.mPath
)
654 //----------------------------------------------------------------------------------------
655 nsFilePath::nsFilePath(const char* inString
, PRBool inCreateDirs
)
656 //----------------------------------------------------------------------------------------
662 NS_ASSERTION(strstr(inString
, kFileURLPrefix
) != inString
, "URL passed as path");
664 #if defined(XP_WIN) || defined(XP_OS2)
665 nsFileSpecHelpers::UnixToNative(mPath
);
667 // Make canonical and absolute.
668 nsFileSpecHelpers::Canonify(mPath
, inCreateDirs
);
669 #if defined(XP_WIN) || defined(XP_OS2)
670 // Assert native path is of one of these forms:
671 // - regular: X:\some\path
672 // - UNC: \\some_machine\some\path
673 NS_ASSERTION( mPath
[1] == ':' || (mPath
[0] == '\\' && mPath
[1] == '\\'),
674 "unexpected canonical path" );
675 nsFileSpecHelpers::NativeToUnix(mPath
);
679 //----------------------------------------------------------------------------------------
680 nsFilePath::nsFilePath(const nsString
& inString
, PRBool inCreateDirs
)
681 //----------------------------------------------------------------------------------------
687 NS_ASSERTION(strstr((const char*)mPath
, kFileURLPrefix
) != (const char*)mPath
, "URL passed as path");
688 #if defined(XP_WIN) || defined(XP_OS2)
689 nsFileSpecHelpers::UnixToNative(mPath
);
691 // Make canonical and absolute.
692 nsFileSpecHelpers::Canonify(mPath
, inCreateDirs
);
693 #if defined(XP_WIN) || defined(XP_OS2)
694 NS_ASSERTION( mPath
[1] == ':' || (mPath
[0] == '\\' && mPath
[1] == '\\'),
695 "unexpected canonical path" );
696 nsFileSpecHelpers::NativeToUnix(mPath
);
700 //----------------------------------------------------------------------------------------
701 nsFilePath::nsFilePath(const nsFileURL
& inOther
)
702 //----------------------------------------------------------------------------------------
704 mPath
= (const char*)inOther
.mURL
+ kFileURLPrefixLength
;
708 #if (defined XP_UNIX || defined XP_BEOS)
709 //----------------------------------------------------------------------------------------
710 nsFilePath::nsFilePath(const nsFileSpec
& inOther
)
711 //----------------------------------------------------------------------------------------
712 : mPath(inOther
.mPath
)
715 #endif // XP_UNIX || XP_BEOS
717 //----------------------------------------------------------------------------------------
718 nsFilePath::~nsFilePath()
719 //----------------------------------------------------------------------------------------
723 #if (defined XP_UNIX || defined XP_BEOS)
724 //----------------------------------------------------------------------------------------
725 void nsFilePath::operator = (const nsFileSpec
& inOther
)
726 //----------------------------------------------------------------------------------------
728 // XXX bug here, again if.
730 mPath
= inOther
.mPath
;
734 //----------------------------------------------------------------------------------------
735 void nsFilePath::operator = (const char* inString
)
736 //----------------------------------------------------------------------------------------
739 NS_ASSERTION(strstr(inString
, kFileURLPrefix
) != inString
, "URL passed as path");
743 #if defined(XP_WIN) || defined(XP_OS2)
744 nsFileSpecHelpers::UnixToNative(mPath
);
746 // Make canonical and absolute.
747 nsFileSpecHelpers::Canonify(mPath
, PR_FALSE
/* XXX? */);
748 #if defined(XP_WIN) || defined(XP_OS2)
749 nsFileSpecHelpers::NativeToUnix(mPath
);
753 //----------------------------------------------------------------------------------------
754 void nsFilePath::operator = (const nsFileURL
& inOther
)
755 //----------------------------------------------------------------------------------------
757 mPath
= (const char*)nsFilePath(inOther
);
760 //----------------------------------------------------------------------------------------
761 void nsFilePath::operator = (const nsFilePath
& inOther
)
762 //----------------------------------------------------------------------------------------
764 mPath
= inOther
.mPath
;
767 //----------------------------------------------------------------------------------------
768 void nsFilePath::operator +=(const char* inRelativeUnixPath
)
769 //----------------------------------------------------------------------------------------
771 NS_ASSERTION(inRelativeUnixPath
, "Attempt append relative path with null path");
773 char* escapedPath
= nsEscape(inRelativeUnixPath
, url_Path
);
774 mPath
+= escapedPath
;
775 nsCRT::free(escapedPath
);
776 } // nsFilePath::operator +=
778 //----------------------------------------------------------------------------------------
779 nsFilePath
nsFilePath::operator +(const char* inRelativeUnixPath
) const
780 //----------------------------------------------------------------------------------------
782 NS_ASSERTION(inRelativeUnixPath
, "Attempt append relative path with null path");
784 nsFilePath
resultPath(*this);
785 resultPath
+= inRelativeUnixPath
;
787 } // nsFilePath::operator +
790 //========================================================================================
791 // nsFileSpec implementation
792 //========================================================================================
794 //----------------------------------------------------------------------------------------
795 nsFileSpec::nsFileSpec()
796 //----------------------------------------------------------------------------------------
797 : mError(NS_OK
) // XXX shouldn't this be NS_ERROR_NOT_INITIALIZED?
799 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
802 //----------------------------------------------------------------------------------------
803 void nsFileSpec::Clear()
804 //----------------------------------------------------------------------------------------
807 mError
= NS_ERROR_NOT_INITIALIZED
;
810 //----------------------------------------------------------------------------------------
811 nsFileSpec::~nsFileSpec()
812 //----------------------------------------------------------------------------------------
814 // mPath cleans itself up
817 //----------------------------------------------------------------------------------------
818 nsFileSpec::nsFileSpec(const nsPersistentFileDescriptor
& inDescriptor
)
819 //----------------------------------------------------------------------------------------
821 *this = inDescriptor
;
824 //----------------------------------------------------------------------------------------
825 nsFileSpec::nsFileSpec(const nsFileURL
& inURL
)
826 //----------------------------------------------------------------------------------------
828 *this = nsFilePath(inURL
); // convert to unix path first
831 //----------------------------------------------------------------------------------------
832 void nsFileSpec::MakeUnique(const char* inSuggestedLeafName
, PRBool inCreateFile
)
833 //----------------------------------------------------------------------------------------
835 if (inSuggestedLeafName
&& *inSuggestedLeafName
)
836 SetLeafName(inSuggestedLeafName
);
837 MakeUnique(inCreateFile
);
838 } // nsFileSpec::MakeUnique
840 //----------------------------------------------------------------------------------------
841 void nsFileSpec::MakeUnique(PRBool inCreateFile
)
842 //----------------------------------------------------------------------------------------
844 // XXX: updated path starts empty. In case of error this will cause
845 // any callers to fail badly, but that seems better than letting them
846 // re-use the default name which has failed to be unique.
848 nsCOMPtr
<nsILocalFile
> localFile
;
849 NS_NewNativeLocalFile(nsDependentCString(*this), PR_TRUE
, getter_AddRefs(localFile
));
855 rv
= localFile
->CreateUnique(nsIFile::NORMAL_FILE_TYPE
, 0600);
857 rv
= localFile
->CreateUnique(nsIFile::DIRECTORY_TYPE
, 0700);
859 if (NS_SUCCEEDED(rv
))
860 localFile
->GetNativePath(path
);
863 NS_ASSERTION(!path
.IsEmpty(), "MakeUnique() failed!");
864 *this = path
.get(); // reset the filepath to point to the unique location
866 } // nsFileSpec::MakeUnique
868 //----------------------------------------------------------------------------------------
869 void nsFileSpec::operator = (const nsFileURL
& inURL
)
870 //----------------------------------------------------------------------------------------
872 *this = nsFilePath(inURL
); // convert to unix path first
875 //----------------------------------------------------------------------------------------
876 void nsFileSpec::operator = (const nsPersistentFileDescriptor
& inDescriptor
)
877 //----------------------------------------------------------------------------------------
881 inDescriptor
.GetData(data
);
884 // Decode descriptor into a Handle (which is actually an AliasHandle)
885 char* decodedData
= PL_Base64Decode(data
.get(), data
.Length(), nsnull
);
886 Handle aliasH
= nsnull
;
887 mError
= NS_FILE_RESULT(::PtrToHand(decodedData
, &aliasH
, (data
.Length() * 3) / 4));
888 PR_Free(decodedData
);
889 if (NS_FAILED(mError
))
890 return; // not enough memory?
894 mError
= NS_FILE_RESULT(::FSResolveAlias(nsnull
, (AliasHandle
)aliasH
, &fileRef
, &changed
));
895 ::DisposeHandle(aliasH
);
897 UInt8 pathBuf
[PATH_MAX
];
898 mError
= NS_FILE_RESULT(::FSRefMakePath(&fileRef
, pathBuf
, PATH_MAX
));
899 if (NS_FAILED(mError
))
901 mPath
= (const char*)pathBuf
;
908 //========================================================================================
909 // UNIX & WIN nsFileSpec implementation
910 //========================================================================================
912 #if (defined XP_UNIX || defined XP_BEOS)
913 //----------------------------------------------------------------------------------------
914 nsFileSpec::nsFileSpec(const nsFilePath
& inPath
)
915 //----------------------------------------------------------------------------------------
916 : mPath((const char*)inPath
)
919 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
922 //----------------------------------------------------------------------------------------
923 void nsFileSpec::operator = (const nsFilePath
& inPath
)
924 //----------------------------------------------------------------------------------------
926 mPath
= (const char*)inPath
;
929 #endif // XP_UNIX || XP_BEOS
931 #if (defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS))
932 //----------------------------------------------------------------------------------------
933 nsFileSpec::nsFileSpec(const nsFileSpec
& inSpec
)
934 //----------------------------------------------------------------------------------------
935 : mPath(inSpec
.mPath
)
938 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
941 //----------------------------------------------------------------------------------------
942 nsFileSpec::nsFileSpec(const char* inString
, PRBool inCreateDirs
)
943 //----------------------------------------------------------------------------------------
947 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
948 // Make canonical and absolute.
949 nsFileSpecHelpers::Canonify(mPath
, inCreateDirs
);
952 //----------------------------------------------------------------------------------------
953 nsFileSpec::nsFileSpec(const nsString
& inString
, PRBool inCreateDirs
)
954 //----------------------------------------------------------------------------------------
958 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
959 // Make canonical and absolute.
960 nsFileSpecHelpers::Canonify(mPath
, inCreateDirs
);
963 //----------------------------------------------------------------------------------------
964 void nsFileSpec::operator = (const nsFileSpec
& inSpec
)
965 //----------------------------------------------------------------------------------------
967 mPath
= inSpec
.mPath
;
968 mError
= inSpec
.Error();
971 //----------------------------------------------------------------------------------------
972 void nsFileSpec::operator = (const char* inString
)
973 //----------------------------------------------------------------------------------------
976 // Make canonical and absolute.
977 nsFileSpecHelpers::Canonify(mPath
, PR_FALSE
/* XXX? */);
980 #endif // XP_UNIX,XP_WIN,XP_OS2,XP_BEOS
982 //----------------------------------------------------------------------------------------
983 nsFileSpec
nsFileSpec::operator + (const char* inRelativePath
) const
984 //----------------------------------------------------------------------------------------
986 NS_ASSERTION(inRelativePath
, "Attempt to append name with a null string");
988 nsFileSpec resultSpec
= *this;
989 resultSpec
+= inRelativePath
;
991 } // nsFileSpec::operator +
993 //----------------------------------------------------------------------------------------
994 PRBool
nsFileSpec::operator == (const nsFileSpec
& inOther
) const
995 //----------------------------------------------------------------------------------------
997 PRBool amEmpty
= mPath
.IsEmpty();
998 PRBool heEmpty
= inOther
.mPath
.IsEmpty();
999 if (amEmpty
) // we're the same if he's empty...
1001 if (heEmpty
) // ('cuz I'm not...)
1004 nsSimpleCharString str
= mPath
;
1005 nsSimpleCharString inStr
= inOther
.mPath
;
1007 // Length() is size of buffer, not length of string
1008 PRUint32 strLast
= str
.Length() - 1, inLast
= inStr
.Length() - 1;
1009 #if defined(XP_WIN) || defined(XP_OS2)
1010 #define DIR_SEPARATOR '\\' // XXX doesn't NSPR have this?
1011 /* windows does not care about case. */
1013 #define DIR_STRCMP strcmp
1015 #define DIR_STRCMP _stricmp
1018 #define DIR_SEPARATOR '/'
1020 #define DIR_STRCMP strcasecmp
1022 #define DIR_STRCMP strcmp
1025 if(str
[strLast
] == DIR_SEPARATOR
)
1026 str
[strLast
] = '\0';
1028 if(inStr
[inLast
] == DIR_SEPARATOR
)
1029 inStr
[inLast
] = '\0';
1031 if (DIR_STRCMP(str
, inStr
) == 0)
1033 #undef DIR_SEPARATOR
1038 //----------------------------------------------------------------------------------------
1039 PRBool
nsFileSpec::operator != (const nsFileSpec
& inOther
) const
1040 //----------------------------------------------------------------------------------------
1042 return (! (*this == inOther
) );
1045 //----------------------------------------------------------------------------------------
1046 // This is the only automatic conversion to const char*
1047 // that is provided, and it allows the
1048 // path to be "passed" to NSPR file routines. This practice
1049 // is VERY EVIL and should only be used to support legacy
1050 // code. Using it guarantees bugs on Macintosh. The path is NOT allocated, so do
1051 // not even think of deleting (or freeing) it.
1052 const char* nsFileSpec::GetCString() const
1053 //----------------------------------------------------------------------------------------
1058 //----------------------------------------------------------------------------------------
1059 // Is our spec a child of the provided parent?
1060 PRBool
nsFileSpec::IsChildOf(nsFileSpec
&possibleParent
)
1061 //----------------------------------------------------------------------------------------
1063 nsFileSpec iter
= *this, parent
;
1070 NS_ASSERTION(depth
< 100, "IsChildOf has lost its little mind");
1074 if (iter
== possibleParent
)
1077 iter
.GetParent(parent
); // shouldn't this be an error on parent?
1081 if (iter
== parent
) // hit bottom
1090 // not reached, but I bet some compiler will whine
1095 //========================================================================================
1096 // class nsPersistentFileDescriptor
1097 //========================================================================================
1099 //----------------------------------------------------------------------------------------
1100 nsPersistentFileDescriptor::nsPersistentFileDescriptor(const nsPersistentFileDescriptor
& inDesc
)
1101 //----------------------------------------------------------------------------------------
1102 : mDescriptorString(inDesc
.mDescriptorString
)
1104 } // nsPersistentFileDescriptor::nsPersistentFileDescriptor
1106 //----------------------------------------------------------------------------------------
1107 void nsPersistentFileDescriptor::operator = (const nsPersistentFileDescriptor
& inDesc
)
1108 //----------------------------------------------------------------------------------------
1110 mDescriptorString
= inDesc
.mDescriptorString
;
1111 } // nsPersistentFileDescriptor::operator =
1113 //----------------------------------------------------------------------------------------
1114 nsPersistentFileDescriptor::nsPersistentFileDescriptor(const nsFileSpec
& inSpec
)
1115 //----------------------------------------------------------------------------------------
1118 } // nsPersistentFileDescriptor::nsPersistentFileDescriptor
1120 //----------------------------------------------------------------------------------------
1121 void nsPersistentFileDescriptor::operator = (const nsFileSpec
& inSpec
)
1122 //----------------------------------------------------------------------------------------
1130 OSErr err
= ::FSPathMakeRef((const UInt8
*)inSpec
.GetCString(), &fileRef
, &isDir
);
1135 err
= ::FSNewAlias(nsnull
, &fileRef
, &aliasH
);
1139 PRUint32 bytes
= ::GetHandleSize((Handle
) aliasH
);
1140 ::HLock((Handle
)aliasH
);
1141 char* buf
= PL_Base64Encode((const char*)*aliasH
, bytes
, nsnull
);
1142 ::DisposeHandle((Handle
) aliasH
);
1144 mDescriptorString
= buf
;
1147 mDescriptorString
= inSpec
.GetCString();
1149 } // nsPersistentFileDescriptor::operator =
1151 //----------------------------------------------------------------------------------------
1152 nsPersistentFileDescriptor::~nsPersistentFileDescriptor()
1153 //----------------------------------------------------------------------------------------
1155 } // nsPersistentFileDescriptor::~nsPersistentFileDescriptor
1157 //----------------------------------------------------------------------------------------
1158 void nsPersistentFileDescriptor::GetData(nsAFlatCString
& outData
) const
1159 //----------------------------------------------------------------------------------------
1161 outData
.Assign(mDescriptorString
, mDescriptorString
.Length());
1164 //----------------------------------------------------------------------------------------
1165 void nsPersistentFileDescriptor::SetData(const nsAFlatCString
& inData
)
1166 //----------------------------------------------------------------------------------------
1168 mDescriptorString
.CopyFrom(inData
.get(), inData
.Length());
1171 //----------------------------------------------------------------------------------------
1172 void nsPersistentFileDescriptor::SetData(const char* inData
, PRInt32 inSize
)
1173 //----------------------------------------------------------------------------------------
1175 mDescriptorString
.CopyFrom(inData
, inSize
);
1178 //========================================================================================
1180 //========================================================================================
1182 //----------------------------------------------------------------------------------------
1183 nsNSPRPath::operator const char*() const
1184 // NSPR expects a UNIX path on unix and Macintosh, but a native path on windows. NSPR
1185 // cannot be changed, so we have to do the dirty work.
1186 //----------------------------------------------------------------------------------------
1188 #if defined(XP_WIN) || defined(XP_OS2)
1189 if (!modifiedNSPRPath
)
1191 // If this is the first call, initialize modifiedNSPRPath. Start by cloning
1192 // mFilePath, but strip the leading separator, if present
1193 const char* unixPath
= (const char*)mFilePath
;
1197 ((nsNSPRPath
*)this)->modifiedNSPRPath
1198 = nsCRT::strdup(*unixPath
== '/' ? unixPath
+ 1: unixPath
);
1201 if (modifiedNSPRPath
[1] == '|')
1202 modifiedNSPRPath
[1] = ':';
1204 // Remove the ending separator only if it is not the last separator
1205 int len
= strlen(modifiedNSPRPath
);
1206 if (modifiedNSPRPath
[len
- 1 ] == '/' && modifiedNSPRPath
[len
- 2 ] != ':')
1207 modifiedNSPRPath
[len
- 1 ] = '\0';
1209 return modifiedNSPRPath
;
1211 return (const char*)mFilePath
;
1215 //----------------------------------------------------------------------------------------
1216 nsNSPRPath::~nsNSPRPath()
1217 //----------------------------------------------------------------------------------------
1219 #if defined(XP_WIN) || defined(XP_OS2)
1220 if (modifiedNSPRPath
)
1221 nsCRT::free(modifiedNSPRPath
);
1227 NS_FileSpecToIFile(nsFileSpec
* fileSpec
, nsILocalFile
* *result
)
1231 nsCOMPtr
<nsILocalFile
> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID
));
1233 if (!file
) return NS_ERROR_FAILURE
;
1235 rv
= file
->InitWithNativePath(nsDependentCString(fileSpec
->GetNativePathCString()));
1237 if (NS_FAILED(rv
)) return rv
;