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:
sfraser%netscape.com
1999-10-11 21:19:06 +00:00
parent c90da152c8
commit 8023b08ebc
7 changed files with 1298 additions and 1102 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,