Fix for bugs 15795 and 16090 -- fix startup crash which was due to an uninitialized nsFileSpec trashing the stack. Also no longer set mError on CreateDirectory if the dir already exists, prevent += "foo" when mError is set, and add assertions XP to catch calls with NULL strings.
reviewed by dougt and (in part) sspitzer. a=leaf. git-svn-id: svn://10.0.0.236/trunk@50360 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -30,6 +30,11 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef XP_MAC
|
||||
#include <Aliases.h>
|
||||
#include <TextUtils.h>
|
||||
#endif
|
||||
|
||||
//========================================================================================
|
||||
// class nsSimpleCharString
|
||||
//========================================================================================
|
||||
@@ -252,6 +257,7 @@ void nsSimpleCharString::ReallocData(PRUint32 inLength)
|
||||
mData->mLength = inLength;
|
||||
} // nsSimpleCharString::ReleaseData
|
||||
|
||||
|
||||
//========================================================================================
|
||||
NS_NAMESPACE nsFileSpecHelpers
|
||||
//========================================================================================
|
||||
@@ -362,6 +368,11 @@ char* nsSimpleCharString::GetLeaf(char inSeparator) const
|
||||
return result;
|
||||
} // nsSimpleCharString::GetLeaf
|
||||
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
@@ -437,10 +448,15 @@ void nsFileSpecHelpers::MakeAllDirectories(const char* inPath, int mode)
|
||||
|
||||
#endif // XP_PC || XP_UNIX
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
#if defined(XP_PC)
|
||||
#include "nsFileSpecWin.cpp" // Windows-specific implementations
|
||||
#elif defined(XP_MAC)
|
||||
#include "nsFileSpecMac.cpp" // Macintosh-specific implementations
|
||||
//#include "nsFileSpecMac.cpp" // Macintosh-specific implementations
|
||||
// we include the .cpp file in the project now.
|
||||
#elif defined(XP_BEOS)
|
||||
#include "nsFileSpecBeOS.cpp" // BeOS-specific implementations
|
||||
#elif defined(XP_UNIX)
|
||||
@@ -602,6 +618,10 @@ void nsFileURL::operator = (const nsFileSpec& inOther)
|
||||
} // nsFileURL::operator =
|
||||
#endif
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
//========================================================================================
|
||||
// nsFilePath implementation
|
||||
//========================================================================================
|
||||
@@ -741,6 +761,8 @@ void nsFilePath::operator = (const nsFilePath& inOther)
|
||||
void nsFilePath::operator +=(const char* inRelativeUnixPath)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
NS_ASSERTION(inRelativeUnixPath, "Attempt append relative path with null path");
|
||||
|
||||
char* escapedPath = nsEscape(inRelativeUnixPath, url_Path);
|
||||
mPath += escapedPath;
|
||||
nsCRT::free(escapedPath);
|
||||
@@ -753,11 +775,18 @@ void nsFilePath::operator +=(const char* inRelativeUnixPath)
|
||||
nsFilePath nsFilePath::operator +(const char* inRelativeUnixPath) const
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
nsFilePath result(*this);
|
||||
result += inRelativeUnixPath;
|
||||
return result;
|
||||
NS_ASSERTION(inRelativeUnixPath, "Attempt append relative path with null path");
|
||||
|
||||
nsFilePath resultPath(*this);
|
||||
resultPath += inRelativeUnixPath;
|
||||
return resultPath;
|
||||
} // nsFilePath::operator +
|
||||
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
//========================================================================================
|
||||
// nsFileSpec implementation
|
||||
//========================================================================================
|
||||
@@ -766,11 +795,27 @@ nsFilePath nsFilePath::operator +(const char* inRelativeUnixPath) const
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsFileSpec::nsFileSpec()
|
||||
//----------------------------------------------------------------------------------------
|
||||
: mError(NS_OK)
|
||||
: mError(NS_OK) // XXX shouldn't this be NS_ERROR_NOT_INITIALIZED?
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
void nsFileSpec::Clear()
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
mPath.SetToEmpty();
|
||||
mError = NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsFileSpec::~nsFileSpec()
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
// mPath cleans itself up
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsFileSpec::nsFileSpec(const nsPersistentFileDescriptor& inDescriptor)
|
||||
//----------------------------------------------------------------------------------------
|
||||
@@ -876,9 +921,7 @@ nsFileSpec::nsFileSpec(const nsFilePath& inPath)
|
||||
, mError(NS_OK)
|
||||
{
|
||||
}
|
||||
#endif // XP_UNIX
|
||||
|
||||
#if defined XP_UNIX || defined XP_BEOS
|
||||
//----------------------------------------------------------------------------------------
|
||||
void nsFileSpec::operator = (const nsFilePath& inPath)
|
||||
//----------------------------------------------------------------------------------------
|
||||
@@ -896,9 +939,7 @@ nsFileSpec::nsFileSpec(const nsFileSpec& inSpec)
|
||||
, mError(NS_OK)
|
||||
{
|
||||
}
|
||||
#endif //XP_UNIX
|
||||
|
||||
#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsFileSpec::nsFileSpec(const char* inString, PRBool inCreateDirs)
|
||||
//----------------------------------------------------------------------------------------
|
||||
@@ -908,9 +949,7 @@ nsFileSpec::nsFileSpec(const char* inString, PRBool inCreateDirs)
|
||||
// Make canonical and absolute.
|
||||
nsFileSpecHelpers::Canonify(mPath, inCreateDirs);
|
||||
}
|
||||
#endif //XP_UNIX,PC
|
||||
|
||||
#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsFileSpec::nsFileSpec(const nsString& inString, PRBool inCreateDirs)
|
||||
//----------------------------------------------------------------------------------------
|
||||
@@ -920,15 +959,7 @@ nsFileSpec::nsFileSpec(const nsString& inString, PRBool inCreateDirs)
|
||||
// Make canonical and absolute.
|
||||
nsFileSpecHelpers::Canonify(mPath, inCreateDirs);
|
||||
}
|
||||
#endif //XP_UNIX,PC
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsFileSpec::~nsFileSpec()
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
|
||||
//----------------------------------------------------------------------------------------
|
||||
void nsFileSpec::operator = (const nsFileSpec& inSpec)
|
||||
//----------------------------------------------------------------------------------------
|
||||
@@ -936,10 +967,7 @@ void nsFileSpec::operator = (const nsFileSpec& inSpec)
|
||||
mPath = inSpec.mPath;
|
||||
mError = inSpec.Error();
|
||||
}
|
||||
#endif //XP_UNIX
|
||||
|
||||
|
||||
#if defined(XP_UNIX) || defined(XP_PC) || defined(XP_BEOS)
|
||||
//----------------------------------------------------------------------------------------
|
||||
void nsFileSpec::operator = (const char* inString)
|
||||
//----------------------------------------------------------------------------------------
|
||||
@@ -949,15 +977,17 @@ void nsFileSpec::operator = (const char* inString)
|
||||
nsFileSpecHelpers::Canonify(mPath, PR_FALSE /* XXX? */);
|
||||
mError = NS_OK;
|
||||
}
|
||||
#endif //XP_UNIX
|
||||
#endif //XP_UNIX,PC,XP_BEOS
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsFileSpec nsFileSpec::operator + (const char* inRelativePath) const
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
nsFileSpec result = *this;
|
||||
result += inRelativePath;
|
||||
return result;
|
||||
NS_ASSERTION(inRelativePath, "Attempt to append name with a null string");
|
||||
|
||||
nsFileSpec resultSpec = *this;
|
||||
resultSpec += inRelativePath;
|
||||
return resultSpec;
|
||||
} // nsFileSpec::operator +
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
@@ -1015,22 +1045,23 @@ PRBool nsFileSpec::operator != (const nsFileSpec& inOther) const
|
||||
|
||||
#ifndef XP_MAC
|
||||
//----------------------------------------------------------------------------------------
|
||||
const char* nsFileSpec::GetCString() const
|
||||
// This is the only automatic conversion to const char*
|
||||
// that is provided, and it allows the
|
||||
// path to be "passed" to NSPR file routines. This practice
|
||||
// is VERY EVIL and should only be used to support legacy
|
||||
// code. Using it guarantees bugs on Macintosh. The path is NOT allocated, so do
|
||||
// not even think of deleting (or freeing) it.
|
||||
const char* nsFileSpec::GetCString() const
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Is our spec a child of the provided parent? */
|
||||
PRBool
|
||||
nsFileSpec::IsChildOf(nsFileSpec &possibleParent)
|
||||
//----------------------------------------------------------------------------------------
|
||||
// Is our spec a child of the provided parent?
|
||||
PRBool nsFileSpec::IsChildOf(nsFileSpec &possibleParent)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
nsFileSpec iter = *this, parent;
|
||||
#ifdef DEBUG
|
||||
@@ -1059,10 +1090,13 @@ nsFileSpec::IsChildOf(nsFileSpec &possibleParent)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* not reached, but I bet some compiler will whine */
|
||||
// not reached, but I bet some compiler will whine
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
||||
//========================================================================================
|
||||
// class nsPersistentFileDescriptor
|
||||
|
||||
@@ -328,22 +328,27 @@ class NS_COM nsFileSpec
|
||||
PRBool operator ==(const nsFileSpec& inOther) const;
|
||||
PRBool operator !=(const nsFileSpec& inOther) const;
|
||||
|
||||
operator const char* () const { return GetCString(); }
|
||||
// Same as GetCString (please read the comments).
|
||||
// Do not try to free this!
|
||||
const char* GetNativePathCString() const { return GetCString(); }
|
||||
// Same as GetCString (please read the comments).
|
||||
// Do not try to free this!
|
||||
|
||||
// Returns a native path, and allows the
|
||||
// path to be "passed" to legacy code. This practice
|
||||
// is VERY EVIL and should only be used to support legacy
|
||||
// code. Using it guarantees bugs on Macintosh.
|
||||
// The path is cached and freed by the nsFileSpec destructor
|
||||
// so do not delete (or free) it. See also nsNSPRPath below,
|
||||
// if you really must pass a string to PR_OpenFile().
|
||||
// Doing so will introduce two automatic bugs.
|
||||
const char* GetCString() const;
|
||||
// Returns a native path, and allows the
|
||||
// path to be "passed" to legacy code. This practice
|
||||
// is VERY EVIL and should only be used to support legacy
|
||||
// code. Using it guarantees bugs on Macintosh.
|
||||
// The path is cached and freed by the nsFileSpec destructor
|
||||
// so do not delete (or free) it. See also nsNSPRPath below,
|
||||
// if you really must pass a string to PR_OpenFile().
|
||||
// Doing so will introduce two automatic bugs.
|
||||
PRBool IsChildOf(nsFileSpec &possibleParent);
|
||||
|
||||
// Same as GetCString (please read the comments).
|
||||
// Do not try to free this!
|
||||
operator const char* () const { return GetCString(); }
|
||||
|
||||
// Same as GetCString (please read the comments).
|
||||
// Do not try to free this!
|
||||
const char* GetNativePathCString() const { return GetCString(); }
|
||||
|
||||
|
||||
PRBool IsChildOf(nsFileSpec &possibleParent);
|
||||
|
||||
#ifdef XP_MAC
|
||||
// For Macintosh people, this is meant to be useful in its own right as a C++ version
|
||||
@@ -372,10 +377,10 @@ class NS_COM nsFileSpec
|
||||
ConstStr255Param GetLeafPName() const { return mSpec.name; }
|
||||
|
||||
OSErr GetCatInfo(CInfoPBRec& outInfo) const;
|
||||
#if DOUGT_UNTESTED
|
||||
|
||||
OSErr SetFileTypeAndCreator(OSType type, OSType creator);
|
||||
OSErr GetFileTypeAndCreator(OSType* type, OSType* creator);
|
||||
#endif
|
||||
|
||||
#endif // end of Macintosh utility methods.
|
||||
|
||||
PRBool Valid() const { return NS_SUCCEEDED(Error()); }
|
||||
@@ -394,33 +399,46 @@ class NS_COM nsFileSpec
|
||||
//--------------------------------------------------
|
||||
|
||||
char* GetLeafName() const; // Allocated. Use nsCRT::free().
|
||||
|
||||
#if 0
|
||||
// needs implementing
|
||||
// copy the leaf name into the supplied buffer, thus
|
||||
// getting a copy without allocation. Buffer should be
|
||||
// 64 chars big.
|
||||
void GetLeafNameCopy(char* destBuffer, PRInt32 bufferSize) const;
|
||||
#endif
|
||||
// inLeafName can be a relative path, so this allows
|
||||
// one kind of concatenation of "paths".
|
||||
void SetLeafName(const char* inLeafName);
|
||||
// inLeafName can be a relative path, so this allows
|
||||
// one kind of concatenation of "paths".
|
||||
void SetLeafName(const nsString& inLeafName)
|
||||
{
|
||||
const nsAutoCString leafName(inLeafName);
|
||||
SetLeafName(leafName);
|
||||
}
|
||||
void GetParent(nsFileSpec& outSpec) const;
|
||||
// Return the filespec of the parent directory. Used
|
||||
// in conjunction with GetLeafName(), this lets you
|
||||
// parse a path into a list of node names. Beware,
|
||||
// however, that the top node is still not a name,
|
||||
// but a spec. Volumes on Macintosh can have identical
|
||||
// names. Perhaps could be used for an operator --() ?
|
||||
|
||||
typedef PRUint32 TimeStamp; // ie nsFileSpec::TimeStamp. This is 32 bits now,
|
||||
// but might change, eg, to a 64-bit class. So use the
|
||||
// typedef, and use a streaming operator to convert
|
||||
// to a string, so that your code won't break. It's
|
||||
// none of your business what the number means. Don't
|
||||
// rely on the implementation.
|
||||
// Return the filespec of the parent directory. Used
|
||||
// in conjunction with GetLeafName(), this lets you
|
||||
// parse a path into a list of node names. Beware,
|
||||
// however, that the top node is still not a name,
|
||||
// but a spec. Volumes on Macintosh can have identical
|
||||
// names. Perhaps could be used for an operator --() ?
|
||||
void GetParent(nsFileSpec& outSpec) const;
|
||||
|
||||
|
||||
// ie nsFileSpec::TimeStamp. This is 32 bits now,
|
||||
// but might change, eg, to a 64-bit class. So use the
|
||||
// typedef, and use a streaming operator to convert
|
||||
// to a string, so that your code won't break. It's
|
||||
// none of your business what the number means. Don't
|
||||
// rely on the implementation.
|
||||
typedef PRUint32 TimeStamp;
|
||||
|
||||
// This will return different values on different
|
||||
// platforms, even for the same file (eg, on a server).
|
||||
// But if the platform is constant, it will increase after
|
||||
// every file modification.
|
||||
void GetModDate(TimeStamp& outStamp) const;
|
||||
// This will return different values on different
|
||||
// platforms, even for the same file (eg, on a server).
|
||||
// But if the platform is constant, it will increase after
|
||||
// every file modification.
|
||||
|
||||
PRBool ModDateChanged(const TimeStamp& oldStamp) const
|
||||
{
|
||||
TimeStamp newStamp;
|
||||
@@ -438,15 +456,17 @@ class NS_COM nsFileSpec
|
||||
relativePath(inRelativeUnixPath);
|
||||
return *this + relativePath;
|
||||
}
|
||||
|
||||
// Concatenate the relative path to this directory.
|
||||
// Used for constructing the filespec of a descendant.
|
||||
// This must be a directory for this to work. This differs
|
||||
// from SetLeafName(), since the latter will work
|
||||
// starting with a sibling of the directory and throws
|
||||
// away its leaf information, whereas this one assumes
|
||||
// this is a directory, and the relative path starts
|
||||
// "below" this.
|
||||
void operator += (const char* inRelativeUnixPath);
|
||||
// Concatenate the relative path to this directory.
|
||||
// Used for constructing the filespec of a descendant.
|
||||
// This must be a directory for this to work. This differs
|
||||
// from SetLeafName(), since the latter will work
|
||||
// starting with a sibling of the directory and throws
|
||||
// away its leaf information, whereas this one assumes
|
||||
// this is a directory, and the relative path starts
|
||||
// "below" this.
|
||||
|
||||
void operator += (const nsString& inRelativeUnixPath)
|
||||
{
|
||||
const nsAutoCString relativePath(inRelativeUnixPath);
|
||||
@@ -461,22 +481,22 @@ class NS_COM nsFileSpec
|
||||
MakeUnique(suggestedLeafName);
|
||||
}
|
||||
|
||||
PRBool IsDirectory() const;
|
||||
// More stringent than Exists()
|
||||
PRBool IsFile() const;
|
||||
// More stringent than Exists()
|
||||
|
||||
PRBool IsDirectory() const; // More stringent than Exists()
|
||||
PRBool IsFile() const; // More stringent than Exists()
|
||||
PRBool Exists() const;
|
||||
|
||||
PRBool IsHidden() const;
|
||||
|
||||
PRBool IsSymlink() const;
|
||||
|
||||
//--------------------------------------------------
|
||||
// Creation and deletion of objects. These can modify the disk.
|
||||
//--------------------------------------------------
|
||||
|
||||
// Called for the spec of an alias. Modifies the spec to
|
||||
// point to the original. Sets mError.
|
||||
nsresult ResolveSymlink(PRBool& wasSymlink);
|
||||
// Called for the spec of an alias. Modifies the spec to
|
||||
// point to the original. Sets mError.
|
||||
|
||||
void CreateDirectory(int mode = 0700 /* for unix */);
|
||||
void CreateDir(int mode = 0700) { CreateDirectory(mode); }
|
||||
@@ -498,11 +518,17 @@ class NS_COM nsFileSpec
|
||||
const nsAutoCString argsString(args);
|
||||
return Execute(argsString);
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// Data
|
||||
//--------------------------------------------------
|
||||
|
||||
protected:
|
||||
|
||||
// Clear the nsFileSpec contents, resetting it
|
||||
// to the uninitialized state;
|
||||
void Clear();
|
||||
|
||||
friend class nsFilePath;
|
||||
friend class nsFileURL;
|
||||
friend class nsDirectoryIterator;
|
||||
@@ -511,6 +537,7 @@ class NS_COM nsFileSpec
|
||||
#endif
|
||||
nsSimpleCharString mPath;
|
||||
nsresult mError;
|
||||
|
||||
}; // class nsFileSpec
|
||||
|
||||
// FOR HISTORICAL REASONS:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,21 @@
|
||||
/* -*- 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 "nsFileSpecStreaming.h"
|
||||
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
@@ -248,6 +248,8 @@ void nsFileSpec::GetParent(nsFileSpec& outSpec) const
|
||||
void nsFileSpec::operator += (const char* inRelativePath)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
NS_ASSERTION(inRelativePath, "Attempt to do += with a null string");
|
||||
|
||||
if (!inRelativePath || mPath.IsEmpty())
|
||||
return;
|
||||
|
||||
@@ -339,6 +341,8 @@ void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const
|
||||
nsresult nsFileSpec::Rename(const char* inNewName)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
NS_ASSERTION(inNewName, "Attempt to Rename with a null string");
|
||||
|
||||
// This function should not be used to move a file on disk.
|
||||
if (mPath.IsEmpty() || strchr(inNewName, '/'))
|
||||
return NS_FILE_FAILURE;
|
||||
|
||||
@@ -175,6 +175,7 @@ void nsFilePath::operator = (const nsFileSpec& inSpec)
|
||||
void nsFileSpec::SetLeafName(const char* inLeafName)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
NS_ASSERTION(inLeafName, "Attempt to SetLeafName with a null string");
|
||||
mPath.LeafReplace('\\', inLeafName);
|
||||
} // nsFileSpec::SetLeafName
|
||||
|
||||
@@ -374,6 +375,8 @@ void nsFileSpec::GetParent(nsFileSpec& outSpec) const
|
||||
void nsFileSpec::operator += (const char* inRelativePath)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
NS_ASSERTION(inRelativePath, "Attempt to do += with a null string");
|
||||
|
||||
if (!inRelativePath || mPath.IsEmpty())
|
||||
return;
|
||||
|
||||
@@ -468,6 +471,8 @@ void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const
|
||||
nsresult nsFileSpec::Rename(const char* inNewName)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
NS_ASSERTION(inNewName, "Attempt to Rename with a null string");
|
||||
|
||||
// This function should not be used to move a file on disk.
|
||||
if (strchr(inNewName, '/'))
|
||||
return NS_FILE_FAILURE;
|
||||
|
||||
@@ -44,185 +44,46 @@ class FileImpl
|
||||
//========================================================================================
|
||||
{
|
||||
public:
|
||||
FileImpl(PRFileDesc* inDesc)
|
||||
: mFileDesc(inDesc)
|
||||
, mNSPRMode(0)
|
||||
, mFailed(PR_FALSE)
|
||||
, mEOF(PR_FALSE)
|
||||
, mLength(-1)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
FileImpl(PRFileDesc* inDesc);
|
||||
FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode);
|
||||
|
||||
nsresult rv = mOutBuffer.Init(4096, 4096);
|
||||
if (NS_FAILED(rv)) mFailed = PR_TRUE;
|
||||
|
||||
mWriteCursor = nsnull;
|
||||
mWriteLimit = nsnull;
|
||||
|
||||
}
|
||||
FileImpl(
|
||||
const nsFileSpec& inFile,
|
||||
int nsprMode,
|
||||
PRIntn accessMode)
|
||||
: mFileDesc(nsnull)
|
||||
, mNSPRMode(-1)
|
||||
, mFailed(PR_FALSE)
|
||||
, mEOF(PR_FALSE)
|
||||
, mLength(-1)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
nsresult rv = mOutBuffer.Init(4096, 4096);
|
||||
if (NS_FAILED(rv)) mFailed = PR_TRUE;
|
||||
|
||||
mWriteCursor = nsnull;
|
||||
mWriteLimit = nsnull;
|
||||
|
||||
rv = Open(inFile, nsprMode, accessMode);
|
||||
/// NS_ASSERTION(NS_SUCCEEDED(rv), "Open failed");
|
||||
}
|
||||
virtual ~FileImpl()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
virtual ~FileImpl();
|
||||
// nsISupports interface
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIOpenFile interface
|
||||
NS_IMETHOD Open(
|
||||
const nsFileSpec& inFile,
|
||||
int nsprMode,
|
||||
PRIntn accessMode);
|
||||
// nsIOpenFile interface
|
||||
NS_IMETHOD Open(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode);
|
||||
NS_IMETHOD Close();
|
||||
NS_IMETHOD Seek(PRSeekWhence whence, PRInt32 offset);
|
||||
|
||||
NS_IMETHOD GetIsOpen(PRBool* outOpen)
|
||||
{
|
||||
*outOpen = (mFileDesc != nsnull);
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD GetIsOpen(PRBool* outOpen);
|
||||
NS_IMETHOD Tell(PRIntn* outWhere);
|
||||
|
||||
// nsIInputStream interface
|
||||
NS_IMETHOD Available(PRUint32 *aLength)
|
||||
{
|
||||
NS_PRECONDITION(aLength != nsnull, "null ptr");
|
||||
if (!aLength)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (mLength < 0)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
*aLength = mLength;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD Read(char* aBuf,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aReadCount)
|
||||
{
|
||||
NS_PRECONDITION(aBuf != nsnull, "null ptr");
|
||||
if (!aBuf)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
NS_PRECONDITION(aReadCount != nsnull, "null ptr");
|
||||
if (!aReadCount)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (!mFileDesc)
|
||||
return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
|
||||
if (mFailed)
|
||||
return NS_ERROR_FAILURE;
|
||||
PRInt32 bytesRead = PR_Read(mFileDesc, aBuf, aCount);
|
||||
if (bytesRead < 0)
|
||||
{
|
||||
*aReadCount = 0;
|
||||
mFailed = PR_TRUE;
|
||||
return NS_FILE_RESULT(PR_GetError());
|
||||
}
|
||||
else if (bytesRead == 0) {
|
||||
mEOF = PR_TRUE;
|
||||
}
|
||||
*aReadCount = bytesRead;
|
||||
return NS_OK;
|
||||
}
|
||||
// nsIOutputStream interface
|
||||
NS_IMETHOD Write(const char* aBuf,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aWriteCount)
|
||||
{
|
||||
NS_PRECONDITION(aBuf != nsnull, "null ptr");
|
||||
NS_PRECONDITION(aWriteCount != nsnull, "null ptr");
|
||||
|
||||
*aWriteCount = 0;
|
||||
// nsIInputStream interface
|
||||
NS_IMETHOD Available(PRUint32 *aLength);
|
||||
NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount);
|
||||
|
||||
#ifdef XP_MAC
|
||||
// Calling PR_Write on stdout is sure suicide.
|
||||
if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR)
|
||||
{
|
||||
cout.write(aBuf, aCount);
|
||||
*aWriteCount = aCount;
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
if (!mFileDesc)
|
||||
return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
|
||||
if (mFailed)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PRUint32 bufOffset = 0;
|
||||
PRUint32 currentWrite = 0;
|
||||
while (aCount > 0)
|
||||
{
|
||||
if (mWriteCursor == nsnull || mWriteCursor == mWriteLimit)
|
||||
{
|
||||
char* seg = mOutBuffer.AppendNewSegment();
|
||||
if (seg == nsnull)
|
||||
{
|
||||
// buffer is full, try again
|
||||
Flush();
|
||||
seg = mOutBuffer.AppendNewSegment();
|
||||
if (seg == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mWriteCursor = seg;
|
||||
mWriteLimit = seg + mOutBuffer.GetSegmentSize();
|
||||
}
|
||||
|
||||
// move
|
||||
|
||||
currentWrite = mWriteLimit - mWriteCursor;
|
||||
|
||||
if (aCount < currentWrite)
|
||||
currentWrite = aCount;
|
||||
|
||||
memcpy(mWriteCursor, (aBuf + bufOffset), currentWrite);
|
||||
|
||||
mWriteCursor += currentWrite;
|
||||
|
||||
aCount -= currentWrite;
|
||||
bufOffset += currentWrite;
|
||||
*aWriteCount += currentWrite;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
// nsIOutputStream interface
|
||||
NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount);
|
||||
NS_IMETHOD Flush();
|
||||
|
||||
NS_IMETHOD GetAtEOF(PRBool* outAtEOF)
|
||||
{
|
||||
*outAtEOF = mEOF;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD SetAtEOF(PRBool inAtEOF)
|
||||
{
|
||||
mEOF = inAtEOF;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD GetAtEOF(PRBool* outAtEOF);
|
||||
NS_IMETHOD SetAtEOF(PRBool inAtEOF);
|
||||
|
||||
protected:
|
||||
|
||||
enum {
|
||||
kOuputBufferSegmentSize = 4096,
|
||||
kOuputBufferMaxSize = 4096
|
||||
};
|
||||
|
||||
nsresult AllocateBuffers(PRUint32 segmentSize, PRUint32 maxSize);
|
||||
|
||||
PRFileDesc* mFileDesc;
|
||||
int mNSPRMode;
|
||||
PRBool mFailed;
|
||||
PRBool mEOF;
|
||||
PRInt32 mLength;
|
||||
|
||||
PRBool mGotBuffers;
|
||||
nsSegmentedBuffer mOutBuffer;
|
||||
char* mWriteCursor;
|
||||
char* mWriteLimit;
|
||||
@@ -245,6 +106,60 @@ NS_IMPL_QUERY_HEAD(FileImpl)
|
||||
NS_IMPL_QUERY_TAIL(nsIOutputStream)
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
FileImpl::FileImpl(PRFileDesc* inDesc)
|
||||
//----------------------------------------------------------------------------------------
|
||||
: mFileDesc(inDesc)
|
||||
, mNSPRMode(0)
|
||||
, mFailed(PR_FALSE)
|
||||
, mEOF(PR_FALSE)
|
||||
, mLength(-1)
|
||||
, mGotBuffers(PR_FALSE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
mWriteCursor = nsnull;
|
||||
mWriteLimit = nsnull;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
FileImpl::FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode)
|
||||
//----------------------------------------------------------------------------------------
|
||||
: mFileDesc(nsnull)
|
||||
, mNSPRMode(-1)
|
||||
, mFailed(PR_FALSE)
|
||||
, mEOF(PR_FALSE)
|
||||
, mLength(-1)
|
||||
, mGotBuffers(PR_FALSE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
||||
mWriteCursor = nsnull;
|
||||
mWriteLimit = nsnull;
|
||||
|
||||
nsresult rv = Open(inFile, nsprMode, accessMode); // this sets nsprMode
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
#if DEBUG
|
||||
char *fileName = inFile.GetLeafName();
|
||||
printf("Opening file %s failed\n", fileName);
|
||||
nsCRT::free(fileName);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
FileImpl::~FileImpl()
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
nsresult rv = Close();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Close failed");
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP FileImpl::Open(
|
||||
const nsFileSpec& inFile,
|
||||
@@ -286,8 +201,8 @@ NS_IMETHODIMP FileImpl::Open(
|
||||
mFileDesc = 0;
|
||||
OSErr err = inFile.Error();
|
||||
if (err != noErr)
|
||||
if (err != fnfErr || !(nsprMode & PR_CREATE_FILE))
|
||||
return NS_FILE_RESULT(inFile.Error());
|
||||
if (err != fnfErr || !(nsprMode & PR_CREATE_FILE))
|
||||
return NS_FILE_RESULT(inFile.Error());
|
||||
err = noErr;
|
||||
#if DEBUG
|
||||
const OSType kCreator = 'CWIE';
|
||||
@@ -338,6 +253,28 @@ NS_IMETHODIMP FileImpl::Open(
|
||||
return NS_OK;
|
||||
} // FileImpl::Open
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP FileImpl::Available(PRUint32 *aLength)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
NS_PRECONDITION(aLength != nsnull, "null ptr");
|
||||
if (!aLength)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (mLength < 0)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
*aLength = mLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP FileImpl::GetIsOpen(PRBool* outOpen)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
*outOpen = (mFileDesc != nsnull);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP FileImpl::Seek(PRSeekWhence whence, PRInt32 offset)
|
||||
//----------------------------------------------------------------------------------------
|
||||
@@ -371,6 +308,105 @@ NS_IMETHODIMP FileImpl::Seek(PRSeekWhence whence, PRInt32 offset)
|
||||
return NS_OK;
|
||||
} // FileImpl::Seek
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP FileImpl::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
NS_PRECONDITION(aBuf != nsnull, "null ptr");
|
||||
if (!aBuf)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
NS_PRECONDITION(aReadCount != nsnull, "null ptr");
|
||||
if (!aReadCount)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (!mFileDesc)
|
||||
return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
|
||||
if (mFailed)
|
||||
return NS_ERROR_FAILURE;
|
||||
PRInt32 bytesRead = PR_Read(mFileDesc, aBuf, aCount);
|
||||
if (bytesRead < 0)
|
||||
{
|
||||
*aReadCount = 0;
|
||||
mFailed = PR_TRUE;
|
||||
return NS_FILE_RESULT(PR_GetError());
|
||||
}
|
||||
else if (bytesRead == 0)
|
||||
{
|
||||
mEOF = PR_TRUE;
|
||||
}
|
||||
*aReadCount = bytesRead;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP FileImpl::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
NS_PRECONDITION(aBuf != nsnull, "null ptr");
|
||||
NS_PRECONDITION(aWriteCount != nsnull, "null ptr");
|
||||
|
||||
*aWriteCount = 0;
|
||||
|
||||
#ifdef XP_MAC
|
||||
// Calling PR_Write on stdout is sure suicide.
|
||||
if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR)
|
||||
{
|
||||
cout.write(aBuf, aCount);
|
||||
*aWriteCount = aCount;
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
if (!mFileDesc)
|
||||
return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
|
||||
if (mFailed)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!mGotBuffers)
|
||||
{
|
||||
nsresult rv = AllocateBuffers(kOuputBufferSegmentSize, kOuputBufferMaxSize);
|
||||
if (NS_FAILED(rv))
|
||||
return rv; // try to write non-buffered?
|
||||
}
|
||||
|
||||
PRUint32 bufOffset = 0;
|
||||
PRUint32 currentWrite = 0;
|
||||
while (aCount > 0)
|
||||
{
|
||||
if (mWriteCursor == nsnull || mWriteCursor == mWriteLimit)
|
||||
{
|
||||
char* seg = mOutBuffer.AppendNewSegment();
|
||||
if (seg == nsnull)
|
||||
{
|
||||
// buffer is full, try again
|
||||
Flush();
|
||||
seg = mOutBuffer.AppendNewSegment();
|
||||
if (seg == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
mWriteCursor = seg;
|
||||
mWriteLimit = seg + mOutBuffer.GetSegmentSize();
|
||||
}
|
||||
|
||||
// move
|
||||
currentWrite = mWriteLimit - mWriteCursor;
|
||||
|
||||
if (aCount < currentWrite)
|
||||
currentWrite = aCount;
|
||||
|
||||
memcpy(mWriteCursor, (aBuf + bufOffset), currentWrite);
|
||||
|
||||
mWriteCursor += currentWrite;
|
||||
|
||||
aCount -= currentWrite;
|
||||
bufOffset += currentWrite;
|
||||
*aWriteCount += currentWrite;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP FileImpl::Tell(PRIntn* outWhere)
|
||||
//----------------------------------------------------------------------------------------
|
||||
@@ -385,7 +421,8 @@ NS_IMETHODIMP FileImpl::Tell(PRIntn* outWhere)
|
||||
NS_IMETHODIMP FileImpl::Close()
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
Flush();
|
||||
if ((mNSPRMode & PR_RDONLY) == 0)
|
||||
Flush();
|
||||
|
||||
if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc)
|
||||
return NS_OK;
|
||||
@@ -423,10 +460,10 @@ NS_IMETHODIMP FileImpl::Flush()
|
||||
|
||||
PRInt32 bytesWrit = PR_Write(mFileDesc, seg, segSize);
|
||||
if (bytesWrit != (PRInt32)segSize)
|
||||
{
|
||||
mFailed = PR_TRUE;
|
||||
return NS_FILE_RESULT(PR_GetError());
|
||||
}
|
||||
{
|
||||
mFailed = PR_TRUE;
|
||||
return NS_FILE_RESULT(PR_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
mOutBuffer.Empty();
|
||||
@@ -442,6 +479,36 @@ NS_IMETHODIMP FileImpl::Flush()
|
||||
return NS_OK;
|
||||
} // FileImpl::flush
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP FileImpl::GetAtEOF(PRBool* outAtEOF)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
*outAtEOF = mEOF;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_IMETHODIMP FileImpl::SetAtEOF(PRBool inAtEOF)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
mEOF = inAtEOF;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
nsresult FileImpl::AllocateBuffers(PRUint32 segmentSize, PRUint32 maxBufSize)
|
||||
//----------------------------------------------------------------------------------------
|
||||
{
|
||||
nsresult rv = mOutBuffer.Init(segmentSize, maxBufSize);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mGotBuffers = PR_TRUE;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
NS_COM nsresult NS_NewTypicalInputFileStream(
|
||||
nsISupports** aResult,
|
||||
|
||||
Reference in New Issue
Block a user