Bug 87831 - Fizilla won't launch if its path contains non-ASCII char. r=ftang/sr=sfraser

This commit is contained in:
ccarlen%netscape.com 2001-09-28 09:19:42 +00:00
Родитель c8c44a4397
Коммит ed53a57b9a
3 изменённых файлов: 292 добавлений и 129 удалений

Просмотреть файл

@ -83,8 +83,7 @@ namespace MacFileHelpers
FSSpec& ioSpec,
Boolean inCreateDirs);
char* PathNameFromFSSpec(
const FSSpec& inSpec,
Boolean wantLeafName );
const FSSpec& inSpec );
OSErr CreateFolderInFolder(
short refNum, // Parent directory/volume
long dirID,
@ -516,100 +515,31 @@ OSErr MacFileHelpers::FSSpecFromUnixPath(
} // MacFileHelpers::FSSpecFromLocalUnixPath
//-----------------------------------
char* MacFileHelpers::PathNameFromFSSpec( const FSSpec& inSpec, Boolean wantLeafName )
char* MacFileHelpers::PathNameFromFSSpec( const FSSpec& inSpec )
// 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.
// For consistency and to work under OS X this creates an nsILocalFileMac and has it do the work.
//-----------------------------------
{
char* result = nil;
OSErr err = noErr;
short fullPathLength = 0;
Handle fullPath = nsnull;
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;
MacFileHelpers::PLstrcpy(dummyFileName, "\pG'day!");
nsresult rv;
/* 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, nsnull, 0, &tempSpec.name[1], tempSpec.name[0]);
err = MemError();
}
} while ( err == noErr && pb.dirInfo.ioDrDirID != fsRtDirID );
}
}
}
if ( err != noErr && err != fnfErr)
goto Clean;
FSSpec nonConstSpec = inSpec;
nsXPIDLCString path;
nsCOMPtr<nsILocalFileMac> macFile;
rv = NS_NewLocalFileWithFSSpec(&nonConstSpec, PR_TRUE, getter_AddRefs(macFile));
if (NS_FAILED(rv)) return nsnull;
nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(macFile, &rv));
if (NS_FAILED(rv)) return nsnull;
rv = localFile->GetPath(getter_Copies(path));
if (NS_FAILED(rv)) return nsnull;
PRInt32 strLen = path.Length();
result = new char [strLen + 1];
if (!result) return nsnull;
memcpy(result, path.get(), strLen);
result[ strLen ] = 0;
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
@ -1238,7 +1168,7 @@ const char* nsFileSpec::GetCString() const
{
if (mPath.IsEmpty())
{
char* path = MacFileHelpers::PathNameFromFSSpec(mSpec, true);
char* path = MacFileHelpers::PathNameFromFSSpec(mSpec);
if (path != NULL) {
const_cast<nsFileSpec*>(this)->mPath = path; // operator =() copies the string!!!
delete[] path;
@ -1318,7 +1248,7 @@ nsFilePath::nsFilePath(const nsFileURL& inOther)
void nsFilePath::operator = (const nsFileSpec& inSpec)
//----------------------------------------------------------------------------------------
{
char * path = MacFileHelpers::PathNameFromFSSpec(inSpec, true);
char * path = MacFileHelpers::PathNameFromFSSpec(inSpec);
path = MacFileHelpers::EncodeMacPath(path, true, false);
mPath = path;
nsCRT::free(path);
@ -1329,7 +1259,7 @@ void nsFilePath::operator = (const nsFileSpec& inSpec)
void nsFilePath::operator = (const nsFileURL& inOther)
//----------------------------------------------------------------------------------------
{
char * path = MacFileHelpers::PathNameFromFSSpec(inOther.mFileSpec, true);
char * path = MacFileHelpers::PathNameFromFSSpec(inOther.mFileSpec);
path = MacFileHelpers::EncodeMacPath(path, true, false);
mPath = path;
nsCRT::free(path);
@ -1406,7 +1336,7 @@ void nsFileURL::operator = (const nsFileSpec& inOther)
//----------------------------------------------------------------------------------------
{
mFileSpec = inOther;
char* path = MacFileHelpers::PathNameFromFSSpec( mFileSpec, true );
char* path = MacFileHelpers::PathNameFromFSSpec( mFileSpec );
char* encodedPath = MacFileHelpers::EncodeMacPath(path, true, true);
nsSimpleCharString encodedURL(kFileURLPrefix);
encodedURL += encodedPath;

Просмотреть файл

@ -59,6 +59,8 @@
#include <AppleEvents.h>
#include <AEDataModel.h>
#include <AERegistry.h>
#include <Gestalt.h>
#include <UnicodeConverter.h>
#include <Math64.h>
#include <Aliases.h>
@ -692,6 +694,171 @@ static OSErr ResolvePathAndSpec(const char * filePath, FSSpec *inSpec, PRBool cr
return err;
}
#pragma mark -
#pragma mark [nsFSStringConversionMac]
class nsFSStringConversionMac {
public:
static nsresult UCSToFS(const nsAString& aIn, nsACString& aOut);
static nsresult FSToUCS(const nsACString& ain, nsAString& aOut);
static void CleanUp();
private:
static TextEncoding GetSystemEncoding();
static nsresult PrepareEncoder();
static nsresult PrepareDecoder();
static UnicodeToTextInfo sEncoderInfo;
static TextToUnicodeInfo sDecoderInfo;
};
UnicodeToTextInfo nsFSStringConversionMac::sEncoderInfo = nsnull;
TextToUnicodeInfo nsFSStringConversionMac::sDecoderInfo = nsnull;
nsresult nsFSStringConversionMac::UCSToFS(const nsAString& aIn, nsACString& aOut)
{
nsresult rv = PrepareEncoder();
if (NS_FAILED(rv)) return rv;
OSStatus err = noErr;
char stackBuffer[512];
aOut.Truncate(0);
nsReadingIterator<PRUnichar> done_reading;
aIn.EndReading(done_reading);
// for each chunk of |aIn|...
PRUint32 fragmentLength = 0;
nsReadingIterator<PRUnichar> iter;
for (aIn.BeginReading(iter); iter != done_reading && err == noErr; iter.advance(PRInt32(fragmentLength)))
{
fragmentLength = PRUint32(iter.size_forward());
UInt32 bytesLeft = fragmentLength * sizeof(UniChar);
nsReadingIterator<PRUnichar> sub_iter(iter);
do {
UInt32 bytesRead = 0, bytesWritten = 0;
err = ::ConvertFromUnicodeToText(sEncoderInfo,
bytesLeft,
(const UniChar*)sub_iter.get(),
kUnicodeUseFallbacksMask | kUnicodeLooseMappingsMask,
0, nsnull, nsnull, nsnull,
sizeof(stackBuffer),
&bytesRead,
&bytesWritten,
stackBuffer);
if (err == kTECUsedFallbacksStatus)
err = noErr;
else if (err == kTECOutputBufferFullStatus) {
bytesLeft -= bytesRead;
sub_iter.advance(bytesRead / sizeof(UniChar));
}
aOut.Append(stackBuffer, bytesWritten);
}
while (err == kTECOutputBufferFullStatus);
}
return (err == noErr) ? NS_OK : NS_ERROR_FAILURE;
}
nsresult nsFSStringConversionMac::FSToUCS(const nsACString& aIn, nsAString& aOut)
{
nsresult rv = PrepareDecoder();
if (NS_FAILED(rv)) return rv;
OSStatus err = noErr;
UniChar stackBuffer[512];
aOut.Truncate(0);
nsReadingIterator<char> done_reading;
aIn.EndReading(done_reading);
// for each chunk of |aIn|...
PRUint32 fragmentLength = 0;
nsReadingIterator<char> iter;
for (aIn.BeginReading(iter); iter != done_reading && err == noErr; iter.advance(PRInt32(fragmentLength)))
{
fragmentLength = PRUint32(iter.size_forward());
UInt32 bytesLeft = fragmentLength;
nsReadingIterator<char> sub_iter(iter);
do {
UInt32 bytesRead = 0, bytesWritten = 0;
err = ::ConvertFromTextToUnicode(sDecoderInfo,
bytesLeft,
sub_iter.get(),
kUnicodeUseFallbacksMask | kUnicodeLooseMappingsMask,
0, nsnull, nsnull, nsnull,
sizeof(stackBuffer),
&bytesRead,
&bytesWritten,
stackBuffer);
if (err == kTECUsedFallbacksStatus)
err = noErr;
else if (err == kTECOutputBufferFullStatus) {
bytesLeft -= bytesRead;
sub_iter.advance(bytesRead);
}
aOut.Append((PRUnichar *)stackBuffer, bytesWritten / sizeof(PRUnichar));
}
while (err == kTECOutputBufferFullStatus);
}
return (err == noErr) ? NS_OK : NS_ERROR_FAILURE;
}
void nsFSStringConversionMac::CleanUp()
{
if (sDecoderInfo) {
::DisposeTextToUnicodeInfo(&sDecoderInfo);
sDecoderInfo = nsnull;
}
if (sEncoderInfo) {
::DisposeUnicodeToTextInfo(&sEncoderInfo);
sEncoderInfo = nsnull;
}
}
TextEncoding nsFSStringConversionMac::GetSystemEncoding()
{
OSStatus err;
TextEncoding theEncoding;
err = ::UpgradeScriptInfoToTextEncoding(smSystemScript, kTextLanguageDontCare,
kTextRegionDontCare, NULL, &theEncoding);
if (err != noErr)
theEncoding = kTextEncodingMacRoman;
return theEncoding;
}
nsresult nsFSStringConversionMac::PrepareEncoder()
{
nsresult rv = NS_OK;
if (!sEncoderInfo) {
OSStatus err;
err = ::CreateUnicodeToTextInfoByEncoding(GetSystemEncoding(), &sEncoderInfo);
if (err)
rv = NS_ERROR_FAILURE;
}
return rv;
}
nsresult nsFSStringConversionMac::PrepareDecoder()
{
nsresult rv = NS_OK;
if (!sDecoderInfo) {
OSStatus err;
err = ::CreateTextToUnicodeInfoByEncoding(GetSystemEncoding(), &sDecoderInfo);
if (err)
rv = NS_ERROR_FAILURE;
}
return rv;
}
#pragma mark -
#pragma mark [nsDirEnumerator]
class nsDirEnumerator : public nsISimpleEnumerator
@ -804,7 +971,8 @@ NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator)
#pragma mark -
OSType nsLocalFile::mgCurrentProcessSignature = 0;
OSType nsLocalFile::sCurrentProcessSignature = 0;
PRBool nsLocalFile::sHasHFSPlusAPIs = PR_FALSE;
#pragma mark [CTOR/DTOR]
nsLocalFile::nsLocalFile()
@ -820,9 +988,9 @@ nsLocalFile::nsLocalFile()
MakeDirty();
ClearFSSpec(mSpec);
DetermineCurrentProcessCreator();
if (mgCurrentProcessSignature != 0)
mCreator = mgCurrentProcessSignature;
InitClassStatics();
if (sCurrentProcessSignature != 0)
mCreator = sCurrentProcessSignature;
}
nsLocalFile::~nsLocalFile()
@ -1407,24 +1575,82 @@ nsLocalFile::GetPath(char **_retval)
break;
case eInitWithFSSpec:
{ // Now would be a good time to call the code that makes an FSSpec into a path
short fullPathLen;
Handle fullPathHandle;
ResolveAndStat(PR_TRUE);
(void)::FSpGetFullPath(&mResolvedSpec, &fullPathLen, &fullPathHandle);
if (!fullPathHandle)
return NS_ERROR_OUT_OF_MEMORY;
char* fullPath = (char *)nsMemory::Alloc(fullPathLen + 1);
if (!fullPath)
return NS_ERROR_OUT_OF_MEMORY;
::HLock(fullPathHandle);
nsCRT::memcpy(fullPath, *fullPathHandle, fullPathLen);
fullPath[fullPathLen] = '\0';
*_retval = fullPath;
::DisposeHandle(fullPathHandle);
{
ResolveAndStat(PR_TRUE);
#if TARGET_CARBON
if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case...
{
OSErr err;
nsresult rv;
nsAutoString ucPathString;
nsCAutoString fsCharSetPathStr;
FSRef nodeRef;
FSCatalogInfo catalogInfo;
catalogInfo.parentDirID = 0;
err = ::FSpMakeFSRef(&mResolvedSpec, &nodeRef);
if (err == fnfErr) {
FSSpec parentDirSpec;
err = GetParentFolderSpec(mResolvedSpec, parentDirSpec);
if (err == noErr) {
nsDependentCString leafName((char *)&mResolvedSpec.name[1], PRUint32(mResolvedSpec.name[0]));
nsFSStringConversionMac::FSToUCS(leafName, ucPathString);
err = ::FSpMakeFSRef(&parentDirSpec, &nodeRef);
}
}
while (err == noErr && catalogInfo.parentDirID != fsRtParID) {
HFSUniStr255 nodeName;
FSRef parentRef;
err = ::FSGetCatalogInfo(&nodeRef,
kFSCatInfoNodeFlags + kFSCatInfoParentDirID,
&catalogInfo,
&nodeName,
nsnull,
&parentRef);
if (err == noErr)
{
if (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)
nodeName.unicode[nodeName.length++] = PRUnichar(':');
nsDependentString nodeNameStr((PRUnichar *)nodeName.unicode, (PRUint32)nodeName.length);
ucPathString.Insert(nodeNameStr, 0);
nodeRef = parentRef;
}
}
rv = MacErrorMapper(err);
if (NS_FAILED(rv))
return rv;
rv = nsFSStringConversionMac::UCSToFS(ucPathString, fsCharSetPathStr);
if (NS_FAILED(rv))
return rv;
// When nsIFile params are all nsAString&, we won't have to do this
*_retval = fsCharSetPathStr.ToNewCString();
if (!*_retval)
return NS_ERROR_OUT_OF_MEMORY;
}
else
#endif
{
// Now would be a good time to call the code that makes an FSSpec into a path
short fullPathLen;
Handle fullPathHandle;
(void)::FSpGetFullPath(&mResolvedSpec, &fullPathLen, &fullPathHandle);
if (!fullPathHandle)
return NS_ERROR_OUT_OF_MEMORY;
char* fullPath = (char *)nsMemory::Alloc(fullPathLen + 1);
if (!fullPath)
return NS_ERROR_OUT_OF_MEMORY;
::HLock(fullPathHandle);
nsCRT::memcpy(fullPath, *fullPathHandle, fullPathLen);
fullPath[fullPathLen] = '\0';
*_retval = fullPath;
::DisposeHandle(fullPathHandle);
}
break;
}
@ -2911,7 +3137,7 @@ NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreator(OSType type, OSType creator)
return NS_ERROR_FILE_NOT_FOUND;
if (creator == CURRENT_PROCESS_CREATOR)
creator = (mgCurrentProcessSignature != 0) ? mgCurrentProcessSignature : kDefaultCreator;
creator = (sCurrentProcessSignature != 0) ? sCurrentProcessSignature : kDefaultCreator;
// See if the user specified a type or creator before changing from what was read
if (type)
@ -3128,13 +3354,13 @@ nsresult nsLocalFile::ExtensionIsOnExceptionList(const char *extension, PRBool *
}
nsresult nsLocalFile::DetermineCurrentProcessCreator()
void nsLocalFile::InitClassStatics()
{
nsresult rv = NS_OK;
OSErr err;
if (mgCurrentProcessSignature == 0)
if (sCurrentProcessSignature == 0)
{
OSErr err;
ProcessSerialNumber psn;
ProcessInfoRec info;
@ -3146,14 +3372,21 @@ nsresult nsLocalFile::DetermineCurrentProcessCreator()
info.processAppSpec = nil;
err = ::GetProcessInformation(&psn, &info);
if (err == noErr)
mgCurrentProcessSignature = info.processSignature;
sCurrentProcessSignature = info.processSignature;
// Try again next time if error
else
rv = MacErrorMapper(err);
}
return NS_OK;
static PRBool didHFSPlusCheck = PR_FALSE;
if (!didHFSPlusCheck)
{
long response;
err = ::Gestalt(gestaltFSAttr, &response);
sHasHFSPlusAPIs = (err == noErr && (response & (1 << gestaltHasHFSPlusAPIs)) != 0);
didHFSPlusCheck = PR_TRUE;
}
}
#pragma mark -
// Handy dandy utility create routine for something or the other

Просмотреть файл

@ -103,9 +103,7 @@ protected:
nsresult SetOSTypeAndCreatorFromExtension(const char* extension = nsnull);
nsresult ExtensionIsOnExceptionList(const char *extension, PRBool *onList);
static nsresult DetermineCurrentProcessCreator();
private:
// It's important we keep track of how we were initialized
@ -143,8 +141,10 @@ private:
OSType mType, mCreator;
static OSType mgCurrentProcessSignature;
static void InitClassStatics();
static OSType sCurrentProcessSignature;
static PRBool sHasHFSPlusAPIs;
};
#endif