diff --git a/mozilla/base/src/mac/nsFileSpecMac.cpp b/mozilla/base/src/mac/nsFileSpecMac.cpp new file mode 100644 index 00000000000..b2a5930b0ee --- /dev/null +++ b/mozilla/base/src/mac/nsFileSpecMac.cpp @@ -0,0 +1,571 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +// This file is included by nsFile.cp, and includes the Macintosh-specific +// implementations. + +#include "FullPath.h" +#include "FileCopy.h" +#include "nsEscape.h" + +#include +#include +#include +#include +#include + +const unsigned char* kAliasHavenFolderName = "\pnsAliasHaven"; + +//======================================================================================== +namespace MacFileHelpers +//======================================================================================== +{ + void SwapSlashColon(char * s); + OSErr FSSpecFromFullUnixPath( + const char * unixPath, + FSSpec& outSpec, + Boolean resolveAlias); + char* MacPathFromUnixPath(const char* unixPath); + char* EncodeMacPath( + char* inPath, // NOT const - gets clobbered + Boolean prependSlash, + Boolean doEscape ); + OSErr FSSpecFromPathname( + const char* inPathNamePtr, + FSSpec& outSpec); + char* PathNameFromFSSpec( + const FSSpec& inSpec, + Boolean wantLeafName ); + OSErr CreateFolderInFolder( + short refNum, // Parent directory/volume + long dirID, + ConstStr255Param folderName, // Name of the new folder + short& outRefNum, // Volume of the created folder + long& outDirID); // + + // Some routines to support an "alias haven" directory. Aliases in this directory + // are never resolved. There is a ResolveAlias here that respects that. This is + // to support attaching of aliases in mail. + void EnsureAliasHaven(); + void SetNoResolve(Boolean inResolve); + Boolean IsAliasSafe(const FSSpec& inSpec); + OSErr MakeAliasSafe(FSSpec& inOutSpec); + OSErr ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased); + + Boolean sNoResolve = false; + long sAliasHavenDirID = 0; + short sAliasHavenVRefNum = 0; +} // namespace MacFileHelpers + +//----------------------------------- +void MacFileHelpers::SwapSlashColon(char * s) +//----------------------------------- + +{ + while ( *s != 0) + { + if (*s == '/') + *s++ = ':'; + else if (*s == ':') + *s++ = '/'; + else + *s++; + } +} // MacFileHelpers::SwapSlashColon + +//----------------------------------- +char* MacFileHelpers::EncodeMacPath( + char* inPath, // NOT const, gets clobbered + Boolean prependSlash, + Boolean doEscape ) +// Transforms Macintosh style path into Unix one +// Method: Swap ':' and '/', hex escape the result +//----------------------------------- +{ + if (inPath == NULL) + return NULL; + int pathSize = strlen(inPath); + + // XP code sometimes chokes if there's a final slash in the unix path. + // Since correct mac paths to folders and volumes will end in ':', strip this + // first. + char* c = inPath + pathSize - 1; + if (*c == ':') + { + *c = 0; + pathSize--; + } + + char * newPath = NULL; + char * finalPath = NULL; + + if (prependSlash) + { + newPath = new char[pathSize + 2]; + newPath[0] = ':'; // It will be converted to '/' + memcpy(&newPath[1], inPath, pathSize + 1); + } + else + { + newPath = new char[pathSize + 1]; + strcpy(newPath, inPath); + } + if (newPath) + { + SwapSlashColon( newPath ); + if (doEscape) + { + finalPath = nsEscape(newPath, url_Path); + delete [] newPath; + } + else + finalPath = newPath; + } + delete [] inPath; + return finalPath; +} // MacFileHelpers::EncodeMacPath + +//---------------------------------------------------------------------------------------- +inline void MacFileHelpers::SetNoResolve(Boolean inResolve) +//---------------------------------------------------------------------------------------- +{ + sNoResolve = inResolve; +} // MacFileHelpers::SetNoResolve + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::MakeAliasSafe(FSSpec& inOutSpec) +// Pass in the spec of an alias. This copies the file to the safe haven folder, and +// returns the spec of the copy to the caller +//---------------------------------------------------------------------------------------- +{ + EnsureAliasHaven(); + nsNativeFileSpec dstDirSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\p"); + + // Make sure its name is unique + nsNativeFileSpec havenSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\pG'day"); + if (havenSpec.Valid()) + havenSpec.MakeUnique(inOutSpec.name); + // Copy the file into the haven directory + if (havenSpec.Valid()) + { + OSErr err = ::FSpFileCopy( + &inOutSpec, + dstDirSpec, + havenSpec.GetLeafPName(), + nil, 0, true); + // Return the spec of the copy to the caller. + if (err != noErr) + return err; + inOutSpec = havenSpec; + } + return noErr; +} // MacFileHelpers::MakeAliasSafe + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::MakeUnique(ConstStr255Param inSuggestedLeafName) +//---------------------------------------------------------------------------------------- +{ + if (inSuggestedLeafName[0] > 0) + PLstrcpy(mSpec.name, inSuggestedLeafName); + + MakeUnique(); +} + +//---------------------------------------------------------------------------------------- +char* MacFileHelpers::MacPathFromUnixPath(const char* unixPath) +//---------------------------------------------------------------------------------------- +{ + // Relying on the fact that the unix path is always longer than the mac path: + size_t len = strlen(unixPath); + char* result = new char[len + 2]; // ... but allow for the initial colon in a partial name + if (result) + { + char* dst = result; + const char* src = unixPath; + if (*src == '/') // ¥ full path + src++; + else if (strchr(src, '/')) // ¥ partial path, and not just a leaf name + *dst++ = ':'; + strcpy(dst, src); + nsUnescape(dst); // Hex Decode + MacFileHelpers::SwapSlashColon(dst); + } + return result; +} // MacFileHelpers::MacPathFromUnixPath + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::FSSpecFromPathname(const char* inPathNamePtr, FSSpec& outSpec) +// FSSpecFromPathname reverses PathNameFromFSSpec. +// It returns a FSSpec given a c string which is a mac pathname. +//---------------------------------------------------------------------------------------- +{ + OSErr err; + // Simplify this routine to use FSMakeFSSpec if length < 255. Otherwise use the MoreFiles + // routine FSpLocationFromFullPath, which allocates memory, to handle longer pathnames. + if (strlen(inPathNamePtr) < 255) + { + Str255 path; + + int pos = 0; + while ( (path[++pos] = *inPathNamePtr++) != 0 ) + ; + path[0] = pos-1; // save the length of the string (pos is the next open spot) + + err = ::FSMakeFSSpec(0, 0, path, &outSpec); + } + else + err = FSpLocationFromFullPath(strlen(inPathNamePtr), inPathNamePtr, &outSpec); + + return err; +} + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::CreateFolderInFolder( + short refNum, // Parent directory/volume + long dirID, + ConstStr255Param folderName, // Name of the new folder + short& outRefNum, // Volume of the created folder + long& outDirID) // +// Creates a folder named 'folderName' inside a folder. +// The errors returned are same as PBDirCreate +//---------------------------------------------------------------------------------------- +{ + HFileParam hpb; + hpb.ioVRefNum = refNum; + hpb.ioDirID = dirID; + hpb.ioNamePtr = (StringPtr)&folderName; + + OSErr err = PBDirCreateSync((HParmBlkPtr)&hpb); + if (err == noErr) + { + outRefNum = hpb.ioVRefNum; + outDirID = hpb.ioDirID; + } + else + { + outRefNum = 0; + outDirID = 0; + } + return err; +} // MacFileHelpers::CreateFolderInFolder + +//---------------------------------------------------------------------------------------- +void MacFileHelpers::EnsureAliasHaven() +//---------------------------------------------------------------------------------------- +{ + // Alias Haven is a directory in which we never resolve aliases. + if (sAliasHavenVRefNum != 0) + return; + + + FSSpec temp; + if (FindFolder(0, kTemporaryFolderType, true, & temp.vRefNum, &temp.parID) == noErr) + { + CreateFolderInFolder( + temp.vRefNum, // Parent directory/volume + temp.parID, + kAliasHavenFolderName, // Name of the new folder + sAliasHavenVRefNum, // Volume of the created folder + sAliasHavenDirID); + } +} // MacFileHelpers::EnsureAliasHaven + +//---------------------------------------------------------------------------------------- +Boolean MacFileHelpers::IsAliasSafe(const FSSpec& inSpec) +// Returns true if the alias is in the alias haven directory, or if alias resolution +// has been turned off. +//---------------------------------------------------------------------------------------- +{ + return sNoResolve + || (inSpec.parID == sAliasHavenDirID && inSpec.vRefNum == sAliasHavenVRefNum); +} // MacFileHelpers::IsAliasSafe + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased) +//---------------------------------------------------------------------------------------- +{ + wasAliased = false; + if (IsAliasSafe(inOutSpec)) + return noErr; + Boolean dummy; + return ::ResolveAliasFile(&inOutSpec, TRUE, &dummy, &wasAliased); +} // MacFileHelpers::ResolveAliasFile + +//----------------------------------- +OSErr MacFileHelpers::FSSpecFromFullUnixPath( + const char * unixPath, + FSSpec& outSpec, + Boolean resolveAlias) +// File spec from URL. Reverses GetURLFromFileSpec +// Its input is only the part of the URL +// JRM 97/01/08 changed this so that if it's a partial path (doesn't start with '/'), +// then it is combined with inOutSpec's vRefNum and parID to form a new spec. +//----------------------------------- +{ + if (unixPath == NULL) + return badFidErr; + char* macPath = MacPathFromUnixPath(unixPath); + if (!macPath) + return memFullErr; + + OSErr err = noErr; + NS_ASSERTION(*unixPath == '/' /*full path*/, "Not a Unix path!"); + err = FSSpecFromPathname(macPath, outSpec); + if (err == fnfErr) + err = noErr; + Boolean dummy; + if (err == noErr && resolveAlias) // Added + err = MacFileHelpers::ResolveAliasFile(outSpec, dummy); + delete [] macPath; + NS_ASSERTION(err==noErr||err==fnfErr||err==dirNFErr||err==nsvErr, "Not a path!"); + return err; +} // MacFileHelpers::FSSpecFromLocalUnixPath + +//----------------------------------- +char* MacFileHelpers::PathNameFromFSSpec( const FSSpec& inSpec, Boolean wantLeafName ) +// Returns a full pathname to the given file +// Returned value is allocated with new [], and must be freed with delete [] +// This is taken from FSpGetFullPath in MoreFiles, except that we need to tolerate +// fnfErr. +//----------------------------------- +{ + char* result = nil; + OSErr err = noErr; + + short fullPathLength = 0; + Handle fullPath = NULL; + + FSSpec tempSpec = inSpec; + if ( tempSpec.parID == fsRtParID ) + { + /* The object is a volume */ + + /* Add a colon to make it a full pathname */ + tempSpec.name[++tempSpec.name[0]] = ':'; + + /* We're done */ + err = PtrToHand(&tempSpec.name[1], &fullPath, tempSpec.name[0]); + } + else + { + /* The object isn't a volume */ + + CInfoPBRec pb = { 0 }; + Str63 dummyFileName; + PLstrcpy(dummyFileName, "\pG'day!"); + + /* Is the object a file or a directory? */ + pb.dirInfo.ioNamePtr = (! tempSpec.name[0]) ? (StringPtr)dummyFileName : tempSpec.name; + pb.dirInfo.ioVRefNum = tempSpec.vRefNum; + pb.dirInfo.ioDrDirID = tempSpec.parID; + pb.dirInfo.ioFDirIndex = 0; + err = PBGetCatInfoSync(&pb); + if ( err == noErr || err == fnfErr) + { + // if the object is a directory, append a colon so full pathname ends with colon + // Beware of the "illegal spec" case that Netscape uses (empty name string). In + // this case, we don't want the colon. + if ( err == noErr && tempSpec.name[0] && (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) + { + ++tempSpec.name[0]; + tempSpec.name[tempSpec.name[0]] = ':'; + } + + /* Put the object name in first */ + err = PtrToHand(&tempSpec.name[1], &fullPath, tempSpec.name[0]); + if ( err == noErr ) + { + /* Get the ancestor directory names */ + pb.dirInfo.ioNamePtr = tempSpec.name; + pb.dirInfo.ioVRefNum = tempSpec.vRefNum; + pb.dirInfo.ioDrParID = tempSpec.parID; + do /* loop until we have an error or find the root directory */ + { + pb.dirInfo.ioFDirIndex = -1; + pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; + err = PBGetCatInfoSync(&pb); + if ( err == noErr ) + { + /* Append colon to directory name */ + ++tempSpec.name[0]; + tempSpec.name[tempSpec.name[0]] = ':'; + + /* Add directory name to beginning of fullPath */ + (void) Munger(fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]); + err = MemError(); + } + } while ( err == noErr && pb.dirInfo.ioDrDirID != fsRtDirID ); + } + } + } + if ( err != noErr && err != fnfErr) + goto Clean; + + fullPathLength = GetHandleSize(fullPath); + err = noErr; + int allocSize = 1 + fullPathLength; + // We only want the leaf name if it's the root directory or wantLeafName is true. + if (inSpec.parID != fsRtParID && !wantLeafName) + allocSize -= inSpec.name[0]; + result = new char[allocSize]; + if (!result) + goto Clean; + memcpy(result, *fullPath, allocSize - 1); + result[ allocSize - 1 ] = 0; +Clean: + if (fullPath) + DisposeHandle(fullPath); + NS_ASSERTION(result, "Out of memory"); // OOPS! very bad. + return result; +} // MacFileHelpers::PathNameFromFSSpec + +//======================================================================================== +// Macintosh nsNativeFileSpec implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec() +//---------------------------------------------------------------------------------------- +: mError(noErr) +{ + mSpec.name[0] = '\0'; +} + +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec(const nsNativeFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +: mSpec((FSSpec&)inSpec) +, mError(inSpec.Error()) +{ +} + +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec(const std::string& inString) +//---------------------------------------------------------------------------------------- +{ + mError = MacFileHelpers::FSSpecFromFullUnixPath(inString.c_str(), mSpec, true); +} // nsNativeFileSpec::nsNativeFileSpec + +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec( + short vRefNum, + long parID, + ConstStr255Param name) +//---------------------------------------------------------------------------------------- +{ + mError = ::FSMakeFSSpec(vRefNum, parID, name, &mSpec); + if (mError == fnfErr) + mError = noErr; +} + +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec(const nsUnixFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + *this = inPath.GetNativeSpec(); +} + +#if DEBUG +//---------------------------------------------------------------------------------------- +ostream& operator << (ostream& s, const nsNativeFileSpec& spec) +//---------------------------------------------------------------------------------------- +{ + s << spec.mSpec.vRefNum << ", " << spec.mSpec.parID << ", \""; + for (int i = 1; i <= spec.mSpec.name[0]; i++) + s.put(spec.mSpec.name[i]); + return s << "\""; +} // ostream& operator << (ostream&, const nsNativeFileSpec&) +#endif // DEBUG + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator = (const std::string& inString) +//---------------------------------------------------------------------------------------- +{ + mError = MacFileHelpers::FSSpecFromFullUnixPath(inString.c_str(), mSpec, true); +} // nsNativeFileSpec::operator = + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator = (const nsNativeFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mSpec = inSpec; + mError = inSpec.Error(); +} // nsNativeFileSpec::operator = + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator = (const nsUnixFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + mSpec = inPath.GetNativeSpec(); +} // nsNativeFileSpec::operator = + +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + FSSpec temp; + return ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &temp) == noErr; +} // nsNativeFileSpec::operator = + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::SetLeafName(const std::string& inLeafName) +//---------------------------------------------------------------------------------------- +{ + *mSpec.name = inLeafName.length(); + memcpy(mSpec.name + 1, inLeafName.c_str(), 1 + *mSpec.name); +} // nsNativeFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +std::string nsNativeFileSpec::GetLeafName() const +//---------------------------------------------------------------------------------------- +{ + char leaf[64]; + memcpy(leaf, &mSpec.name[1], mSpec.name[0]); + leaf[mSpec.name[0]] = '\0'; + return std::string(leaf); +} // nsNativeFileSpec::GetLeafName + +//======================================================================================== +// Macintosh nsUnixFilePath implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsUnixFilePath::nsUnixFilePath(const nsNativeFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +#ifdef XP_MAC +: mNativeFileSpec(inSpec) +#endif +{ + char * path = MacFileHelpers::PathNameFromFSSpec( inSpec.mSpec, TRUE ); + char * unixPath = MacFileHelpers::EncodeMacPath(path, true, true); + mPath = unixPath; + delete [] unixPath; +} + +//---------------------------------------------------------------------------------------- +void nsUnixFilePath::operator = (const nsNativeFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + char * path = MacFileHelpers::PathNameFromFSSpec( inSpec.mSpec, TRUE ); + char * unixPath = MacFileHelpers::EncodeMacPath(path, true, true); + mPath = unixPath; + delete [] unixPath; +#ifdef XP_MAC + mNativeFileSpec = inSpec; +#endif +} // nsUnixFilePath::operator = diff --git a/mozilla/base/src/nsFileSpec.cpp b/mozilla/base/src/nsFileSpec.cpp new file mode 100644 index 00000000000..f13554bd62e --- /dev/null +++ b/mozilla/base/src/nsFileSpec.cpp @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsFileSpec.h" + +#include "prtypes.h" + +#if DEBUG +#include +#endif + +#include + +//======================================================================================== +namespace nsFileSpecHelpers +//======================================================================================== +{ + enum + { kMaxFilenameLength = 31 // should work on Macintosh, Unix, and Win32. + , kMaxAltDigitLength = 5 + , kMaxAltNameLength = (kMaxFilenameLength - (kMaxAltDigitLength + 1)) + }; + void LeafReplace( + std::string& ioPath, + char inSeparator, + const std::string& inLeafName); + std::string GetLeaf(const std::string& inPath, char inSeparator); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::LeafReplace( + std::string& ioPath, + char inSeparator, + const std::string& inLeafName) +//---------------------------------------------------------------------------------------- +{ + // Find the existing leaf name + std::string::size_type lastSeparator = ioPath.rfind(inSeparator); + std::string::size_type myLength = ioPath.length(); + if (lastSeparator < myLength) + ioPath = ioPath.substr(0, lastSeparator + 1) + inLeafName; +} // nsNativeFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +std::string nsFileSpecHelpers::GetLeaf(const std::string& inPath, char inSeparator) +//---------------------------------------------------------------------------------------- +{ + std::string::size_type lastSeparator = inPath.rfind(inSeparator); + std::string::size_type myLength = inPath.length(); + if (lastSeparator < myLength) + return inPath.substr(1 + lastSeparator, myLength - lastSeparator - 1); + return inPath; +} // nsNativeFileSpec::GetLeafName + + +#ifdef XP_MAC +#include "nsFileSpecMac.cpp" // Macintosh-specific implementations +#elif defined(XP_WIN) +#include "nsFileSpecWin.cpp" // Windows-specific implementations +#elif defined(XP_UNIX) +#include "nsFileSpecUnix.cpp" // Unix-specific implementations +#endif + + +//======================================================================================== +// nsFileURL implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const std::string& inString) +//---------------------------------------------------------------------------------------- +: mURL(inString) +#ifdef XP_MAC +, mNativeFileSpec(inString.substr(kFileURLPrefixLength, inString.length() - kFileURLPrefixLength)) +#endif +{ + NS_ASSERTION(mURL.substr(0, kFileURLPrefixLength) == kFileURLPrefix, "Not a URL!"); +} + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const std::string& inString) +//---------------------------------------------------------------------------------------- +{ + mURL = inString; + NS_ASSERTION(mURL.substr(0, kFileURLPrefixLength) == kFileURLPrefix, "Not a URL!"); +#ifdef XP_MAC + mNativeFileSpec = + inString.substr(kFileURLPrefixLength, inString.length() - kFileURLPrefixLength); +#endif +} + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +: mURL(inOther.mURL) +#ifdef XP_MAC +, mNativeFileSpec(inOther.GetNativeSpec()) +#endif +{ +} + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = inOther.mURL; +#ifdef XP_MAC + mNativeFileSpec = inOther.GetNativeSpec(); +#endif +} + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsUnixFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = kFileURLPrefix + ((string&)inOther); +#ifdef XP_MAC + mNativeFileSpec = inOther.GetNativeSpec(); +#endif +} +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsUnixFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = kFileURLPrefix + ((string&)inOther); +#ifdef XP_MAC + mNativeFileSpec = inOther.GetNativeSpec(); +#endif +} + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsNativeFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = kFileURLPrefix + (std::string&)nsUnixFilePath(inOther); +#ifdef XP_MAC + mNativeFileSpec = inOther; +#endif +} +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsNativeFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = kFileURLPrefix + (std::string&)nsUnixFilePath(inOther); +#ifdef XP_MAC + mNativeFileSpec = inOther; +#endif +} + +//======================================================================================== +// nsUnixFilePath implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsUnixFilePath::nsUnixFilePath(const std::string& inString) +//---------------------------------------------------------------------------------------- +: mPath(inString) +#ifdef XP_MAC +, mNativeFileSpec(inString) +#endif +{ + NS_ASSERTION(mPath.substr(0, kFileURLPrefixLength) != kFileURLPrefix, "URL passed as path"); +} + +//---------------------------------------------------------------------------------------- +nsUnixFilePath::nsUnixFilePath(const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +: mPath(((string&)inOther).substr( + kFileURLPrefixLength, ((string&)inOther).length() - kFileURLPrefixLength)) +#ifdef XP_MAC +, mNativeFileSpec(inOther.GetNativeSpec()) +#endif +{ +} + +//---------------------------------------------------------------------------------------- +void nsUnixFilePath::operator = (const std::string& inString) +//---------------------------------------------------------------------------------------- +{ + mPath = inString; +#ifdef XP_MAC + mNativeFileSpec = inString; +#endif + NS_ASSERTION(mPath.substr(0, kFileURLPrefixLength) != kFileURLPrefix, "URL passed as path"); +} + +//---------------------------------------------------------------------------------------- +void nsUnixFilePath::operator = (const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + mPath = ((string&)inOther).substr( + kFileURLPrefixLength, ((string&)inOther).length() - kFileURLPrefixLength); +#ifdef XP_MAC + mNativeFileSpec = inOther.GetNativeSpec(); +#endif +} + +//======================================================================================== +// nsNativeFileSpec implementation +//======================================================================================== + +#ifndef XP_MAC +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec() +//---------------------------------------------------------------------------------------- +{ +} +#endif + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::MakeUnique(const std::string& inSuggestedLeafName) +//---------------------------------------------------------------------------------------- +{ + if (inSuggestedLeafName.length() > 0) + SetLeafName(inSuggestedLeafName); + + MakeUnique(); +} // nsNativeFileSpec::MakeUnique + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::MakeUnique() +//---------------------------------------------------------------------------------------- +{ + if (!Exists()) + return; + + short index = 0; + std::string altName = GetLeafName(); + std::string::size_type lastDot = altName.rfind('.'); + std::string suffix; + if (lastDot < altName.length()) + { + suffix = altName.substr(lastDot, altName.length() - lastDot); // include '.' + altName = altName.substr(0, lastDot); + } + const std::string::size_type kMaxRootLength + = nsFileSpecHelpers::kMaxAltNameLength - suffix.length() - 1; + if (altName.length() > kMaxRootLength) + altName = altName.substr(0, kMaxRootLength); + while (Exists()) + { + // start with "Picture-2.jpg" after "Picture.jpg" exists + if ( ++index > 999 ) // something's very wrong + return; + char buf[nsFileSpecHelpers::kMaxFilenameLength + 1]; + ostrstream newName(buf, nsFileSpecHelpers::kMaxFilenameLength); + newName << altName.c_str() << "-" << index << suffix.c_str() << ends; + SetLeafName(newName.str()); // or: SetLeafName(buf) + } +} // nsNativeFileSpec::MakeUnique diff --git a/mozilla/base/tests/FilesTest.cpp b/mozilla/base/tests/FilesTest.cpp new file mode 100644 index 00000000000..4563b2cd924 --- /dev/null +++ b/mozilla/base/tests/FilesTest.cpp @@ -0,0 +1,82 @@ +#include "nsFileSpec.h" +#include + +#include "nsFileStream.h" + +namespace FileTest +{ + void WriteStuff(ostream& s); +} + +//---------------------------------------------------------------------------------------- +void FileTest::WriteStuff(ostream& s) +//---------------------------------------------------------------------------------------- +{ + // Initialize a URL from a string without suffix. Change the path to suit your machine. + nsFileURL fileURL("file:///Development/MPW/MPW%20Shell"); + s << "File URL initialized to: \"" << (string&)fileURL << "\""<< endl; + + // Initialize a Unix path from a URL + nsUnixFilePath filePath(fileURL); + s << "As a unix path: \"" << (string&)filePath << "\""<< endl; + + // Initialize a native file spec from a URL + nsNativeFileSpec fileSpec(fileURL); + s << "As a file spec: " << fileSpec << endl; + + // Make the spec unique (this one has no suffix). + fileSpec.MakeUnique(); + s << "Unique file spec: " << fileSpec << endl; + + // Assign the spec to a URL + fileURL = fileSpec; + s << "File URL assigned from spec: \"" << (string&)fileURL << "\""<< endl; + + // Assign a unix path using a string with a suffix. + filePath = "/Development/MPW/SysErrs.err"; + s << "File path reassigned to: \"" << (string&)filePath << "\""<< endl; + + // Assign to a file spec using a unix path. + fileSpec = filePath; + s << "File spec reassigned to: " << fileSpec << endl; + + // Make this unique (this one has a suffix). + fileSpec.MakeUnique(); + s << "File spec made unique: " << fileSpec << endl; +} // WriteStuff + +//---------------------------------------------------------------------------------------- +void main() +// For use with DEBUG defined. +//---------------------------------------------------------------------------------------- +{ + +#if !defined(DEBUG) || (DEBUG==0) +#error "This test only works with a DEBUG build." +#endif + // Test of nsFileSpec + + cout << "WRITING TEST OUTPUT TO cout" << endl << endl; + FileTest::WriteStuff(cout); + cout << endl << endl; + + // Test of nsOutputFileStream + + nsUnixFilePath myTextFilePath("/Development/iotest.txt"); + + cout << "WRITING IDENTICAL OUTPUT TO " << myTextFilePath << endl << endl; + nsOutputFileStream testStream(myTextFilePath); + FileTest::WriteStuff(testStream); + + // Test of nsInputFileStream + + cout << "READING BACK DATA FROM " << myTextFilePath << endl << endl; + nsInputFileStream testStream2(myTextFilePath); + char line[1000]; + while (!testStream2.eof()) + { + testStream2.getline(line, sizeof(line), '\n'); + cout << line << endl; + } + +} // main diff --git a/mozilla/xpcom/io/nsFileSpec.cpp b/mozilla/xpcom/io/nsFileSpec.cpp new file mode 100644 index 00000000000..f13554bd62e --- /dev/null +++ b/mozilla/xpcom/io/nsFileSpec.cpp @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsFileSpec.h" + +#include "prtypes.h" + +#if DEBUG +#include +#endif + +#include + +//======================================================================================== +namespace nsFileSpecHelpers +//======================================================================================== +{ + enum + { kMaxFilenameLength = 31 // should work on Macintosh, Unix, and Win32. + , kMaxAltDigitLength = 5 + , kMaxAltNameLength = (kMaxFilenameLength - (kMaxAltDigitLength + 1)) + }; + void LeafReplace( + std::string& ioPath, + char inSeparator, + const std::string& inLeafName); + std::string GetLeaf(const std::string& inPath, char inSeparator); +} + +//---------------------------------------------------------------------------------------- +void nsFileSpecHelpers::LeafReplace( + std::string& ioPath, + char inSeparator, + const std::string& inLeafName) +//---------------------------------------------------------------------------------------- +{ + // Find the existing leaf name + std::string::size_type lastSeparator = ioPath.rfind(inSeparator); + std::string::size_type myLength = ioPath.length(); + if (lastSeparator < myLength) + ioPath = ioPath.substr(0, lastSeparator + 1) + inLeafName; +} // nsNativeFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +std::string nsFileSpecHelpers::GetLeaf(const std::string& inPath, char inSeparator) +//---------------------------------------------------------------------------------------- +{ + std::string::size_type lastSeparator = inPath.rfind(inSeparator); + std::string::size_type myLength = inPath.length(); + if (lastSeparator < myLength) + return inPath.substr(1 + lastSeparator, myLength - lastSeparator - 1); + return inPath; +} // nsNativeFileSpec::GetLeafName + + +#ifdef XP_MAC +#include "nsFileSpecMac.cpp" // Macintosh-specific implementations +#elif defined(XP_WIN) +#include "nsFileSpecWin.cpp" // Windows-specific implementations +#elif defined(XP_UNIX) +#include "nsFileSpecUnix.cpp" // Unix-specific implementations +#endif + + +//======================================================================================== +// nsFileURL implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const std::string& inString) +//---------------------------------------------------------------------------------------- +: mURL(inString) +#ifdef XP_MAC +, mNativeFileSpec(inString.substr(kFileURLPrefixLength, inString.length() - kFileURLPrefixLength)) +#endif +{ + NS_ASSERTION(mURL.substr(0, kFileURLPrefixLength) == kFileURLPrefix, "Not a URL!"); +} + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const std::string& inString) +//---------------------------------------------------------------------------------------- +{ + mURL = inString; + NS_ASSERTION(mURL.substr(0, kFileURLPrefixLength) == kFileURLPrefix, "Not a URL!"); +#ifdef XP_MAC + mNativeFileSpec = + inString.substr(kFileURLPrefixLength, inString.length() - kFileURLPrefixLength); +#endif +} + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +: mURL(inOther.mURL) +#ifdef XP_MAC +, mNativeFileSpec(inOther.GetNativeSpec()) +#endif +{ +} + +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = inOther.mURL; +#ifdef XP_MAC + mNativeFileSpec = inOther.GetNativeSpec(); +#endif +} + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsUnixFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = kFileURLPrefix + ((string&)inOther); +#ifdef XP_MAC + mNativeFileSpec = inOther.GetNativeSpec(); +#endif +} +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsUnixFilePath& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = kFileURLPrefix + ((string&)inOther); +#ifdef XP_MAC + mNativeFileSpec = inOther.GetNativeSpec(); +#endif +} + +//---------------------------------------------------------------------------------------- +nsFileURL::nsFileURL(const nsNativeFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = kFileURLPrefix + (std::string&)nsUnixFilePath(inOther); +#ifdef XP_MAC + mNativeFileSpec = inOther; +#endif +} +//---------------------------------------------------------------------------------------- +void nsFileURL::operator = (const nsNativeFileSpec& inOther) +//---------------------------------------------------------------------------------------- +{ + mURL = kFileURLPrefix + (std::string&)nsUnixFilePath(inOther); +#ifdef XP_MAC + mNativeFileSpec = inOther; +#endif +} + +//======================================================================================== +// nsUnixFilePath implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsUnixFilePath::nsUnixFilePath(const std::string& inString) +//---------------------------------------------------------------------------------------- +: mPath(inString) +#ifdef XP_MAC +, mNativeFileSpec(inString) +#endif +{ + NS_ASSERTION(mPath.substr(0, kFileURLPrefixLength) != kFileURLPrefix, "URL passed as path"); +} + +//---------------------------------------------------------------------------------------- +nsUnixFilePath::nsUnixFilePath(const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +: mPath(((string&)inOther).substr( + kFileURLPrefixLength, ((string&)inOther).length() - kFileURLPrefixLength)) +#ifdef XP_MAC +, mNativeFileSpec(inOther.GetNativeSpec()) +#endif +{ +} + +//---------------------------------------------------------------------------------------- +void nsUnixFilePath::operator = (const std::string& inString) +//---------------------------------------------------------------------------------------- +{ + mPath = inString; +#ifdef XP_MAC + mNativeFileSpec = inString; +#endif + NS_ASSERTION(mPath.substr(0, kFileURLPrefixLength) != kFileURLPrefix, "URL passed as path"); +} + +//---------------------------------------------------------------------------------------- +void nsUnixFilePath::operator = (const nsFileURL& inOther) +//---------------------------------------------------------------------------------------- +{ + mPath = ((string&)inOther).substr( + kFileURLPrefixLength, ((string&)inOther).length() - kFileURLPrefixLength); +#ifdef XP_MAC + mNativeFileSpec = inOther.GetNativeSpec(); +#endif +} + +//======================================================================================== +// nsNativeFileSpec implementation +//======================================================================================== + +#ifndef XP_MAC +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec() +//---------------------------------------------------------------------------------------- +{ +} +#endif + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::MakeUnique(const std::string& inSuggestedLeafName) +//---------------------------------------------------------------------------------------- +{ + if (inSuggestedLeafName.length() > 0) + SetLeafName(inSuggestedLeafName); + + MakeUnique(); +} // nsNativeFileSpec::MakeUnique + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::MakeUnique() +//---------------------------------------------------------------------------------------- +{ + if (!Exists()) + return; + + short index = 0; + std::string altName = GetLeafName(); + std::string::size_type lastDot = altName.rfind('.'); + std::string suffix; + if (lastDot < altName.length()) + { + suffix = altName.substr(lastDot, altName.length() - lastDot); // include '.' + altName = altName.substr(0, lastDot); + } + const std::string::size_type kMaxRootLength + = nsFileSpecHelpers::kMaxAltNameLength - suffix.length() - 1; + if (altName.length() > kMaxRootLength) + altName = altName.substr(0, kMaxRootLength); + while (Exists()) + { + // start with "Picture-2.jpg" after "Picture.jpg" exists + if ( ++index > 999 ) // something's very wrong + return; + char buf[nsFileSpecHelpers::kMaxFilenameLength + 1]; + ostrstream newName(buf, nsFileSpecHelpers::kMaxFilenameLength); + newName << altName.c_str() << "-" << index << suffix.c_str() << ends; + SetLeafName(newName.str()); // or: SetLeafName(buf) + } +} // nsNativeFileSpec::MakeUnique diff --git a/mozilla/xpcom/io/nsFileSpecMac.cpp b/mozilla/xpcom/io/nsFileSpecMac.cpp new file mode 100644 index 00000000000..b2a5930b0ee --- /dev/null +++ b/mozilla/xpcom/io/nsFileSpecMac.cpp @@ -0,0 +1,571 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +// This file is included by nsFile.cp, and includes the Macintosh-specific +// implementations. + +#include "FullPath.h" +#include "FileCopy.h" +#include "nsEscape.h" + +#include +#include +#include +#include +#include + +const unsigned char* kAliasHavenFolderName = "\pnsAliasHaven"; + +//======================================================================================== +namespace MacFileHelpers +//======================================================================================== +{ + void SwapSlashColon(char * s); + OSErr FSSpecFromFullUnixPath( + const char * unixPath, + FSSpec& outSpec, + Boolean resolveAlias); + char* MacPathFromUnixPath(const char* unixPath); + char* EncodeMacPath( + char* inPath, // NOT const - gets clobbered + Boolean prependSlash, + Boolean doEscape ); + OSErr FSSpecFromPathname( + const char* inPathNamePtr, + FSSpec& outSpec); + char* PathNameFromFSSpec( + const FSSpec& inSpec, + Boolean wantLeafName ); + OSErr CreateFolderInFolder( + short refNum, // Parent directory/volume + long dirID, + ConstStr255Param folderName, // Name of the new folder + short& outRefNum, // Volume of the created folder + long& outDirID); // + + // Some routines to support an "alias haven" directory. Aliases in this directory + // are never resolved. There is a ResolveAlias here that respects that. This is + // to support attaching of aliases in mail. + void EnsureAliasHaven(); + void SetNoResolve(Boolean inResolve); + Boolean IsAliasSafe(const FSSpec& inSpec); + OSErr MakeAliasSafe(FSSpec& inOutSpec); + OSErr ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased); + + Boolean sNoResolve = false; + long sAliasHavenDirID = 0; + short sAliasHavenVRefNum = 0; +} // namespace MacFileHelpers + +//----------------------------------- +void MacFileHelpers::SwapSlashColon(char * s) +//----------------------------------- + +{ + while ( *s != 0) + { + if (*s == '/') + *s++ = ':'; + else if (*s == ':') + *s++ = '/'; + else + *s++; + } +} // MacFileHelpers::SwapSlashColon + +//----------------------------------- +char* MacFileHelpers::EncodeMacPath( + char* inPath, // NOT const, gets clobbered + Boolean prependSlash, + Boolean doEscape ) +// Transforms Macintosh style path into Unix one +// Method: Swap ':' and '/', hex escape the result +//----------------------------------- +{ + if (inPath == NULL) + return NULL; + int pathSize = strlen(inPath); + + // XP code sometimes chokes if there's a final slash in the unix path. + // Since correct mac paths to folders and volumes will end in ':', strip this + // first. + char* c = inPath + pathSize - 1; + if (*c == ':') + { + *c = 0; + pathSize--; + } + + char * newPath = NULL; + char * finalPath = NULL; + + if (prependSlash) + { + newPath = new char[pathSize + 2]; + newPath[0] = ':'; // It will be converted to '/' + memcpy(&newPath[1], inPath, pathSize + 1); + } + else + { + newPath = new char[pathSize + 1]; + strcpy(newPath, inPath); + } + if (newPath) + { + SwapSlashColon( newPath ); + if (doEscape) + { + finalPath = nsEscape(newPath, url_Path); + delete [] newPath; + } + else + finalPath = newPath; + } + delete [] inPath; + return finalPath; +} // MacFileHelpers::EncodeMacPath + +//---------------------------------------------------------------------------------------- +inline void MacFileHelpers::SetNoResolve(Boolean inResolve) +//---------------------------------------------------------------------------------------- +{ + sNoResolve = inResolve; +} // MacFileHelpers::SetNoResolve + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::MakeAliasSafe(FSSpec& inOutSpec) +// Pass in the spec of an alias. This copies the file to the safe haven folder, and +// returns the spec of the copy to the caller +//---------------------------------------------------------------------------------------- +{ + EnsureAliasHaven(); + nsNativeFileSpec dstDirSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\p"); + + // Make sure its name is unique + nsNativeFileSpec havenSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\pG'day"); + if (havenSpec.Valid()) + havenSpec.MakeUnique(inOutSpec.name); + // Copy the file into the haven directory + if (havenSpec.Valid()) + { + OSErr err = ::FSpFileCopy( + &inOutSpec, + dstDirSpec, + havenSpec.GetLeafPName(), + nil, 0, true); + // Return the spec of the copy to the caller. + if (err != noErr) + return err; + inOutSpec = havenSpec; + } + return noErr; +} // MacFileHelpers::MakeAliasSafe + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::MakeUnique(ConstStr255Param inSuggestedLeafName) +//---------------------------------------------------------------------------------------- +{ + if (inSuggestedLeafName[0] > 0) + PLstrcpy(mSpec.name, inSuggestedLeafName); + + MakeUnique(); +} + +//---------------------------------------------------------------------------------------- +char* MacFileHelpers::MacPathFromUnixPath(const char* unixPath) +//---------------------------------------------------------------------------------------- +{ + // Relying on the fact that the unix path is always longer than the mac path: + size_t len = strlen(unixPath); + char* result = new char[len + 2]; // ... but allow for the initial colon in a partial name + if (result) + { + char* dst = result; + const char* src = unixPath; + if (*src == '/') // ¥ full path + src++; + else if (strchr(src, '/')) // ¥ partial path, and not just a leaf name + *dst++ = ':'; + strcpy(dst, src); + nsUnescape(dst); // Hex Decode + MacFileHelpers::SwapSlashColon(dst); + } + return result; +} // MacFileHelpers::MacPathFromUnixPath + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::FSSpecFromPathname(const char* inPathNamePtr, FSSpec& outSpec) +// FSSpecFromPathname reverses PathNameFromFSSpec. +// It returns a FSSpec given a c string which is a mac pathname. +//---------------------------------------------------------------------------------------- +{ + OSErr err; + // Simplify this routine to use FSMakeFSSpec if length < 255. Otherwise use the MoreFiles + // routine FSpLocationFromFullPath, which allocates memory, to handle longer pathnames. + if (strlen(inPathNamePtr) < 255) + { + Str255 path; + + int pos = 0; + while ( (path[++pos] = *inPathNamePtr++) != 0 ) + ; + path[0] = pos-1; // save the length of the string (pos is the next open spot) + + err = ::FSMakeFSSpec(0, 0, path, &outSpec); + } + else + err = FSpLocationFromFullPath(strlen(inPathNamePtr), inPathNamePtr, &outSpec); + + return err; +} + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::CreateFolderInFolder( + short refNum, // Parent directory/volume + long dirID, + ConstStr255Param folderName, // Name of the new folder + short& outRefNum, // Volume of the created folder + long& outDirID) // +// Creates a folder named 'folderName' inside a folder. +// The errors returned are same as PBDirCreate +//---------------------------------------------------------------------------------------- +{ + HFileParam hpb; + hpb.ioVRefNum = refNum; + hpb.ioDirID = dirID; + hpb.ioNamePtr = (StringPtr)&folderName; + + OSErr err = PBDirCreateSync((HParmBlkPtr)&hpb); + if (err == noErr) + { + outRefNum = hpb.ioVRefNum; + outDirID = hpb.ioDirID; + } + else + { + outRefNum = 0; + outDirID = 0; + } + return err; +} // MacFileHelpers::CreateFolderInFolder + +//---------------------------------------------------------------------------------------- +void MacFileHelpers::EnsureAliasHaven() +//---------------------------------------------------------------------------------------- +{ + // Alias Haven is a directory in which we never resolve aliases. + if (sAliasHavenVRefNum != 0) + return; + + + FSSpec temp; + if (FindFolder(0, kTemporaryFolderType, true, & temp.vRefNum, &temp.parID) == noErr) + { + CreateFolderInFolder( + temp.vRefNum, // Parent directory/volume + temp.parID, + kAliasHavenFolderName, // Name of the new folder + sAliasHavenVRefNum, // Volume of the created folder + sAliasHavenDirID); + } +} // MacFileHelpers::EnsureAliasHaven + +//---------------------------------------------------------------------------------------- +Boolean MacFileHelpers::IsAliasSafe(const FSSpec& inSpec) +// Returns true if the alias is in the alias haven directory, or if alias resolution +// has been turned off. +//---------------------------------------------------------------------------------------- +{ + return sNoResolve + || (inSpec.parID == sAliasHavenDirID && inSpec.vRefNum == sAliasHavenVRefNum); +} // MacFileHelpers::IsAliasSafe + +//---------------------------------------------------------------------------------------- +OSErr MacFileHelpers::ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased) +//---------------------------------------------------------------------------------------- +{ + wasAliased = false; + if (IsAliasSafe(inOutSpec)) + return noErr; + Boolean dummy; + return ::ResolveAliasFile(&inOutSpec, TRUE, &dummy, &wasAliased); +} // MacFileHelpers::ResolveAliasFile + +//----------------------------------- +OSErr MacFileHelpers::FSSpecFromFullUnixPath( + const char * unixPath, + FSSpec& outSpec, + Boolean resolveAlias) +// File spec from URL. Reverses GetURLFromFileSpec +// Its input is only the part of the URL +// JRM 97/01/08 changed this so that if it's a partial path (doesn't start with '/'), +// then it is combined with inOutSpec's vRefNum and parID to form a new spec. +//----------------------------------- +{ + if (unixPath == NULL) + return badFidErr; + char* macPath = MacPathFromUnixPath(unixPath); + if (!macPath) + return memFullErr; + + OSErr err = noErr; + NS_ASSERTION(*unixPath == '/' /*full path*/, "Not a Unix path!"); + err = FSSpecFromPathname(macPath, outSpec); + if (err == fnfErr) + err = noErr; + Boolean dummy; + if (err == noErr && resolveAlias) // Added + err = MacFileHelpers::ResolveAliasFile(outSpec, dummy); + delete [] macPath; + NS_ASSERTION(err==noErr||err==fnfErr||err==dirNFErr||err==nsvErr, "Not a path!"); + return err; +} // MacFileHelpers::FSSpecFromLocalUnixPath + +//----------------------------------- +char* MacFileHelpers::PathNameFromFSSpec( const FSSpec& inSpec, Boolean wantLeafName ) +// Returns a full pathname to the given file +// Returned value is allocated with new [], and must be freed with delete [] +// This is taken from FSpGetFullPath in MoreFiles, except that we need to tolerate +// fnfErr. +//----------------------------------- +{ + char* result = nil; + OSErr err = noErr; + + short fullPathLength = 0; + Handle fullPath = NULL; + + FSSpec tempSpec = inSpec; + if ( tempSpec.parID == fsRtParID ) + { + /* The object is a volume */ + + /* Add a colon to make it a full pathname */ + tempSpec.name[++tempSpec.name[0]] = ':'; + + /* We're done */ + err = PtrToHand(&tempSpec.name[1], &fullPath, tempSpec.name[0]); + } + else + { + /* The object isn't a volume */ + + CInfoPBRec pb = { 0 }; + Str63 dummyFileName; + PLstrcpy(dummyFileName, "\pG'day!"); + + /* Is the object a file or a directory? */ + pb.dirInfo.ioNamePtr = (! tempSpec.name[0]) ? (StringPtr)dummyFileName : tempSpec.name; + pb.dirInfo.ioVRefNum = tempSpec.vRefNum; + pb.dirInfo.ioDrDirID = tempSpec.parID; + pb.dirInfo.ioFDirIndex = 0; + err = PBGetCatInfoSync(&pb); + if ( err == noErr || err == fnfErr) + { + // if the object is a directory, append a colon so full pathname ends with colon + // Beware of the "illegal spec" case that Netscape uses (empty name string). In + // this case, we don't want the colon. + if ( err == noErr && tempSpec.name[0] && (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) + { + ++tempSpec.name[0]; + tempSpec.name[tempSpec.name[0]] = ':'; + } + + /* Put the object name in first */ + err = PtrToHand(&tempSpec.name[1], &fullPath, tempSpec.name[0]); + if ( err == noErr ) + { + /* Get the ancestor directory names */ + pb.dirInfo.ioNamePtr = tempSpec.name; + pb.dirInfo.ioVRefNum = tempSpec.vRefNum; + pb.dirInfo.ioDrParID = tempSpec.parID; + do /* loop until we have an error or find the root directory */ + { + pb.dirInfo.ioFDirIndex = -1; + pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; + err = PBGetCatInfoSync(&pb); + if ( err == noErr ) + { + /* Append colon to directory name */ + ++tempSpec.name[0]; + tempSpec.name[tempSpec.name[0]] = ':'; + + /* Add directory name to beginning of fullPath */ + (void) Munger(fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]); + err = MemError(); + } + } while ( err == noErr && pb.dirInfo.ioDrDirID != fsRtDirID ); + } + } + } + if ( err != noErr && err != fnfErr) + goto Clean; + + fullPathLength = GetHandleSize(fullPath); + err = noErr; + int allocSize = 1 + fullPathLength; + // We only want the leaf name if it's the root directory or wantLeafName is true. + if (inSpec.parID != fsRtParID && !wantLeafName) + allocSize -= inSpec.name[0]; + result = new char[allocSize]; + if (!result) + goto Clean; + memcpy(result, *fullPath, allocSize - 1); + result[ allocSize - 1 ] = 0; +Clean: + if (fullPath) + DisposeHandle(fullPath); + NS_ASSERTION(result, "Out of memory"); // OOPS! very bad. + return result; +} // MacFileHelpers::PathNameFromFSSpec + +//======================================================================================== +// Macintosh nsNativeFileSpec implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec() +//---------------------------------------------------------------------------------------- +: mError(noErr) +{ + mSpec.name[0] = '\0'; +} + +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec(const nsNativeFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +: mSpec((FSSpec&)inSpec) +, mError(inSpec.Error()) +{ +} + +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec(const std::string& inString) +//---------------------------------------------------------------------------------------- +{ + mError = MacFileHelpers::FSSpecFromFullUnixPath(inString.c_str(), mSpec, true); +} // nsNativeFileSpec::nsNativeFileSpec + +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec( + short vRefNum, + long parID, + ConstStr255Param name) +//---------------------------------------------------------------------------------------- +{ + mError = ::FSMakeFSSpec(vRefNum, parID, name, &mSpec); + if (mError == fnfErr) + mError = noErr; +} + +//---------------------------------------------------------------------------------------- +nsNativeFileSpec::nsNativeFileSpec(const nsUnixFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + *this = inPath.GetNativeSpec(); +} + +#if DEBUG +//---------------------------------------------------------------------------------------- +ostream& operator << (ostream& s, const nsNativeFileSpec& spec) +//---------------------------------------------------------------------------------------- +{ + s << spec.mSpec.vRefNum << ", " << spec.mSpec.parID << ", \""; + for (int i = 1; i <= spec.mSpec.name[0]; i++) + s.put(spec.mSpec.name[i]); + return s << "\""; +} // ostream& operator << (ostream&, const nsNativeFileSpec&) +#endif // DEBUG + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator = (const std::string& inString) +//---------------------------------------------------------------------------------------- +{ + mError = MacFileHelpers::FSSpecFromFullUnixPath(inString.c_str(), mSpec, true); +} // nsNativeFileSpec::operator = + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator = (const nsNativeFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + mSpec = inSpec; + mError = inSpec.Error(); +} // nsNativeFileSpec::operator = + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::operator = (const nsUnixFilePath& inPath) +//---------------------------------------------------------------------------------------- +{ + mSpec = inPath.GetNativeSpec(); +} // nsNativeFileSpec::operator = + +//---------------------------------------------------------------------------------------- +bool nsNativeFileSpec::Exists() const +//---------------------------------------------------------------------------------------- +{ + FSSpec temp; + return ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &temp) == noErr; +} // nsNativeFileSpec::operator = + +//---------------------------------------------------------------------------------------- +void nsNativeFileSpec::SetLeafName(const std::string& inLeafName) +//---------------------------------------------------------------------------------------- +{ + *mSpec.name = inLeafName.length(); + memcpy(mSpec.name + 1, inLeafName.c_str(), 1 + *mSpec.name); +} // nsNativeFileSpec::SetLeafName + +//---------------------------------------------------------------------------------------- +std::string nsNativeFileSpec::GetLeafName() const +//---------------------------------------------------------------------------------------- +{ + char leaf[64]; + memcpy(leaf, &mSpec.name[1], mSpec.name[0]); + leaf[mSpec.name[0]] = '\0'; + return std::string(leaf); +} // nsNativeFileSpec::GetLeafName + +//======================================================================================== +// Macintosh nsUnixFilePath implementation +//======================================================================================== + +//---------------------------------------------------------------------------------------- +nsUnixFilePath::nsUnixFilePath(const nsNativeFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +#ifdef XP_MAC +: mNativeFileSpec(inSpec) +#endif +{ + char * path = MacFileHelpers::PathNameFromFSSpec( inSpec.mSpec, TRUE ); + char * unixPath = MacFileHelpers::EncodeMacPath(path, true, true); + mPath = unixPath; + delete [] unixPath; +} + +//---------------------------------------------------------------------------------------- +void nsUnixFilePath::operator = (const nsNativeFileSpec& inSpec) +//---------------------------------------------------------------------------------------- +{ + char * path = MacFileHelpers::PathNameFromFSSpec( inSpec.mSpec, TRUE ); + char * unixPath = MacFileHelpers::EncodeMacPath(path, true, true); + mPath = unixPath; + delete [] unixPath; +#ifdef XP_MAC + mNativeFileSpec = inSpec; +#endif +} // nsUnixFilePath::operator = diff --git a/mozilla/xpcom/tests/FilesTest.cpp b/mozilla/xpcom/tests/FilesTest.cpp new file mode 100644 index 00000000000..4563b2cd924 --- /dev/null +++ b/mozilla/xpcom/tests/FilesTest.cpp @@ -0,0 +1,82 @@ +#include "nsFileSpec.h" +#include + +#include "nsFileStream.h" + +namespace FileTest +{ + void WriteStuff(ostream& s); +} + +//---------------------------------------------------------------------------------------- +void FileTest::WriteStuff(ostream& s) +//---------------------------------------------------------------------------------------- +{ + // Initialize a URL from a string without suffix. Change the path to suit your machine. + nsFileURL fileURL("file:///Development/MPW/MPW%20Shell"); + s << "File URL initialized to: \"" << (string&)fileURL << "\""<< endl; + + // Initialize a Unix path from a URL + nsUnixFilePath filePath(fileURL); + s << "As a unix path: \"" << (string&)filePath << "\""<< endl; + + // Initialize a native file spec from a URL + nsNativeFileSpec fileSpec(fileURL); + s << "As a file spec: " << fileSpec << endl; + + // Make the spec unique (this one has no suffix). + fileSpec.MakeUnique(); + s << "Unique file spec: " << fileSpec << endl; + + // Assign the spec to a URL + fileURL = fileSpec; + s << "File URL assigned from spec: \"" << (string&)fileURL << "\""<< endl; + + // Assign a unix path using a string with a suffix. + filePath = "/Development/MPW/SysErrs.err"; + s << "File path reassigned to: \"" << (string&)filePath << "\""<< endl; + + // Assign to a file spec using a unix path. + fileSpec = filePath; + s << "File spec reassigned to: " << fileSpec << endl; + + // Make this unique (this one has a suffix). + fileSpec.MakeUnique(); + s << "File spec made unique: " << fileSpec << endl; +} // WriteStuff + +//---------------------------------------------------------------------------------------- +void main() +// For use with DEBUG defined. +//---------------------------------------------------------------------------------------- +{ + +#if !defined(DEBUG) || (DEBUG==0) +#error "This test only works with a DEBUG build." +#endif + // Test of nsFileSpec + + cout << "WRITING TEST OUTPUT TO cout" << endl << endl; + FileTest::WriteStuff(cout); + cout << endl << endl; + + // Test of nsOutputFileStream + + nsUnixFilePath myTextFilePath("/Development/iotest.txt"); + + cout << "WRITING IDENTICAL OUTPUT TO " << myTextFilePath << endl << endl; + nsOutputFileStream testStream(myTextFilePath); + FileTest::WriteStuff(testStream); + + // Test of nsInputFileStream + + cout << "READING BACK DATA FROM " << myTextFilePath << endl << endl; + nsInputFileStream testStream2(myTextFilePath); + char line[1000]; + while (!testStream2.eof()) + { + testStream2.getline(line, sizeof(line), '\n'); + cout << line << endl; + } + +} // main