source: trunk/third/firefox/xpcom/obsolete/nsFileSpecMac.cpp @ 21695

Revision 21695, 49.1 KB checked in by rbasch, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21694, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Netscape Public License
6 * Version 1.1 (the "License"); you may not use this file except in
7 * compliance with the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/NPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
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.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * 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 NPL, 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 NPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37 
38//        This file is included by nsFile.cp, and includes the Macintosh-specific
39//        implementations.
40
41
42#include <string.h>
43
44#include "prtypes.h"
45#include "nscore.h"
46
47#include "FullPath.h"
48#include "FileCopy.h"
49#include "MoreFilesExtras.h"
50
51#include <Aliases.h>
52#include <Folders.h>
53#include <Math64.h>
54#include <TextUtils.h>
55#include <Processes.h>
56#include <limits.h>             // ULONG_MAX
57
58#include "nsFileSpec.h"
59#include "nsEscape.h"
60#include "nsXPIDLString.h"
61
62
63const unsigned char* kAliasHavenFolderName = "\pnsAliasHaven";
64
65//========================================================================================
66namespace MacFileHelpers
67//========================================================================================
68{
69        inline void                                             PLstrcpy(Str255 dst, ConstStr255Param src)
70                                                                        {
71                                                                                memcpy(dst, src, 1 + src[0]);
72                                                                        }
73
74        void                                                    PLstrcpy(Str255 dst, const char* src, int inMaxLen=255);
75        void                                                    PLstrncpy(Str255 dst, const char* src, int inMaxLen);
76
77        void                                                    SwapSlashColon(char * s);
78        OSErr                                                   FSSpecFromUnixPath(
79                                                                                const char * unixPath,
80                                                                                FSSpec& ioSpec,
81                                                                                Boolean hexDecode,
82                                                                                Boolean resolveAlias,
83                                                                                Boolean allowPartial = false,
84                                                                                Boolean createDirs = false);
85        char*                                                   MacPathFromUnixPath(
86                                                                                const char* unixPath,
87                                                                                Boolean hexDecode);
88        char*                                                   EncodeMacPath(
89                                                                                char* inPath, // NOT const - gets clobbered
90                                                                                Boolean prependSlash,
91                                                                                Boolean doEscape );
92        OSErr                                                   FSSpecFromPathname(
93                                                                                const char* inPathNamePtr,
94                                                                                FSSpec& ioSpec,
95                                                                                Boolean inCreateDirs);
96        char*                                                   PathNameFromFSSpec(
97                                                                                const FSSpec& inSpec );
98        OSErr                                                   CreateFolderInFolder(
99                                                                                short                           refNum,         // Parent directory/volume
100                                                                                long                            dirID,
101                                                                                ConstStr255Param        folderName,        // Name of the new folder
102                                                                                short&                          outRefNum,        // Volume of the created folder
103                                                                                long&                           outDirID);        //
104
105        // Some routines to support an "alias haven" directory.  Aliases in this directory
106        // are never resolved.  There is a ResolveAlias here that respects that.  This is
107        // to support attaching of aliases in mail.
108        void                                                    EnsureAliasHaven();
109        void                                                    SetNoResolve(Boolean inResolve);
110        PRBool                                                  IsAliasSafe(const FSSpec& inSpec);
111        OSErr                                                   MakeAliasSafe(FSSpec& inOutSpec);
112        OSErr                                                   ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased);
113
114        Boolean                                                 sNoResolve = false;
115        long                                                    sAliasHavenDirID = 0;
116        short                                                   sAliasHavenVRefNum = 0;
117} // namespace MacFileHelpers
118
119//----------------------------------------------------------------------------------------
120void MacFileHelpers::PLstrcpy(Str255 dst, const char* src, int inMax)
121//----------------------------------------------------------------------------------------
122{
123        int srcLength = strlen(src);
124        NS_ASSERTION(srcLength <= inMax, "Oops, string is too long!");
125        if (srcLength > inMax)
126                srcLength = inMax;
127        dst[0] = srcLength;
128        memcpy(&dst[1], src, srcLength);
129}
130
131//----------------------------------------------------------------------------------------
132void MacFileHelpers::PLstrncpy(Str255 dst, const char* src, int inMax)
133//----------------------------------------------------------------------------------------
134{
135        int srcLength = strlen(src);
136        if (srcLength > inMax)
137                srcLength = inMax;
138        dst[0] = srcLength;
139        memcpy(&dst[1], src, srcLength);
140}
141
142//-----------------------------------
143void MacFileHelpers::SwapSlashColon(char * s)
144//-----------------------------------
145
146{
147        while (*s)
148        {
149                if (*s == '/')
150                        *s++ = ':';
151                else if (*s == ':')
152                        *s++ = '/';
153                else
154                        *s++;
155        }
156} // MacFileHelpers::SwapSlashColon
157
158//-----------------------------------
159char* MacFileHelpers::EncodeMacPath(
160        char* inPath, // NOT const, gets clobbered
161        Boolean prependSlash,
162        Boolean doEscape )
163//        Transforms Macintosh style path into Unix one
164//        Method: Swap ':' and '/', hex escape the result
165//-----------------------------------
166{
167        if (inPath == nsnull)
168                return nsnull;
169        int pathSize = strlen(inPath);
170       
171        // XP code sometimes chokes if there's a final slash in the unix path.
172        // Since correct mac paths to folders and volumes will end in ':', strip this
173        // first.
174        char* c = inPath + pathSize - 1;
175        if (*c == ':')
176        {
177                *c = 0;
178                pathSize--;
179        }
180
181        char * newPath = nsnull;
182        char * finalPath = nsnull;
183       
184        if (prependSlash)
185        {
186                newPath = new char[pathSize + 2];
187                newPath[0] = ':';        // It will be converted to '/'
188                memcpy(&newPath[1], inPath, pathSize + 1);
189        }
190        else
191        {
192                newPath = new char[pathSize + 1];
193                strcpy(newPath, inPath);
194        }
195        if (newPath)
196        {
197                SwapSlashColon( newPath );
198                if (doEscape)
199                {
200                        finalPath = nsEscape(newPath, url_Path);
201                        delete [] newPath;
202                }
203                else
204                        finalPath = newPath;
205        }
206        delete [] inPath;
207        return finalPath;
208} // MacFileHelpers::EncodeMacPath
209
210//----------------------------------------------------------------------------------------
211inline void MacFileHelpers::SetNoResolve(Boolean inResolve)
212//----------------------------------------------------------------------------------------
213{
214        sNoResolve = inResolve;
215} // MacFileHelpers::SetNoResolve
216
217//----------------------------------------------------------------------------------------
218OSErr MacFileHelpers::MakeAliasSafe(FSSpec& inOutSpec)
219// Pass in the spec of an alias.  This copies the file to the safe haven folder, and
220// returns the spec of the copy to the caller
221//----------------------------------------------------------------------------------------
222{
223        EnsureAliasHaven();
224        nsFileSpec dstDirSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\p");
225
226        // Make sure its name is unique
227        nsFileSpec havenSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\pG'day");
228        if (havenSpec.Valid())
229                havenSpec.MakeUnique(inOutSpec.name);
230        // Copy the file into the haven directory
231        if (havenSpec.Valid())
232        {
233                OSErr err = ::FSpFileCopy(
234                                                &inOutSpec,
235                                                dstDirSpec,
236                                                havenSpec.GetLeafPName(),
237                                                nil, 0, true);
238                // Return the spec of the copy to the caller.
239                if (err != noErr)
240                        return err;
241                inOutSpec = havenSpec;
242        }
243        return noErr;
244} // MacFileHelpers::MakeAliasSafe
245
246//----------------------------------------------------------------------------------------
247char* MacFileHelpers::MacPathFromUnixPath(const char* unixPath, Boolean hexDecode)
248//----------------------------------------------------------------------------------------
249{
250        // Relying on the fact that the unix path is always longer than the mac path:
251        size_t len = strlen(unixPath);
252        char* result = new char[len + 2]; // ... but allow for the initial colon in a partial name
253        // REMEMBER: at the end we call SwapSlashColon, so bear that in mind when you see
254        // this code using '/' as a separator in what is supposed to be a Macintosh path!
255        if (result)
256        {
257                char* dst = result;
258                const char* src = unixPath;
259                if (*src == '/')                         // * full path
260                        src++;
261                else if (strchr(src, '/') && *src != '.')
262                {
263                        // * partial path, and not just a leaf name. The '.' test is there because
264                        // the loop below will add sufficient colons in that case.
265                        *dst++ = '/';
266                }
267                // Copy src to dst, but watch out for .. and .
268                char c = '/';
269                do
270                {
271                        char cprev = c; // remember the previous char (initially /)
272                        c = *src++;
273                        if (c == '.' && cprev == '/')
274                        {
275                                char* dstSaved = dst;
276                                // Special cases: "." and "..". Convert to ':' and '::'
277                                *dst++ = '/';  // . becomes :
278                                c = *src++;
279                                if (c == '.')
280                                {
281                                        *dst++ = '/'; // .. becomes ::
282                                        c = *src++;
283                                }
284                                if (c == '/')
285                                {
286                                        // ../    becomes       :: so just skip the slash
287                                        // ./     becomes       :  "  "    "    "       "
288                                        src++;
289                                }
290                                else if (c)
291                                {
292                                        // Oh. A file called ".foo" or "..foo"
293                                        // Back up and just do the normal thing.
294                                        src -= (dst - dstSaved);
295                                        dst = dstSaved;
296                                        // Since c is not '/', we won't do this stuff on the
297                                        // next iteration.
298                                }
299                                continue;
300                        }
301                        else if (c == '/' && cprev == '/')
302                        {
303                                // Hmm. A 'run on' path with two slashes right next to each other.
304                                // This is an illegal path, but, hey, we'll be tough and try to
305                                // deal with it (especially since '::' has loaded semantics in
306                                // a Mac path)
307                                continue;
308                        }
309                        *dst++ = c;
310                } while (c);
311                if (hexDecode)
312                        nsUnescape(result);        // Hex Decode
313                MacFileHelpers::SwapSlashColon(result);
314        }
315        return result;
316} // MacFileHelpers::MacPathFromUnixPath
317
318//----------------------------------------------------------------------------------------
319OSErr MacFileHelpers::FSSpecFromPathname(
320        const char* inPathNamePtr,
321        FSSpec& ioSpec, // used as in-parameter for a relative path.
322        Boolean inCreateDirs)
323// FSSpecFromPathname reverses PathNameFromFSSpec.
324// It returns a FSSpec given a c string which is a mac pathname.
325//----------------------------------------------------------------------------------------
326{
327        OSErr err;
328        // Simplify this routine to use FSMakeFSSpec if length < 255. Otherwise use the MoreFiles
329        // routine FSpLocationFromFullPath, which allocates memory, to handle longer pathnames.
330       
331        short inVRefNum = ioSpec.vRefNum;
332        long inParID = ioSpec.parID;
333       
334        size_t inLength = strlen(inPathNamePtr);
335        bool isRelative = (strchr(inPathNamePtr, ':') == 0 || *inPathNamePtr == ':');
336#ifdef NS_DEBUG
337        // Attempt to catch people sending unix paths in to routines that expect native ones.
338        NS_ASSERTION(strchr(inPathNamePtr, '/') == 0,
339                        "Possible unix path where native path is required");
340#endif
341        if (inLength < 255)
342        {
343                Str255 pascalpath;
344                MacFileHelpers::PLstrcpy(pascalpath, inPathNamePtr);
345                if (isRelative)
346                        err = ::FSMakeFSSpec(inVRefNum, inParID, pascalpath, &ioSpec);
347                else
348                        err = ::FSMakeFSSpec(0, 0, pascalpath, &ioSpec);
349        }
350        else if (!isRelative)
351                err = FSpLocationFromFullPath(inLength, inPathNamePtr, &ioSpec);
352        else
353                err = bdNamErr;
354
355        if ((err == dirNFErr || err == bdNamErr) && inCreateDirs)
356        {
357                const char* path = inPathNamePtr;
358                if (isRelative)
359                {
360                        ioSpec.vRefNum = inVRefNum;
361                        ioSpec.parID = inParID;
362                }
363                else
364                {
365                        ioSpec.vRefNum = 0;
366                        ioSpec.parID = 0;
367                }
368                do {
369                        // Locate the colon that terminates the node.
370                        // But if we've a partial path (starting with a colon), find the second one.
371                        const char* nextColon = strchr(path + (*path == ':'), ':');
372                        // Well, if there are no more colons, point to the end of the string.
373                        if (!nextColon)
374                                nextColon = path + strlen(path);
375
376                        // Make a pascal string out of this node.  Include initial
377                        // and final colon, if any!
378                        Str255 ppath;
379                        MacFileHelpers::PLstrncpy(ppath, path, nextColon - path + 1);
380                       
381                        // Use this string as a relative path using the directory created
382                        // on the previous round (or directory 0,0 on the first round).
383                        err = ::FSMakeFSSpec(ioSpec.vRefNum, ioSpec.parID, ppath, &ioSpec);
384
385                        // If this was the leaf node, then we are done.
386                        if (!*nextColon)
387                                break;
388
389                        // Since there's more to go, we have to get the directory ID, which becomes
390                        // the parID for the next round.
391                        if (err == noErr)
392                        {
393                                // The directory (or perhaps a file) exists. Find its dirID.
394                                long dirID;
395                                Boolean isDirectory;
396                                err = ::FSpGetDirectoryID(&ioSpec, &dirID, &isDirectory);
397                                if (!isDirectory)
398                                        return dupFNErr; // oops! a file exists with that name.
399                                if (err)
400                                        return err;
401                                ioSpec.parID = dirID;
402                        }
403                        else if (err == fnfErr)
404                        {
405                                // If we got "file not found", then
406                                // we need to create a directory.
407                                err = ::FSpDirCreate(&ioSpec, smCurrentScript, &ioSpec.parID);
408                                // For some reason, this usually returns fnfErr, even though it works.
409                                if (err == fnfErr)
410                                        err = noErr;
411                        }
412                        if (err != noErr)
413                                return err;
414                        path = nextColon; // next round
415                } while (1);
416        }
417        return err;
418} // MacFileHelpers::FSSpecFromPathname
419
420//----------------------------------------------------------------------------------------
421OSErr MacFileHelpers::CreateFolderInFolder(
422        short                            refNum,         // Parent directory/volume
423        long                            dirID,
424        ConstStr255Param        folderName,        // Name of the new folder
425        short&                            outRefNum,    // Volume of the created folder
426        long&                            outDirID)        //
427// Creates a folder named 'folderName' inside a folder.
428// The errors returned are same as PBDirCreate
429//----------------------------------------------------------------------------------------
430{
431        HFileParam hpb;
432        hpb.ioVRefNum = refNum;
433        hpb.ioDirID = dirID;
434        hpb.ioNamePtr = (StringPtr)&folderName;
435
436        OSErr err = PBDirCreateSync((HParmBlkPtr)&hpb);
437        if (err == noErr)
438        {
439                outRefNum = hpb.ioVRefNum;
440                outDirID = hpb.ioDirID;
441        }
442        else
443        {
444                outRefNum = 0;
445                outDirID = 0;
446        }
447        return err;
448} // MacFileHelpers::CreateFolderInFolder
449
450//----------------------------------------------------------------------------------------
451void MacFileHelpers::EnsureAliasHaven()
452//----------------------------------------------------------------------------------------
453{
454        // Alias Haven is a directory in which we never resolve aliases.
455        if (sAliasHavenVRefNum != 0)
456                return;
457
458       
459        FSSpec temp;
460        if (FindFolder(0, kTemporaryFolderType, true, & temp.vRefNum, &temp.parID) == noErr)
461        {
462                CreateFolderInFolder(
463                        temp.vRefNum,                             // Parent directory/volume
464                        temp.parID,
465                        kAliasHavenFolderName,            // Name of the new folder
466                        sAliasHavenVRefNum,                // Volume of the created folder
467                        sAliasHavenDirID);               
468        }
469} // MacFileHelpers::EnsureAliasHaven
470
471//----------------------------------------------------------------------------------------
472PRBool MacFileHelpers::IsAliasSafe(const FSSpec& inSpec)
473// Returns true if the alias is in the alias haven directory, or if alias resolution
474// has been turned off.
475//----------------------------------------------------------------------------------------
476{
477        return sNoResolve
478                || (inSpec.parID == sAliasHavenDirID && inSpec.vRefNum == sAliasHavenVRefNum);
479} // MacFileHelpers::IsAliasSafe
480
481//----------------------------------------------------------------------------------------
482OSErr MacFileHelpers::ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased)
483//----------------------------------------------------------------------------------------
484{
485        wasAliased = false;
486        if (IsAliasSafe(inOutSpec))
487                return noErr;
488        Boolean dummy;   
489        return ::ResolveAliasFile(&inOutSpec, TRUE, &dummy, &wasAliased);
490} // MacFileHelpers::ResolveAliasFile
491
492//-----------------------------------
493OSErr MacFileHelpers::FSSpecFromUnixPath(
494        const char * unixPath,
495        FSSpec& ioSpec,
496        Boolean hexDecode,
497        Boolean resolveAlias,
498        Boolean allowPartial,
499        Boolean createDirs)
500// File spec from URL. Reverses GetURLFromFileSpec
501// Its input is only the <path> part of the URL
502// JRM 97/01/08 changed this so that if it's a partial path (doesn't start with '/'),
503// then it is combined with inOutSpec's vRefNum and parID to form a new spec.
504//-----------------------------------
505{
506        if (unixPath == nsnull)
507                return badFidErr;
508        char* macPath = MacPathFromUnixPath(unixPath, hexDecode);
509        if (!macPath)
510                return memFullErr;
511
512        OSErr err = noErr;
513        if (!allowPartial)
514        {
515                NS_ASSERTION(*unixPath == '/' /*full path*/, "Not a full Unix path!");
516        }
517        err = FSSpecFromPathname(macPath, ioSpec, createDirs);
518        if (err == fnfErr)
519                err = noErr;
520        Boolean dummy;   
521        if (err == noErr && resolveAlias)        // Added
522                err = MacFileHelpers::ResolveAliasFile(ioSpec, dummy);
523        delete [] macPath;
524        NS_ASSERTION(err==noErr||err==fnfErr||err==dirNFErr||err==nsvErr, "Not a path!");
525        return err;
526} // MacFileHelpers::FSSpecFromLocalUnixPath
527
528//-----------------------------------
529char* MacFileHelpers::PathNameFromFSSpec( const FSSpec& inSpec )
530// Returns a full pathname to the given file
531// Returned value is allocated with new [], and must be freed with delete []
532// For consistency and to work under OS X this creates an nsILocalFileMac and has it do the work.
533//-----------------------------------
534{
535        char* result = nil;
536        nsresult rv;
537
538    FSSpec nonConstSpec = inSpec;
539    nsCAutoString path;
540    nsCOMPtr<nsILocalFileMac> macFile;
541   
542    rv = NS_NewLocalFileWithFSSpec(&nonConstSpec, PR_TRUE, getter_AddRefs(macFile));
543    if (NS_FAILED(rv)) return nsnull;
544    nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(macFile, &rv));
545    if (NS_FAILED(rv)) return nsnull;
546    rv = localFile->GetNativePath(path);
547    if (NS_FAILED(rv)) return nsnull;
548    PRInt32 strLen = path.Length();
549    result = new char [strLen + 1];
550    if (!result) return nsnull;
551        memcpy(result, path.get(), strLen);
552        result[ strLen ] = 0;
553
554        return result;
555} // MacFileHelpers::PathNameFromFSSpec
556
557
558#pragma mark -
559
560//========================================================================================
561//                                        Macintosh nsFileSpec implementation
562//========================================================================================
563
564//----------------------------------------------------------------------------------------
565nsFileSpec::nsFileSpec()
566//----------------------------------------------------------------------------------------
567{
568//    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
569        Clear();
570}
571
572//----------------------------------------------------------------------------------------
573nsFileSpec::nsFileSpec(const FSSpec& inSpec, PRBool resolveAlias)
574//----------------------------------------------------------------------------------------
575: mSpec(inSpec)
576, mError(NS_OK)
577{
578//    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
579        if (resolveAlias)
580        {
581                PRBool dummy;
582                ResolveSymlink(dummy);
583        }
584}
585
586//----------------------------------------------------------------------------------------
587void nsFileSpec::operator = (const FSSpec& inSpec)
588//----------------------------------------------------------------------------------------
589{
590        mSpec = inSpec;
591        mError = NS_OK;
592}
593
594//----------------------------------------------------------------------------------------
595nsFileSpec::nsFileSpec(const nsFileSpec& inSpec)
596//----------------------------------------------------------------------------------------
597:        mSpec(inSpec.mSpec)
598,        mError(inSpec.Error())
599{
600//    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
601}
602
603//----------------------------------------------------------------------------------------
604nsFileSpec::nsFileSpec(const char* inNativePathString, PRBool inCreateDirs)
605//----------------------------------------------------------------------------------------
606{
607//  NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
608    Clear();            // this sets mError to NS_ERROR_NOT_INITIALIZED
609
610        if (inNativePathString)
611        {
612                mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname(
613                                  inNativePathString, mSpec, inCreateDirs));
614                if (mError == NS_FILE_RESULT(fnfErr))
615                        mError = NS_OK;
616        }
617
618} // nsFileSpec::nsFileSpec
619
620//----------------------------------------------------------------------------------------
621nsFileSpec::nsFileSpec(const nsString& inNativePathString, PRBool inCreateDirs)
622//----------------------------------------------------------------------------------------
623{
624//    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
625        Clear();                // this sets mError to NS_ERROR_NOT_INITIALIZED
626
627        mError = NS_FILE_RESULT(
628                MacFileHelpers::FSSpecFromPathname(
629                        NS_LossyConvertUCS2toASCII(inNativePathString).get(),
630                        mSpec, inCreateDirs));
631        if (mError == NS_FILE_RESULT(fnfErr))
632                mError = NS_OK;
633
634} // nsFileSpec::nsFileSpec
635
636//----------------------------------------------------------------------------------------
637nsFileSpec::nsFileSpec(short vRefNum, long parID, ConstStr255Param fileName,  PRBool resolveAlias)
638//----------------------------------------------------------------------------------------
639{
640//    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
641        mError = NS_FILE_RESULT(::FSMakeFSSpec(vRefNum, parID, fileName, &mSpec));
642        if (mError == NS_FILE_RESULT(fnfErr))
643                mError = NS_OK;
644 
645        if (resolveAlias)
646        {
647                PRBool dummy;
648                ResolveSymlink(dummy);
649        }
650}
651
652//----------------------------------------------------------------------------------------
653nsFileSpec::nsFileSpec(const nsFilePath& inPath)
654//----------------------------------------------------------------------------------------
655{
656//    NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
657        *this = inPath.GetFileSpec();
658}
659
660//----------------------------------------------------------------------------------------
661void nsFileSpec::operator = (const char* inString)
662//----------------------------------------------------------------------------------------
663{
664        Clear();                // this sets mError to NS_ERROR_NOT_INITIALIZED
665
666        if (inString)
667        {
668                mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname(inString, mSpec, true));
669                if (mError == NS_FILE_RESULT(fnfErr))
670                        mError = NS_OK;
671        }
672       
673} // nsFileSpec::operator =
674
675//----------------------------------------------------------------------------------------
676void nsFileSpec::operator = (const nsFileSpec& inSpec)
677//----------------------------------------------------------------------------------------
678{
679        mPath.SetToEmpty();
680        mSpec.vRefNum = inSpec.mSpec.vRefNum;
681        mSpec.parID = inSpec.mSpec.parID;
682
683        PRInt32 copySize = inSpec.mSpec.name[0] + 1;
684        if (copySize > sizeof(inSpec.mSpec.name))
685                copySize = sizeof(inSpec.mSpec.name);
686        memcpy(mSpec.name, inSpec.mSpec.name, copySize);
687        mError = inSpec.Error();        // note that the error is propagated
688} // nsFileSpec::operator =
689
690//----------------------------------------------------------------------------------------
691void nsFileSpec::operator = (const nsFilePath& inPath)
692//----------------------------------------------------------------------------------------
693{
694        *this = inPath.GetFileSpec();
695} // nsFileSpec::operator =
696
697//----------------------------------------------------------------------------------------
698inline void nsFileSpec::Clear()
699//----------------------------------------------------------------------------------------
700{
701        mPath.SetToEmpty();
702        mSpec.vRefNum = 0;
703        mSpec.parID = 0;
704        mSpec.name[0] = 0;
705        mError = NS_ERROR_NOT_INITIALIZED;
706}
707
708//----------------------------------------------------------------------------------------
709PRBool nsFileSpec::Exists() const
710//----------------------------------------------------------------------------------------
711{
712  if (NS_FAILED(mError)) return PR_FALSE;
713        FSSpec temp;
714        return ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &temp) == noErr;
715} // nsFileSpec::Exists()
716
717//----------------------------------------------------------------------------------------
718void nsFileSpec::GetModDate(TimeStamp& outStamp) const
719//----------------------------------------------------------------------------------------
720{
721        CInfoPBRec pb;
722        if (GetCatInfo(pb) == noErr)
723                outStamp = ((DirInfo*)&pb)->ioDrMdDat; // The mod date is in the same spot for files and dirs.
724        else
725                outStamp = 0;
726} // nsFileSpec::GetModDate
727
728//----------------------------------------------------------------------------------------
729PRUint32 nsFileSpec::GetFileSize() const
730//----------------------------------------------------------------------------------------
731{
732        CInfoPBRec pb;
733        if (noErr == GetCatInfo(pb))
734                return (PRUint32)((HFileInfo*)&pb)->ioFlLgLen;
735        return 0;
736} // nsFileSpec::GetFileSize
737
738//----------------------------------------------------------------------------------------
739void nsFileSpec::SetLeafName(const char* inLeafName)
740// In leaf name can actually be a partial path...
741//----------------------------------------------------------------------------------------
742{
743        NS_ASSERTION(inLeafName, "Attempt to set leaf name with a null string");
744       
745        mPath.SetToEmpty();
746
747        if (inLeafName)
748        {
749                // what about long relative paths?      Hmm?  We don't have a routine for this anywhere.
750                Str255 partialPath;
751                MacFileHelpers::PLstrcpy(partialPath, inLeafName);
752                mError = NS_FILE_RESULT(
753                        ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, partialPath, &mSpec));
754                if (mError == NS_FILE_RESULT(fnfErr))
755                        mError = NS_OK;
756        }
757       
758} // nsFileSpec::SetLeafName
759
760//----------------------------------------------------------------------------------------
761char* nsFileSpec::GetLeafName() const
762// Result needs to be nsCRT::free()ed.
763//----------------------------------------------------------------------------------------
764{
765        char leaf[sizeof(mSpec.name)];
766        memcpy(leaf, &mSpec.name[1], mSpec.name[0]);
767        leaf[mSpec.name[0]] = '\0';
768        return nsCRT::strdup(leaf);
769} // nsFileSpec::GetLeafName
770
771//----------------------------------------------------------------------------------------
772void nsFileSpec::MakeAliasSafe()
773//----------------------------------------------------------------------------------------
774{
775        mPath.SetToEmpty();
776        mError = NS_FILE_RESULT(MacFileHelpers::MakeAliasSafe(mSpec));
777} // nsFileSpec::MakeAliasSafe
778
779//----------------------------------------------------------------------------------------
780void nsFileSpec::MakeUnique(ConstStr255Param inSuggestedLeafName)
781//----------------------------------------------------------------------------------------
782{
783        mPath.SetToEmpty();
784        if (inSuggestedLeafName[0] > 0)
785                MacFileHelpers::PLstrcpy(mSpec.name, inSuggestedLeafName);
786
787        MakeUnique();
788} // nsFileSpec::MakeUnique
789
790//----------------------------------------------------------------------------------------
791PRBool nsFileSpec::IsFile() const
792//----------------------------------------------------------------------------------------
793{
794        long dirID;
795        Boolean isDirectory;
796        return (noErr == ::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && !isDirectory);
797} // nsFileSpec::IsFile
798
799//----------------------------------------------------------------------------------------
800PRBool nsFileSpec::IsDirectory() const
801//----------------------------------------------------------------------------------------
802{
803        long dirID;
804        Boolean isDirectory;
805        return (noErr == ::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && isDirectory);
806} // nsFileSpec::IsDirectory
807
808//----------------------------------------------------------------------------------------
809PRBool nsFileSpec::IsHidden() const
810//----------------------------------------------------------------------------------------
811{
812        CInfoPBRec              cInfo;
813        PRBool                  hidden = PR_FALSE;
814
815        if (noErr == GetCatInfo(cInfo))
816                if (cInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible)
817                        hidden = PR_TRUE;
818       
819        return hidden;
820} // nsFileSpec::IsHidden
821
822//----------------------------------------------------------------------------------------
823PRBool nsFileSpec::IsSymlink() const
824//----------------------------------------------------------------------------------------
825{
826        CInfoPBRec              cInfo;
827        PRBool                  hidden = PR_FALSE;
828
829        if (noErr == GetCatInfo(cInfo))
830                if (cInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias)
831                        hidden = PR_TRUE;
832       
833        return hidden;
834} // nsFileSpec::IsSymlink
835
836//----------------------------------------------------------------------------------------
837nsresult nsFileSpec::ResolveSymlink(PRBool& wasAliased)
838//----------------------------------------------------------------------------------------
839{
840        Boolean wasAliased2; // Type conversion Boolean <--> PRBool
841        OSErr err = MacFileHelpers::ResolveAliasFile(mSpec, wasAliased2);
842        if (wasAliased2)
843        {
844                mError = NS_FILE_RESULT(err);
845                wasAliased = PR_TRUE;
846        }
847        else
848                wasAliased = PR_FALSE;
849
850        return mError;
851} // nsFileSpec::ResolveSymlink
852
853//----------------------------------------------------------------------------------------
854void nsFileSpec::GetParent(nsFileSpec& outSpec) const
855//----------------------------------------------------------------------------------------
856{
857        if (NS_SUCCEEDED(mError))
858                outSpec.mError = NS_FILE_RESULT(::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, nsnull, outSpec));
859} // nsFileSpec::GetParent
860
861//----------------------------------------------------------------------------------------
862void nsFileSpec::operator += (const char* inRelativePath)
863//----------------------------------------------------------------------------------------
864{
865        NS_ASSERTION(inRelativePath, "Attempt to append relative path with null path");
866
867        // Invalidate the path cache string, since we're changing ourselves.
868        mPath.SetToEmpty();
869
870        // if we are already bad, don't allow appendage
871        if (NS_FAILED(Error()))
872        {
873          NS_WARNING("trying to append to a bad nsFileSpec");
874          return;
875        }
876       
877        // Find the dirID of the directory described by this spec
878        long dirID;
879        Boolean isDirectory;
880        mError = NS_FILE_RESULT(::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory));
881        if (NS_FAILED(mError) || !isDirectory || !inRelativePath)
882                return;
883   // mSpec.vRefNum is already correct.
884        mSpec.parID = dirID;
885
886        // Next, determine if it is a UNIX or Mac style path. Now, Macintosh relative paths
887        // are either leaf names (in which the distinction between unix and macintosh
888        // relative paths disappears) or they start with a colon. If we find an initial colon,
889        // then assume it's a macintosh path.
890        // If it is a UNIX path (including just a leaf name), we will also look for ':' and
891        // assert if we find one.
892        if (*inRelativePath != ':')
893        {
894                // Looks like a UNIX path (including possibly just a leaf name)
895                NS_ASSERTION(strchr(inRelativePath, ':') == nsnull, "Can not determine path type");
896           // Convert unix path (which is unencoded) to a spec
897                mError = NS_FILE_RESULT(
898                        MacFileHelpers::FSSpecFromUnixPath(inRelativePath, mSpec, false, false, true, true));
899        }
900        else
901        {
902                // We must be a mac path!                               
903                mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname(inRelativePath, mSpec, true));
904        }
905        if (mError == NS_FILE_RESULT(fnfErr))
906                mError = NS_OK;
907       
908} // nsFileSpec::operator +=
909
910//----------------------------------------------------------------------------------------
911void nsFileSpec::CreateDirectory(int /* unix mode */)
912//----------------------------------------------------------------------------------------
913{
914        long ignoredDirID;
915        OSErr   err = ::FSpDirCreate(&mSpec, smCurrentScript, &ignoredDirID);
916        // it's OK if the dir already exists
917        if (err != noErr && IsDirectory())
918                err = noErr;
919               
920        mError = NS_FILE_RESULT(err);
921       
922} // nsFileSpec::CreateDirectory
923
924//----------------------------------------------------------------------------------------
925void nsFileSpec::Delete(PRBool inRecursive) const
926//----------------------------------------------------------------------------------------
927{
928        OSErr anErr;
929
930        nsresult& mutableError = const_cast<nsFileSpec*>(this)->mError;
931        if (inRecursive)
932        {
933                // MoreFilesExtras
934                anErr = ::DeleteDirectory(
935                                        mSpec.vRefNum,
936                                        mSpec.parID,
937                                        const_cast<unsigned char*>(mSpec.name));
938        }
939        else
940                anErr = ::FSpDelete(&mSpec);
941       
942        if (anErr == fnfErr) // deleting a file that doesn't exist isn't an error!
943                anErr = noErr;
944       
945        mutableError = NS_FILE_RESULT(anErr);
946   
947} // nsFileSpec::Delete
948
949//----------------------------------------------------------------------------------------
950void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const
951//----------------------------------------------------------------------------------------
952{
953        if (IsDirectory())
954        {
955                if (!(newDir.Exists()))
956                {
957                        newDir.CreateDirectory();
958                }
959
960                for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++)
961                {
962                        nsFileSpec& child = (nsFileSpec&)i;
963
964                        if (child.IsDirectory())
965                        {
966                                nsFileSpec tmpDirSpec(newDir);
967
968                                char *leafname = child.GetLeafName();
969                                tmpDirSpec += leafname;
970                                nsCRT::free(leafname);
971
972                                child.RecursiveCopy(tmpDirSpec);
973                        }
974                        else
975                        {
976                                child.RecursiveCopy(newDir);
977                        }
978                }
979        }
980        else
981        {
982                nsFileSpec& filePath = (nsFileSpec&) *this;
983
984                if (!(newDir.Exists()))
985                {
986                        newDir.CreateDirectory();
987                }
988
989                filePath.CopyToDir(newDir);
990        }
991} // nsFileSpec::RecursiveCopy
992
993//----------------------------------------------------------------------------------------
994nsresult nsFileSpec::Truncate(PRInt32 aNewLength) const
995//----------------------------------------------------------------------------------------
996{
997    short   refNum;
998    OSErr   err;
999       
1000    // First see if we have an internal error set
1001    if (NS_FAILED(mError))
1002        return mError;
1003       
1004    // Need to open the file to trunc
1005    if (::FSpOpenDF(&mSpec, fsWrPerm, &refNum) != noErr)
1006        return NS_FILE_FAILURE;
1007
1008    err = ::SetEOF(refNum, aNewLength);
1009       
1010    // Close the file unless we got an error that it was already closed
1011    if (err != fnOpnErr)
1012        (void)::FSClose(refNum);
1013       
1014    if (err != noErr)
1015        return NS_FILE_FAILURE;
1016       
1017    return NS_OK;
1018} // nsFileSpec::Truncate
1019
1020//----------------------------------------------------------------------------------------
1021nsresult nsFileSpec::Rename(const char* inNewName)
1022//----------------------------------------------------------------------------------------
1023{
1024        NS_ASSERTION(inNewName, "Attempt to rename with null new name");
1025
1026        if (strchr(inNewName, '/'))
1027                return NS_FILE_FAILURE; // no relative paths here!
1028       
1029        Str255 pName;
1030        MacFileHelpers::PLstrcpy(pName, inNewName);
1031        if (::FSpRename(&mSpec, pName) != noErr)
1032                return NS_FILE_FAILURE;
1033        SetLeafName(inNewName);
1034        return NS_OK;
1035} // nsFileSpec::Rename
1036
1037//----------------------------------------------------------------------------------------
1038nsresult nsFileSpec::CopyToDir(const nsFileSpec& newParentDir) const
1039//----------------------------------------------------------------------------------------
1040{
1041        // We can only copy into a directory, and (for now) can not copy entire directories
1042
1043        if (!newParentDir.IsDirectory() || (IsDirectory() ) )
1044                return NS_FILE_FAILURE;
1045       
1046        nsresult rv = NS_FILE_RESULT(::FSpFileCopy(&mSpec,
1047                                                        &newParentDir.mSpec,
1048                                                        const_cast<StringPtr>(GetLeafPName()),
1049                                                        nsnull,
1050                                                        0,
1051                                                        true));
1052
1053        return rv;
1054
1055} // nsFileSpec::CopyToDir
1056
1057//----------------------------------------------------------------------------------------
1058nsresult nsFileSpec::MoveToDir(const nsFileSpec& newParentDir)
1059//----------------------------------------------------------------------------------------
1060{
1061        // We can only move into a directory
1062       
1063        if (!newParentDir.IsDirectory())
1064                return NS_FILE_FAILURE;
1065 
1066        nsresult result = NS_FILE_RESULT(::FSpMoveRenameCompat(&mSpec,
1067                                                                        &newParentDir.mSpec,
1068                                                                        const_cast<StringPtr>(GetLeafPName())));
1069
1070        if ( NS_SUCCEEDED(result) )
1071        {
1072                char* leafName = GetLeafName();
1073                *this = newParentDir + leafName;
1074                nsCRT::free(leafName);
1075        }
1076        return result;
1077} // nsFileSpec::MoveToDir
1078
1079//----------------------------------------------------------------------------------------
1080nsresult nsFileSpec::Execute(const char* /*args - how can this be cross-platform?  problem! */ ) const
1081//----------------------------------------------------------------------------------------
1082{
1083        if (IsDirectory())
1084                return NS_FILE_FAILURE;
1085
1086        LaunchParamBlockRec launchThis;
1087        launchThis.launchAppSpec = const_cast<FSSpec*>(&mSpec);
1088        launchThis.launchAppParameters = nsnull; // args;
1089        /* launch the thing */
1090        launchThis.launchBlockID        = extendedBlock;
1091        launchThis.launchEPBLength      = extendedBlockLen;
1092        launchThis.launchFileFlags      = nsnull;
1093        launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum;
1094        launchThis.launchControlFlags += launchDontSwitch;
1095
1096        nsresult result = NS_FILE_RESULT(::LaunchApplication(&launchThis));
1097        return result;
1098 
1099} // nsFileSpec::Execute
1100
1101//----------------------------------------------------------------------------------------
1102OSErr nsFileSpec::GetCatInfo(CInfoPBRec& outInfo) const
1103//----------------------------------------------------------------------------------------
1104{
1105        DirInfo    *dipb=(DirInfo *)&outInfo;
1106        dipb->ioCompletion = nsnull;
1107        dipb->ioFDirIndex = 0; // use dirID and name
1108        dipb->ioVRefNum = mSpec.vRefNum;
1109        dipb->ioDrDirID = mSpec.parID;
1110        dipb->ioNamePtr = const_cast<nsFileSpec*>(this)->mSpec.name;
1111        return PBGetCatInfoSync(&outInfo);
1112} // nsFileSpec::GetCatInfo()
1113
1114//----------------------------------------------------------------------------------------
1115OSErr nsFileSpec::SetFileTypeAndCreator(OSType type, OSType creator)
1116//----------------------------------------------------------------------------------------
1117{
1118        FInfo info;
1119        OSErr err = ::FSpGetFInfo(&mSpec, &info);
1120        if (err != noErr)
1121                return err;
1122        info.fdType = type;
1123        info.fdCreator = creator;
1124        err = ::FSpSetFInfo(&mSpec, &info);
1125        return err;
1126}
1127
1128//----------------------------------------------------------------------------------------
1129OSErr nsFileSpec::GetFileTypeAndCreator(OSType* type, OSType* creator)
1130//----------------------------------------------------------------------------------------
1131{
1132        FInfo info;
1133        OSErr err = ::FSpGetFInfo(&mSpec, &info);
1134        if (err != noErr)
1135                return err;
1136        *type = info.fdType;
1137        *creator = info.fdCreator;     
1138        return noErr;
1139}
1140
1141//----------------------------------------------------------------------------------------
1142PRInt64 nsFileSpec::GetDiskSpaceAvailable() const
1143//----------------------------------------------------------------------------------------
1144{
1145        PRInt64 space64Bits;
1146
1147        LL_I2L(space64Bits , LONG_MAX);
1148
1149        XVolumeParam    pb;
1150        pb.ioCompletion = nsnull;
1151        pb.ioVolIndex = 0;
1152        pb.ioNamePtr = nsnull;
1153        pb.ioVRefNum = mSpec.vRefNum;
1154       
1155        // PBXGetVolInfoSync works on HFS+ volumes too!
1156        OSErr err = ::PBXGetVolInfoSync(&pb);
1157       
1158        if (err == noErr)
1159        {
1160#ifdef HAVE_LONG_LONG
1161                space64Bits = pb.ioVFreeBytes;
1162#else
1163                const UnsignedWide& freeBytes = UInt64ToUnsignedWide(pb.ioVFreeBytes);
1164                space64Bits.lo = freeBytes.lo;
1165                space64Bits.hi = freeBytes.hi;
1166#endif
1167        }
1168               
1169        return space64Bits;
1170} // nsFileSpec::GetDiskSpace()
1171
1172//----------------------------------------------------------------------------------------
1173const char* nsFileSpec::GetCString() const
1174// This is the only conversion to const char* that is provided, and it allows the
1175// path to be "passed" to NSPR file routines.  This practice is VERY EVIL and should only
1176// be used to support legacy code.      Using it guarantees bugs on Macintosh. The string is
1177// cached and freed by the nsFileSpec destructor, so do not delete (or free) it.
1178//----------------------------------------------------------------------------------------
1179{
1180        if (mPath.IsEmpty())
1181        {
1182                char* path = MacFileHelpers::PathNameFromFSSpec(mSpec);
1183                if (path != NULL) {
1184                        const_cast<nsFileSpec*>(this)->mPath = path;    // operator =() copies the string!!!
1185                        delete[] path;
1186                } else {
1187                        const_cast<nsFileSpec*>(this)->mError = NS_ERROR_OUT_OF_MEMORY;
1188                }
1189        }
1190        return mPath;
1191}
1192
1193#pragma mark -
1194
1195//========================================================================================
1196//                                        Macintosh nsFilePath implementation
1197//========================================================================================
1198
1199//----------------------------------------------------------------------------------------
1200static void AssignFromPath(nsFilePath& ioPath, const char* inString, PRBool inCreateDirs)
1201//----------------------------------------------------------------------------------------
1202{
1203        NS_ASSERTION(inString, "AssignFromPath called with null inString");
1204        NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path");
1205
1206        FSSpec spec;
1207        spec.vRefNum = 0;
1208        spec.parID = 0;
1209        spec.name[0] = 0;
1210        MacFileHelpers::FSSpecFromUnixPath(
1211                inString,
1212                spec,
1213                false,
1214                true, // resolve alias
1215                true,
1216                inCreateDirs);
1217        // Now we have a spec,
1218        // Invoke operator = (const nsFileSpec&) to do the rest.
1219        // Why didn't we just say mPath = inString to get the path? Well, we want it to be
1220        // canonical and absolute.
1221        ioPath = spec;
1222}
1223
1224//----------------------------------------------------------------------------------------
1225nsFilePath::nsFilePath(const char* inString, PRBool inCreateDirs)
1226//----------------------------------------------------------------------------------------
1227{
1228        AssignFromPath(*this, inString, inCreateDirs);
1229} //nsFilePath::nsFilePath
1230
1231//----------------------------------------------------------------------------------------
1232nsFilePath::nsFilePath(const nsString& inString, PRBool inCreateDirs)
1233//----------------------------------------------------------------------------------------
1234{
1235        AssignFromPath(*this, NS_LossyConvertUCS2toASCII(inString).get(),
1236                       inCreateDirs);
1237}
1238
1239//----------------------------------------------------------------------------------------
1240void nsFilePath::operator = (const char* inString)
1241//----------------------------------------------------------------------------------------
1242{
1243        AssignFromPath(*this, inString, PR_FALSE);
1244}
1245
1246//----------------------------------------------------------------------------------------
1247nsFilePath::nsFilePath(const nsFileSpec& inSpec)
1248//----------------------------------------------------------------------------------------
1249{
1250        *this = inSpec;
1251}
1252
1253//----------------------------------------------------------------------------------------
1254nsFilePath::nsFilePath(const nsFileURL& inOther)
1255//----------------------------------------------------------------------------------------
1256{
1257        *this = inOther;
1258}
1259
1260//----------------------------------------------------------------------------------------
1261void nsFilePath::operator = (const nsFileSpec& inSpec)
1262//----------------------------------------------------------------------------------------
1263{
1264        char * path = MacFileHelpers::PathNameFromFSSpec(inSpec);
1265        path = MacFileHelpers::EncodeMacPath(path, true, false);
1266        mPath = path;
1267        nsCRT::free(path);
1268        mFileSpec = inSpec;
1269} // nsFilePath::operator =
1270
1271//----------------------------------------------------------------------------------------
1272void nsFilePath::operator = (const nsFileURL& inOther)
1273//----------------------------------------------------------------------------------------
1274{
1275        char * path = MacFileHelpers::PathNameFromFSSpec(inOther.mFileSpec);
1276        path = MacFileHelpers::EncodeMacPath(path, true, false);
1277        mPath = path;
1278        nsCRT::free(path);
1279        mFileSpec = inOther.GetFileSpec();
1280}
1281
1282#pragma mark -
1283
1284//========================================================================================
1285//                                                                nsFileURL implementation
1286//========================================================================================
1287
1288//----------------------------------------------------------------------------------------
1289nsFileURL::nsFileURL(const char* inString, PRBool inCreateDirs)
1290//----------------------------------------------------------------------------------------
1291:        mURL(inString)
1292{       
1293        NS_ASSERTION(inString, "nsFileURL constructed with null inString");
1294        NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!");
1295        mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath(
1296                inString + kFileURLPrefixLength,
1297                mFileSpec.mSpec,
1298                true, // need to decode
1299                false, // resolve alias
1300                false, // must be a full path
1301                inCreateDirs));
1302        if (mFileSpec.mError == NS_FILE_RESULT(fnfErr))
1303                mFileSpec.mError = NS_OK;
1304} // nsFileURL::nsFileURL
1305
1306//----------------------------------------------------------------------------------------
1307nsFileURL::nsFileURL(const nsString& inString, PRBool inCreateDirs)
1308//----------------------------------------------------------------------------------------
1309:        mURL(nsnull)
1310{
1311        NS_LossyConvertUCS2toASCII cstring(inString);
1312        mURL = cstring.get();
1313        NS_ASSERTION(strstr(cstring.get(), kFileURLPrefix) == cstring.get(),
1314                     "Not a URL!");
1315        mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath(
1316                cstring.get() + kFileURLPrefixLength,
1317                mFileSpec.mSpec,
1318                true, // need to decode
1319                false, // resolve alias
1320                false, // must be a full path
1321                inCreateDirs));
1322        if (mFileSpec.mError == NS_FILE_RESULT(fnfErr))
1323                mFileSpec.mError = NS_OK;
1324} // nsFileURL::nsFileURL
1325
1326//----------------------------------------------------------------------------------------
1327nsFileURL::nsFileURL(const nsFilePath& inOther)
1328//----------------------------------------------------------------------------------------
1329{
1330        *this = inOther.GetFileSpec();
1331} // nsFileURL::nsFileURL
1332
1333//----------------------------------------------------------------------------------------
1334nsFileURL::nsFileURL(const nsFileSpec& inOther)
1335//----------------------------------------------------------------------------------------
1336{
1337        *this = inOther;
1338} // nsFileURL::nsFileURL
1339
1340//----------------------------------------------------------------------------------------
1341void nsFileURL::operator = (const nsFilePath& inOther)
1342//----------------------------------------------------------------------------------------
1343{
1344        *this = inOther.GetFileSpec();
1345} // nsFileURL::operator =
1346
1347//----------------------------------------------------------------------------------------
1348void nsFileURL::operator = (const nsFileSpec& inOther)
1349//----------------------------------------------------------------------------------------
1350{
1351        mFileSpec  = inOther;
1352        char* path = MacFileHelpers::PathNameFromFSSpec( mFileSpec );
1353        char* encodedPath = MacFileHelpers::EncodeMacPath(path, true, true);
1354        nsSimpleCharString encodedURL(kFileURLPrefix);
1355        encodedURL += encodedPath;
1356        nsCRT::free(encodedPath);
1357        mURL = encodedURL;
1358        if (encodedURL[encodedURL.Length() - 1] != '/' && inOther.IsDirectory())
1359                mURL += "/";
1360} // nsFileURL::operator =
1361
1362//----------------------------------------------------------------------------------------
1363void nsFileURL::operator = (const char* inString)
1364//----------------------------------------------------------------------------------------
1365{
1366        NS_ASSERTION(inString, "nsFileURL operator= constructed with null inString");
1367
1368        mURL = inString;
1369        NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!");
1370        mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath(
1371                inString + kFileURLPrefixLength,
1372                mFileSpec.mSpec,
1373                true, // need to decode
1374                true, // resolve alias
1375                false, // must be a full path
1376                false)); // don't create dirs.
1377        if (mFileSpec.mError == NS_FILE_RESULT(fnfErr))
1378                mFileSpec.mError = NS_OK;
1379} // nsFileURL::operator =
1380
1381#pragma mark -
1382
1383//========================================================================================
1384//                                                                nsDirectoryIterator
1385//========================================================================================
1386
1387//----------------------------------------------------------------------------------------
1388nsDirectoryIterator::nsDirectoryIterator(
1389        const nsFileSpec& inDirectory
1390,       PRBool resolveSymLinks)
1391//----------------------------------------------------------------------------------------
1392        : mCurrent(inDirectory)
1393        , mExists(false)
1394        , mResoveSymLinks(resolveSymLinks)
1395        , mIndex(-1)
1396{
1397        CInfoPBRec pb;
1398        OSErr err = inDirectory.GetCatInfo(pb);
1399       
1400        // test that we have got a directory back, not a file
1401        DirInfo* dipb = (DirInfo*)&pb;
1402        if (err != noErr  || !( dipb->ioFlAttrib & 0x0010))
1403                return;
1404        // Sorry about this, there seems to be a bug in CWPro 4:
1405        FSSpec& currentSpec = mCurrent.nsFileSpec::operator FSSpec&();
1406        mVRefNum = currentSpec.vRefNum;
1407        mParID = dipb->ioDrDirID;
1408        mMaxIndex = pb.dirInfo.ioDrNmFls;
1409        mIndex = 0; // ready to increment
1410        ++(*this); // the pre-increment operator
1411       
1412} // nsDirectoryIterator::nsDirectoryIterator
1413
1414//----------------------------------------------------------------------------------------
1415OSErr nsDirectoryIterator::SetToIndex()
1416//----------------------------------------------------------------------------------------
1417{
1418        CInfoPBRec cipb;
1419        DirInfo    *dipb=(DirInfo *)&cipb;
1420        Str255 objectName;
1421        dipb->ioCompletion = nsnull;
1422        dipb->ioFDirIndex = mIndex;
1423        // Sorry about this, there seems to be a bug in CWPro 4:
1424        FSSpec& currentSpec = mCurrent.nsFileSpec::operator FSSpec&();
1425        dipb->ioVRefNum = mVRefNum; /* Might need to use vRefNum, not sure*/
1426        dipb->ioDrDirID = mParID;
1427        dipb->ioNamePtr = objectName;
1428        OSErr err = PBGetCatInfoSync(&cipb);
1429        FSSpec temp;
1430        if (err == noErr)
1431                err = FSMakeFSSpec(mVRefNum, mParID, objectName, &temp);
1432        mCurrent = temp; // use the operator: it clears the string cache.
1433        mExists = err == noErr;
1434
1435        if (mExists && mResoveSymLinks)
1436        {       
1437                PRBool ignore;
1438                mCurrent.ResolveSymlink(ignore);
1439        }
1440        return err;
1441} // nsDirectoryIterator::SetToIndex()
1442
1443//----------------------------------------------------------------------------------------
1444nsDirectoryIterator& nsDirectoryIterator::operator -- ()
1445//----------------------------------------------------------------------------------------
1446{
1447        mExists = false;
1448        while (--mIndex > 0)
1449        {
1450                OSErr err = SetToIndex();
1451                if (err == noErr)
1452                        break;
1453        }
1454        return *this;
1455} // nsDirectoryIterator::operator --
1456
1457//----------------------------------------------------------------------------------------
1458nsDirectoryIterator& nsDirectoryIterator::operator ++ ()
1459//----------------------------------------------------------------------------------------
1460{
1461        mExists = false;
1462        if (mIndex >= 0) // probably trying to use a file as a directory!
1463                while (++mIndex <= mMaxIndex)
1464                {
1465                        OSErr err = SetToIndex();
1466                        if (err == noErr)
1467                                break;
1468                }
1469        return *this;
1470} // nsDirectoryIterator::operator ++
1471
Note: See TracBrowser for help on using the repository browser.