1999-04-06 01:01:33 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
*
|
1999-11-06 06:43:54 +03:00
|
|
|
* The contents of this file are subject to the Netscape Public
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.mozilla.org/NPL/
|
1999-04-06 01:01:33 +04:00
|
|
|
*
|
1999-11-06 06:43:54 +03:00
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
1999-04-06 01:01:33 +04:00
|
|
|
*
|
1999-11-06 06:43:54 +03:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
1999-04-06 01:01:33 +04:00
|
|
|
* Communications Corporation. Portions created by Netscape are
|
1999-11-06 06:43:54 +03:00
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
1999-12-01 02:36:32 +03:00
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
1999-04-06 01:01:33 +04:00
|
|
|
*/
|
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
#include "nsIFileStream.h"
|
|
|
|
#include "nsFileSpec.h"
|
1999-07-20 18:29:43 +04:00
|
|
|
#include "nsCOMPtr.h"
|
1999-02-25 23:49:47 +03:00
|
|
|
|
|
|
|
#include "prerror.h"
|
|
|
|
|
1999-09-09 00:12:35 +04:00
|
|
|
#include "nsSegmentedBuffer.h"
|
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
#ifdef XP_MAC
|
|
|
|
#include "pprio.h" // To get PR_ImportFile
|
|
|
|
#else
|
|
|
|
#include "prio.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef XP_MAC
|
|
|
|
#include <Errors.h>
|
|
|
|
#include <iostream>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//========================================================================================
|
|
|
|
class FileImpl
|
1999-03-06 01:53:56 +03:00
|
|
|
: public nsIRandomAccessStore
|
1999-02-25 23:49:47 +03:00
|
|
|
, public nsIFileOutputStream
|
|
|
|
, public nsIFileInputStream
|
1999-09-09 00:12:35 +04:00
|
|
|
, public nsIOpenFile
|
1999-02-25 23:49:47 +03:00
|
|
|
//========================================================================================
|
|
|
|
{
|
|
|
|
public:
|
1999-10-12 01:19:06 +04:00
|
|
|
FileImpl(PRFileDesc* inDesc);
|
|
|
|
FileImpl(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode);
|
|
|
|
|
|
|
|
virtual ~FileImpl();
|
1999-02-25 23:49:47 +03:00
|
|
|
// nsISupports interface
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
1999-10-12 01:19:06 +04:00
|
|
|
// nsIOpenFile interface
|
|
|
|
NS_IMETHOD Open(const nsFileSpec& inFile, int nsprMode, PRIntn accessMode);
|
1999-02-25 23:49:47 +03:00
|
|
|
NS_IMETHOD Close();
|
|
|
|
NS_IMETHOD Seek(PRSeekWhence whence, PRInt32 offset);
|
1999-10-12 01:19:06 +04:00
|
|
|
NS_IMETHOD GetIsOpen(PRBool* outOpen);
|
1999-02-25 23:49:47 +03:00
|
|
|
NS_IMETHOD Tell(PRIntn* outWhere);
|
|
|
|
|
1999-10-12 01:19:06 +04:00
|
|
|
// nsIInputStream interface
|
|
|
|
NS_IMETHOD Available(PRUint32 *aLength);
|
|
|
|
NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount);
|
2000-08-22 11:03:33 +04:00
|
|
|
NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval);
|
|
|
|
NS_IMETHOD GetObserver(nsIInputStreamObserver * *aObserver);
|
|
|
|
NS_IMETHOD SetObserver(nsIInputStreamObserver * aObserver);
|
1999-09-09 00:12:35 +04:00
|
|
|
|
1999-10-12 01:19:06 +04:00
|
|
|
// nsIOutputStream interface
|
|
|
|
NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount);
|
1999-02-25 23:49:47 +03:00
|
|
|
NS_IMETHOD Flush();
|
2000-08-22 11:03:33 +04:00
|
|
|
NS_IMETHOD WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval);
|
|
|
|
NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval);
|
|
|
|
NS_IMETHOD GetNonBlocking(PRBool *aNonBlocking);
|
|
|
|
NS_IMETHOD SetNonBlocking(PRBool aNonBlocking);
|
|
|
|
NS_IMETHOD GetObserver(nsIOutputStreamObserver * *aObserver);
|
|
|
|
NS_IMETHOD SetObserver(nsIOutputStreamObserver * aObserver);
|
1999-10-12 01:19:06 +04:00
|
|
|
NS_IMETHOD GetAtEOF(PRBool* outAtEOF);
|
|
|
|
NS_IMETHOD SetAtEOF(PRBool inAtEOF);
|
1999-02-28 04:36:48 +03:00
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
protected:
|
|
|
|
|
1999-10-12 01:19:06 +04:00
|
|
|
enum {
|
|
|
|
kOuputBufferSegmentSize = 4096,
|
|
|
|
kOuputBufferMaxSize = 4096
|
|
|
|
};
|
|
|
|
|
|
|
|
nsresult AllocateBuffers(PRUint32 segmentSize, PRUint32 maxSize);
|
|
|
|
|
1999-03-06 01:53:56 +03:00
|
|
|
PRFileDesc* mFileDesc;
|
|
|
|
int mNSPRMode;
|
|
|
|
PRBool mFailed;
|
|
|
|
PRBool mEOF;
|
|
|
|
PRInt32 mLength;
|
1999-09-09 00:12:35 +04:00
|
|
|
|
1999-10-12 01:19:06 +04:00
|
|
|
PRBool mGotBuffers;
|
1999-09-09 00:12:35 +04:00
|
|
|
nsSegmentedBuffer mOutBuffer;
|
|
|
|
char* mWriteCursor;
|
|
|
|
char* mWriteLimit;
|
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
}; // class FileImpl
|
|
|
|
|
|
|
|
NS_IMPL_RELEASE(FileImpl)
|
|
|
|
NS_IMPL_ADDREF(FileImpl)
|
|
|
|
|
1999-08-23 14:14:16 +04:00
|
|
|
NS_IMPL_QUERY_HEAD(FileImpl)
|
1999-09-09 00:12:35 +04:00
|
|
|
NS_IMPL_QUERY_BODY(nsIOpenFile)
|
1999-08-23 14:14:16 +04:00
|
|
|
NS_IMPL_QUERY_BODY(nsIRandomAccessStore)
|
|
|
|
NS_IMPL_QUERY_BODY(nsIOutputStream)
|
|
|
|
NS_IMPL_QUERY_BODY(nsIInputStream)
|
|
|
|
NS_IMPL_QUERY_BODY(nsIFileInputStream)
|
|
|
|
NS_IMPL_QUERY_BODY(nsIFileOutputStream)
|
|
|
|
NS_IMPL_QUERY_TAIL(nsIOutputStream)
|
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
|
1999-10-12 01:19:06 +04:00
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
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)
|
|
|
|
, 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))
|
|
|
|
{
|
2000-03-14 16:54:42 +03:00
|
|
|
mFailed = PR_TRUE;
|
1999-10-12 01:19:06 +04:00
|
|
|
#if DEBUG
|
|
|
|
char *fileName = inFile.GetLeafName();
|
|
|
|
printf("Opening file %s failed\n", fileName);
|
|
|
|
nsCRT::free(fileName);
|
|
|
|
#endif
|
|
|
|
}
|
2000-03-14 16:54:42 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
mFailed = PR_FALSE;
|
|
|
|
}
|
1999-10-12 01:19:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
FileImpl::~FileImpl()
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
|
|
|
nsresult rv = Close();
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Close failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP FileImpl::Open(
|
|
|
|
const nsFileSpec& inFile,
|
|
|
|
int nsprMode,
|
|
|
|
PRIntn accessMode)
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
|
|
|
if (mFileDesc)
|
|
|
|
if ((nsprMode & mNSPRMode) == nsprMode)
|
|
|
|
return NS_OK;
|
|
|
|
else
|
|
|
|
return NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR);
|
|
|
|
|
|
|
|
const int nspr_modes[]={
|
|
|
|
PR_WRONLY | PR_CREATE_FILE,
|
|
|
|
PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
|
|
|
|
PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
|
|
|
|
PR_RDONLY,
|
|
|
|
PR_RDONLY | PR_APPEND,
|
|
|
|
PR_RDWR | PR_CREATE_FILE,
|
|
|
|
PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE,
|
|
|
|
// "wb",
|
|
|
|
// "ab",
|
|
|
|
// "wb",
|
|
|
|
// "rb",
|
|
|
|
// "r+b",
|
|
|
|
// "w+b",
|
|
|
|
0 };
|
|
|
|
const int* currentLegalMode = nspr_modes;
|
|
|
|
while (*currentLegalMode && nsprMode != *currentLegalMode)
|
|
|
|
++currentLegalMode;
|
|
|
|
if (!*currentLegalMode)
|
|
|
|
return NS_FILE_RESULT(PR_ILLEGAL_ACCESS_ERROR);
|
|
|
|
|
|
|
|
#ifdef XP_MAC
|
|
|
|
// Use the file spec to open the file, because one path can be common to
|
|
|
|
// several files on the Macintosh (you can have several volumes with the
|
|
|
|
// same name, see).
|
|
|
|
mFileDesc = 0;
|
1999-05-30 01:27:18 +04:00
|
|
|
OSErr err = inFile.Error();
|
|
|
|
if (err != noErr)
|
1999-10-12 01:19:06 +04:00
|
|
|
if (err != fnfErr || !(nsprMode & PR_CREATE_FILE))
|
|
|
|
return NS_FILE_RESULT(inFile.Error());
|
1999-05-30 01:27:18 +04:00
|
|
|
err = noErr;
|
1999-02-25 23:49:47 +03:00
|
|
|
#if DEBUG
|
|
|
|
const OSType kCreator = 'CWIE';
|
|
|
|
#else
|
|
|
|
const OSType kCreator = 'MOSS';
|
|
|
|
#endif
|
|
|
|
// Resolve the alias to the original file.
|
|
|
|
nsFileSpec original = inFile;
|
|
|
|
PRBool ignoredResult;
|
1999-07-28 03:05:53 +04:00
|
|
|
original.ResolveSymlink(ignoredResult);
|
1999-02-25 23:49:47 +03:00
|
|
|
const FSSpec& spec = original.operator const FSSpec&();
|
|
|
|
if (nsprMode & PR_CREATE_FILE)
|
|
|
|
err = FSpCreate(&spec, kCreator, 'TEXT', 0);
|
|
|
|
if (err == dupFNErr)
|
|
|
|
err = noErr;
|
|
|
|
if (err != noErr)
|
|
|
|
return NS_FILE_RESULT(err);
|
|
|
|
|
|
|
|
SInt8 perm;
|
|
|
|
if (nsprMode & PR_RDWR)
|
|
|
|
perm = fsRdWrPerm;
|
|
|
|
else if (nsprMode & PR_WRONLY)
|
|
|
|
perm = fsWrPerm;
|
|
|
|
else
|
|
|
|
perm = fsRdPerm;
|
|
|
|
|
|
|
|
short refnum;
|
|
|
|
err = FSpOpenDF(&spec, perm, &refnum);
|
|
|
|
|
|
|
|
if (err == noErr && (nsprMode & PR_TRUNCATE))
|
|
|
|
err = SetEOF(refnum, 0);
|
|
|
|
if (err == noErr && (nsprMode & PR_APPEND))
|
|
|
|
err = SetFPos(refnum, fsFromLEOF, 0);
|
|
|
|
if (err != noErr)
|
|
|
|
return NS_FILE_RESULT(err);
|
|
|
|
|
|
|
|
if ((mFileDesc = PR_ImportFile(refnum)) == 0)
|
|
|
|
return NS_FILE_RESULT(PR_GetError());
|
|
|
|
#else
|
|
|
|
// Platforms other than Macintosh...
|
|
|
|
// Another bug in NSPR: Mac PR_Open assumes a unix style path, but Win PR_Open assumes
|
|
|
|
// a windows path.
|
|
|
|
if ((mFileDesc = PR_Open((const char*)nsFileSpec(inFile), nsprMode, accessMode)) == 0)
|
|
|
|
return NS_FILE_RESULT(PR_GetError());
|
|
|
|
#endif
|
|
|
|
mNSPRMode = nsprMode;
|
|
|
|
mLength = PR_Available(mFileDesc);
|
|
|
|
return NS_OK;
|
|
|
|
} // FileImpl::Open
|
|
|
|
|
1999-10-12 01:19:06 +04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
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)
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
2000-03-14 16:54:42 +03:00
|
|
|
*outOpen = (mFileDesc != nsnull && !mFailed);
|
1999-10-12 01:19:06 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP FileImpl::Seek(PRSeekWhence whence, PRInt32 offset)
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
|
|
|
if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc)
|
|
|
|
return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
|
|
|
|
mFailed = PR_FALSE; // reset on a seek.
|
|
|
|
mEOF = PR_FALSE; // reset on a seek.
|
1999-11-18 08:16:42 +03:00
|
|
|
|
|
|
|
// To avoid corruption, we flush during a seek. see bug number 18949
|
|
|
|
Flush();
|
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
PRInt32 position = PR_Seek(mFileDesc, 0, PR_SEEK_CUR);
|
|
|
|
PRInt32 available = PR_Available(mFileDesc);
|
|
|
|
PRInt32 fileSize = position + available;
|
1999-03-05 07:20:54 +03:00
|
|
|
PRInt32 newPosition = 0;
|
1999-02-25 23:49:47 +03:00
|
|
|
switch (whence)
|
|
|
|
{
|
|
|
|
case PR_SEEK_CUR: newPosition = position + offset; break;
|
|
|
|
case PR_SEEK_SET: newPosition = offset; break;
|
|
|
|
case PR_SEEK_END: newPosition = fileSize + offset; break;
|
|
|
|
}
|
|
|
|
if (newPosition < 0)
|
|
|
|
{
|
|
|
|
newPosition = 0;
|
|
|
|
mFailed = PR_TRUE;
|
|
|
|
}
|
1999-03-06 01:53:56 +03:00
|
|
|
if (newPosition >= fileSize) // nb: not "else if".
|
1999-02-25 23:49:47 +03:00
|
|
|
{
|
|
|
|
newPosition = fileSize;
|
|
|
|
mEOF = PR_TRUE;
|
|
|
|
}
|
|
|
|
if (PR_Seek(mFileDesc, newPosition, PR_SEEK_SET) < 0)
|
|
|
|
mFailed = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
} // FileImpl::Seek
|
|
|
|
|
1999-10-12 01:19:06 +04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2000-08-22 11:03:33 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
FileImpl::ReadSegments(nsWriteSegmentFun writer, void * closure, PRUint32 count, PRUint32 *_retval)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("ReadSegments");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
FileImpl::GetObserver(nsIInputStreamObserver * *aObserver)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("GetObserver");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
FileImpl::SetObserver(nsIInputStreamObserver * aObserver)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("SetObserver");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
1999-10-12 01:19:06 +04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
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)
|
|
|
|
{
|
2000-06-21 03:10:06 +04:00
|
|
|
std::cout.write(aBuf, aCount);
|
1999-10-12 01:19:06 +04:00
|
|
|
*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;
|
|
|
|
}
|
|
|
|
|
2000-08-22 11:03:33 +04:00
|
|
|
static NS_METHOD
|
|
|
|
nsWriteSegmentToFile(nsIInputStream* in,
|
|
|
|
void* closure,
|
|
|
|
const char* fromRawSegment,
|
|
|
|
PRUint32 toOffset,
|
|
|
|
PRUint32 count,
|
|
|
|
PRUint32 *writeCount)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("nsWriteSegmentToFile");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
FileImpl::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *result)
|
|
|
|
{
|
|
|
|
return inStr->ReadSegments(nsWriteSegmentToFile, nsnull, count, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
FileImpl::WriteSegments(nsReadSegmentFun reader, void * closure,
|
|
|
|
PRUint32 count, PRUint32 *result)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("WriteSegments");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
FileImpl::GetNonBlocking(PRBool *aNonBlocking)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("GetNonBlocking");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
FileImpl::SetNonBlocking(PRBool aNonBlocking)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("SetNonBlocking");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
FileImpl::GetObserver(nsIOutputStreamObserver * *aObserver)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("GetObserver");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
FileImpl::SetObserver(nsIOutputStreamObserver * aObserver)
|
|
|
|
{
|
|
|
|
NS_NOTREACHED("SetObserver");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
1999-10-12 01:19:06 +04:00
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP FileImpl::Tell(PRIntn* outWhere)
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
|
|
|
if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc)
|
|
|
|
return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
|
|
|
|
*outWhere = PR_Seek(mFileDesc, 0, PR_SEEK_CUR);
|
|
|
|
return NS_OK;
|
|
|
|
} // FileImpl::Tell
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP FileImpl::Close()
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
1999-10-12 01:19:06 +04:00
|
|
|
if ((mNSPRMode & PR_RDONLY) == 0)
|
|
|
|
Flush();
|
1999-09-09 00:12:35 +04:00
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
if (mFileDesc==PR_STDIN || mFileDesc==PR_STDOUT || mFileDesc==PR_STDERR || !mFileDesc)
|
|
|
|
return NS_OK;
|
|
|
|
if (PR_Close(mFileDesc) == PR_SUCCESS)
|
|
|
|
mFileDesc = 0;
|
|
|
|
else
|
|
|
|
return NS_FILE_RESULT(PR_GetError());
|
|
|
|
return NS_OK;
|
|
|
|
} // FileImpl::close
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP FileImpl::Flush()
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
|
|
|
#ifdef XP_MAC
|
|
|
|
if (mFileDesc == PR_STDOUT || mFileDesc == PR_STDERR)
|
|
|
|
{
|
2000-06-21 03:10:06 +04:00
|
|
|
std::cout.flush();
|
1999-02-25 23:49:47 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!mFileDesc)
|
|
|
|
return NS_FILE_RESULT(PR_BAD_DESCRIPTOR_ERROR);
|
1999-07-21 21:56:01 +04:00
|
|
|
|
1999-09-09 00:12:35 +04:00
|
|
|
PRInt32 segCount = mOutBuffer.GetSegmentCount();
|
|
|
|
PRUint32 segSize = mOutBuffer.GetSegmentSize();
|
|
|
|
|
|
|
|
for (PRInt32 i = 0; i < segCount; i++)
|
|
|
|
{
|
|
|
|
char* seg = mOutBuffer.GetSegment(i);
|
|
|
|
|
|
|
|
// if it is the last buffer, it may not be completely full.
|
|
|
|
if(i == (segCount-1))
|
|
|
|
segSize = (mWriteCursor - seg);
|
|
|
|
|
|
|
|
PRInt32 bytesWrit = PR_Write(mFileDesc, seg, segSize);
|
|
|
|
if (bytesWrit != (PRInt32)segSize)
|
1999-10-12 01:19:06 +04:00
|
|
|
{
|
|
|
|
mFailed = PR_TRUE;
|
|
|
|
return NS_FILE_RESULT(PR_GetError());
|
|
|
|
}
|
1999-09-09 00:12:35 +04:00
|
|
|
}
|
|
|
|
|
1999-11-19 06:01:33 +03:00
|
|
|
if (mGotBuffers)
|
|
|
|
mOutBuffer.Empty();
|
1999-09-09 00:12:35 +04:00
|
|
|
mWriteCursor = nsnull;
|
|
|
|
mWriteLimit = nsnull;
|
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
#ifdef XP_MAC
|
|
|
|
// On unix, it seems to fail always.
|
1999-07-21 21:56:01 +04:00
|
|
|
if (PR_Sync(mFileDesc) != PR_SUCCESS)
|
1999-02-25 23:49:47 +03:00
|
|
|
mFailed = PR_TRUE;
|
|
|
|
#endif
|
1999-09-09 00:12:35 +04:00
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
return NS_OK;
|
|
|
|
} // FileImpl::flush
|
|
|
|
|
1999-10-12 01:19:06 +04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-25 23:49:47 +03:00
|
|
|
//----------------------------------------------------------------------------------------
|
1999-05-26 05:38:36 +04:00
|
|
|
NS_COM nsresult NS_NewTypicalInputFileStream(
|
1999-02-25 23:49:47 +03:00
|
|
|
nsISupports** aResult,
|
|
|
|
const nsFileSpec& inFile
|
|
|
|
/*Default nsprMode == PR_RDONLY*/
|
2000-07-31 07:46:22 +04:00
|
|
|
/*Default accessmode = 0666 (octal)*/)
|
1999-02-25 23:49:47 +03:00
|
|
|
// Factory method to get an nsInputStream from a file, using most common options
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
1999-07-16 16:59:20 +04:00
|
|
|
// This QueryInterface was needed because NS_NewIOFileStream
|
|
|
|
// does a cast from (void *) to (nsISupports *) thus causing a
|
|
|
|
// vtable problem on Windows, where we really didn't have the proper pointer
|
|
|
|
// to an nsIInputStream, this ensures that we do
|
|
|
|
#if 1
|
|
|
|
nsISupports * supports;
|
|
|
|
nsIInputStream * inStr;
|
|
|
|
|
2000-07-31 07:46:22 +04:00
|
|
|
nsresult rv = NS_NewIOFileStream(&supports, inFile, PR_RDONLY, 0666);
|
1999-07-16 16:59:20 +04:00
|
|
|
|
1999-07-20 18:29:43 +04:00
|
|
|
*aResult = nsnull;
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
1999-12-01 02:36:32 +03:00
|
|
|
if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIInputStream), (void**)&inStr))) {
|
1999-07-20 18:29:43 +04:00
|
|
|
*aResult = inStr;
|
|
|
|
}
|
|
|
|
NS_RELEASE(supports);
|
1999-07-16 16:59:20 +04:00
|
|
|
}
|
1999-07-20 18:29:43 +04:00
|
|
|
return rv;
|
1999-07-16 16:59:20 +04:00
|
|
|
#else
|
2000-07-31 07:46:22 +04:00
|
|
|
return NS_NewIOFileStream(aResult, inFile, PR_RDONLY, 0666);
|
1999-07-16 16:59:20 +04:00
|
|
|
#endif
|
1999-02-25 23:49:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
1999-05-26 05:38:36 +04:00
|
|
|
NS_COM nsresult NS_NewOutputConsoleStream(
|
1999-02-25 23:49:47 +03:00
|
|
|
nsISupports** aResult)
|
|
|
|
// Factory method to get an nsOutputStream to the console.
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
|
|
if (! aResult)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
FileImpl* stream = new FileImpl(PR_STDOUT);
|
|
|
|
if (! stream)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
NS_ADDREF(stream);
|
|
|
|
*aResult = (nsISupports*)(void*)stream;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
1999-05-26 05:38:36 +04:00
|
|
|
NS_COM nsresult NS_NewTypicalOutputFileStream(
|
1999-02-25 23:49:47 +03:00
|
|
|
nsISupports** aResult,
|
|
|
|
const nsFileSpec& inFile
|
|
|
|
/*default nsprMode= (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/
|
2000-07-31 07:46:22 +04:00
|
|
|
/*Default accessMode= 0666 (octal)*/)
|
1999-02-25 23:49:47 +03:00
|
|
|
// Factory method to get an nsOutputStream to a file - most common case.
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
1999-07-16 16:59:20 +04:00
|
|
|
// This QueryInterface was needed because NS_NewIOFileStream
|
|
|
|
// does a cast from (void *) to (nsISupports *) thus causing a
|
|
|
|
// vtable problem on Windows, where we really didn't have the proper pointer
|
|
|
|
// to an nsIOutputStream, this ensures that we do
|
|
|
|
#if 1
|
1999-07-20 18:29:43 +04:00
|
|
|
/* nsISupports * supports;
|
1999-07-16 16:59:20 +04:00
|
|
|
nsIOutputStream * outStr;
|
|
|
|
|
|
|
|
nsresult rv = NS_NewIOFileStream(
|
|
|
|
&supports,
|
|
|
|
inFile,
|
|
|
|
(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
|
2000-07-31 07:46:22 +04:00
|
|
|
0666);
|
1999-07-16 16:59:20 +04:00
|
|
|
|
1999-07-20 18:29:43 +04:00
|
|
|
*aResult = nsnull;
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
1999-12-01 02:36:32 +03:00
|
|
|
if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIOutputStream), (void**)&outStr))) {
|
1999-07-20 18:29:43 +04:00
|
|
|
*aResult = outStr;
|
|
|
|
}
|
|
|
|
NS_RELEASE(supports);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
*/
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupports> supports;
|
|
|
|
nsIOutputStream * outStr;
|
|
|
|
|
|
|
|
nsresult rv = NS_NewIOFileStream(
|
|
|
|
getter_AddRefs(supports),
|
|
|
|
inFile,
|
|
|
|
(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
|
2000-07-31 07:46:22 +04:00
|
|
|
0666);
|
1999-07-20 18:29:43 +04:00
|
|
|
|
|
|
|
*aResult = nsnull;
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
1999-12-01 02:36:32 +03:00
|
|
|
if (NS_SUCCEEDED(supports->QueryInterface(NS_GET_IID(nsIOutputStream), (void**)&outStr))) {
|
1999-07-20 18:29:43 +04:00
|
|
|
*aResult = outStr;
|
|
|
|
}
|
1999-07-16 16:59:20 +04:00
|
|
|
}
|
1999-07-20 18:29:43 +04:00
|
|
|
return rv;
|
1999-07-16 16:59:20 +04:00
|
|
|
#else
|
1999-02-25 23:49:47 +03:00
|
|
|
return NS_NewIOFileStream(
|
|
|
|
aResult,
|
|
|
|
inFile,
|
|
|
|
(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
|
2000-07-31 07:46:22 +04:00
|
|
|
0666);
|
1999-07-16 16:59:20 +04:00
|
|
|
#endif
|
1999-02-25 23:49:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
1999-05-26 05:38:36 +04:00
|
|
|
NS_COM nsresult NS_NewIOFileStream(
|
1999-02-25 23:49:47 +03:00
|
|
|
nsISupports** aResult,
|
|
|
|
const nsFileSpec& inFile,
|
|
|
|
PRInt32 nsprMode /*default = (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE)*/,
|
2000-07-31 07:46:22 +04:00
|
|
|
PRInt32 accessMode /*Default = 0666 (octal)*/)
|
1999-02-25 23:49:47 +03:00
|
|
|
// Factory method to get an object that implements both nsIInputStream
|
|
|
|
// and nsIOutputStream, associated with a file.
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
|
|
if (!aResult)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
FileImpl* stream = new FileImpl(inFile, nsprMode, accessMode);
|
|
|
|
if (! stream)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2000-03-14 16:54:42 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
PRBool isOpened = PR_FALSE;
|
|
|
|
stream->GetIsOpen(&isOpened);
|
|
|
|
if (!isOpened)
|
|
|
|
{
|
|
|
|
delete stream;
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
1999-02-25 23:49:47 +03:00
|
|
|
|
|
|
|
NS_ADDREF(stream);
|
|
|
|
*aResult = (nsISupports*)(void*)stream;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
1999-05-26 05:38:36 +04:00
|
|
|
NS_COM nsresult NS_NewTypicalIOFileStream(
|
1999-02-25 23:49:47 +03:00
|
|
|
nsISupports** aResult,
|
|
|
|
const nsFileSpec& inFile
|
|
|
|
/*default nsprMode= (PR_RDWR | PR_CREATE_FILE)*/
|
2000-07-31 07:46:22 +04:00
|
|
|
/*Default accessMode= 0666 (octal)*/)
|
1999-02-25 23:49:47 +03:00
|
|
|
// Factory method to get an object that implements both nsIInputStream
|
|
|
|
// and nsIOutputStream, associated with a single file.
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
{
|
|
|
|
return NS_NewIOFileStream(
|
|
|
|
aResult,
|
|
|
|
inFile,
|
|
|
|
(PR_RDWR | PR_CREATE_FILE),
|
2000-07-31 07:46:22 +04:00
|
|
|
0666);
|
1999-02-25 23:49:47 +03:00
|
|
|
}
|