michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsFileStreams_h__ michael@0: #define nsFileStreams_h__ michael@0: michael@0: #include "nsAutoPtr.h" michael@0: #include "nsIFileStreams.h" michael@0: #include "nsIFile.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsIOutputStream.h" michael@0: #include "nsISafeOutputStream.h" michael@0: #include "nsISeekableStream.h" michael@0: #include "nsILineInputStream.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIIPCSerializableInputStream.h" michael@0: #include "nsReadLine.h" michael@0: #include michael@0: michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class nsFileStreamBase : public nsISeekableStream, michael@0: public nsIFileMetadata michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSISEEKABLESTREAM michael@0: NS_DECL_NSIFILEMETADATA michael@0: michael@0: nsFileStreamBase(); michael@0: virtual ~nsFileStreamBase(); michael@0: michael@0: protected: michael@0: nsresult Close(); michael@0: nsresult Available(uint64_t* _retval); michael@0: nsresult Read(char* aBuf, uint32_t aCount, uint32_t* _retval); michael@0: nsresult ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, michael@0: uint32_t aCount, uint32_t* _retval); michael@0: nsresult IsNonBlocking(bool* _retval); michael@0: nsresult Flush(); michael@0: nsresult Write(const char* aBuf, uint32_t aCount, uint32_t* _retval); michael@0: nsresult WriteFrom(nsIInputStream* aFromStream, uint32_t aCount, michael@0: uint32_t* _retval); michael@0: nsresult WriteSegments(nsReadSegmentFun aReader, void* aClosure, michael@0: uint32_t aCount, uint32_t* _retval); michael@0: michael@0: PRFileDesc* mFD; michael@0: michael@0: /** michael@0: * Flags describing our behavior. See the IDL file for possible values. michael@0: */ michael@0: int32_t mBehaviorFlags; michael@0: michael@0: /** michael@0: * Whether we have a pending open (see DEFER_OPEN in the IDL file). michael@0: */ michael@0: bool mDeferredOpen; michael@0: michael@0: struct OpenParams { michael@0: nsCOMPtr localFile; michael@0: int32_t ioFlags; michael@0: int32_t perm; michael@0: }; michael@0: michael@0: /** michael@0: * Data we need to do an open. michael@0: */ michael@0: OpenParams mOpenParams; michael@0: michael@0: /** michael@0: * Prepares the data we need to open the file, and either does the open now michael@0: * by calling DoOpen(), or leaves it to be opened later by a call to michael@0: * DoPendingOpen(). michael@0: */ michael@0: nsresult MaybeOpen(nsIFile* aFile, int32_t aIoFlags, int32_t aPerm, michael@0: bool aDeferred); michael@0: michael@0: /** michael@0: * Cleans up data prepared in MaybeOpen. michael@0: */ michael@0: void CleanUpOpen(); michael@0: michael@0: /** michael@0: * Open the file. This is called either from MaybeOpen (during Init) michael@0: * or from DoPendingOpen (if DEFER_OPEN is used when initializing this michael@0: * stream). The default behavior of DoOpen is to open the file and save the michael@0: * file descriptor. michael@0: */ michael@0: virtual nsresult DoOpen(); michael@0: michael@0: /** michael@0: * If there is a pending open, do it now. It's important for this to be michael@0: * inline since we do it in almost every stream API call. michael@0: */ michael@0: inline nsresult DoPendingOpen(); michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class nsFileInputStream : public nsFileStreamBase, michael@0: public nsIFileInputStream, michael@0: public nsILineInputStream, michael@0: public nsIIPCSerializableInputStream michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_NSIFILEINPUTSTREAM michael@0: NS_DECL_NSILINEINPUTSTREAM michael@0: NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM michael@0: michael@0: NS_IMETHOD Close(); michael@0: NS_IMETHOD Tell(int64_t *aResult); michael@0: NS_IMETHOD Available(uint64_t* _retval); michael@0: NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* _retval); michael@0: NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, michael@0: uint32_t aCount, uint32_t* _retval) michael@0: { michael@0: return nsFileStreamBase::ReadSegments(aWriter, aClosure, aCount, michael@0: _retval); michael@0: } michael@0: NS_IMETHOD IsNonBlocking(bool* _retval) michael@0: { michael@0: return nsFileStreamBase::IsNonBlocking(_retval); michael@0: } michael@0: michael@0: // Overrided from nsFileStreamBase michael@0: NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset); michael@0: michael@0: nsFileInputStream() michael@0: : mLineBuffer(nullptr), mIOFlags(0), mPerm(0), mCachedPosition(0) michael@0: {} michael@0: michael@0: virtual ~nsFileInputStream() michael@0: { michael@0: Close(); michael@0: } michael@0: michael@0: static nsresult michael@0: Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); michael@0: michael@0: protected: michael@0: nsAutoPtr > mLineBuffer; michael@0: michael@0: /** michael@0: * The file being opened. michael@0: */ michael@0: nsCOMPtr mFile; michael@0: /** michael@0: * The IO flags passed to Init() for the file open. michael@0: */ michael@0: int32_t mIOFlags; michael@0: /** michael@0: * The permissions passed to Init() for the file open. michael@0: */ michael@0: int32_t mPerm; michael@0: michael@0: /** michael@0: * Cached position for Tell for automatically reopening streams. michael@0: */ michael@0: int64_t mCachedPosition; michael@0: michael@0: protected: michael@0: /** michael@0: * Internal, called to open a file. Parameters are the same as their michael@0: * Init() analogues. michael@0: */ michael@0: nsresult Open(nsIFile* file, int32_t ioFlags, int32_t perm); michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class nsPartialFileInputStream : public nsFileInputStream, michael@0: public nsIPartialFileInputStream michael@0: { michael@0: public: michael@0: using nsFileInputStream::Init; michael@0: using nsFileInputStream::Read; michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_NSIPARTIALFILEINPUTSTREAM michael@0: NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM michael@0: michael@0: nsPartialFileInputStream() michael@0: : mStart(0), mLength(0), mPosition(0) michael@0: { } michael@0: michael@0: NS_IMETHOD Tell(int64_t *aResult); michael@0: NS_IMETHOD Available(uint64_t *aResult); michael@0: NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* aResult); michael@0: NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset); michael@0: michael@0: static nsresult michael@0: Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); michael@0: michael@0: private: michael@0: uint64_t TruncateSize(uint64_t aSize) { michael@0: return std::min(mLength - mPosition, aSize); michael@0: } michael@0: michael@0: uint64_t mStart; michael@0: uint64_t mLength; michael@0: uint64_t mPosition; michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class nsFileOutputStream : public nsFileStreamBase, michael@0: public nsIFileOutputStream michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_NSIFILEOUTPUTSTREAM michael@0: NS_FORWARD_NSIOUTPUTSTREAM(nsFileStreamBase::) michael@0: michael@0: virtual ~nsFileOutputStream() michael@0: { michael@0: Close(); michael@0: } michael@0: michael@0: static nsresult michael@0: Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * A safe file output stream that overwrites the destination file only michael@0: * once writing is complete. This protects against incomplete writes michael@0: * due to the process or the thread being interrupted or crashed. michael@0: */ michael@0: class nsAtomicFileOutputStream : public nsFileOutputStream, michael@0: public nsISafeOutputStream michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_NSISAFEOUTPUTSTREAM michael@0: michael@0: nsAtomicFileOutputStream() : michael@0: mTargetFileExists(true), michael@0: mWriteResult(NS_OK) {} michael@0: michael@0: virtual ~nsAtomicFileOutputStream() michael@0: { michael@0: Close(); michael@0: } michael@0: michael@0: virtual nsresult DoOpen() MOZ_OVERRIDE; michael@0: michael@0: NS_IMETHODIMP Close(); michael@0: NS_IMETHODIMP Write(const char *buf, uint32_t count, uint32_t *result); michael@0: NS_IMETHODIMP Init(nsIFile* file, int32_t ioFlags, int32_t perm, int32_t behaviorFlags); michael@0: michael@0: protected: michael@0: nsCOMPtr mTargetFile; michael@0: nsCOMPtr mTempFile; michael@0: michael@0: bool mTargetFileExists; michael@0: nsresult mWriteResult; // Internally set in Write() michael@0: michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * A safe file output stream that overwrites the destination file only michael@0: * once writing + flushing is complete. This protects against more michael@0: * classes of software/hardware errors than nsAtomicFileOutputStream, michael@0: * at the expense of being more costly to the disk, OS and battery. michael@0: */ michael@0: class nsSafeFileOutputStream : public nsAtomicFileOutputStream michael@0: { michael@0: public: michael@0: michael@0: NS_IMETHOD Finish(); michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class nsFileStream : public nsFileStreamBase, michael@0: public nsIInputStream, michael@0: public nsIOutputStream, michael@0: public nsIFileStream michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_NSIFILESTREAM michael@0: NS_FORWARD_NSIINPUTSTREAM(nsFileStreamBase::) michael@0: michael@0: // Can't use NS_FORWARD_NSIOUTPUTSTREAM due to overlapping methods michael@0: // Close() and IsNonBlocking() michael@0: NS_IMETHOD Flush() michael@0: { michael@0: return nsFileStreamBase::Flush(); michael@0: } michael@0: NS_IMETHOD Write(const char* aBuf, uint32_t aCount, uint32_t* _retval) michael@0: { michael@0: return nsFileStreamBase::Write(aBuf, aCount, _retval); michael@0: } michael@0: NS_IMETHOD WriteFrom(nsIInputStream* aFromStream, uint32_t aCount, michael@0: uint32_t* _retval) michael@0: { michael@0: return nsFileStreamBase::WriteFrom(aFromStream, aCount, _retval); michael@0: } michael@0: NS_IMETHOD WriteSegments(nsReadSegmentFun aReader, void* aClosure, michael@0: uint32_t aCount, uint32_t* _retval) michael@0: { michael@0: return nsFileStreamBase::WriteSegments(aReader, aClosure, aCount, michael@0: _retval); michael@0: } michael@0: michael@0: virtual ~nsFileStream() michael@0: { michael@0: Close(); michael@0: } michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #endif // nsFileStreams_h__