michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * 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: michael@0: #ifndef _nsCacheEntryDescriptor_h_ michael@0: #define _nsCacheEntryDescriptor_h_ michael@0: michael@0: #include "nsICacheEntryDescriptor.h" michael@0: #include "nsCacheEntry.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsIOutputStream.h" michael@0: #include "nsCacheService.h" michael@0: #include "zlib.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "nsVoidArray.h" michael@0: michael@0: /****************************************************************************** michael@0: * nsCacheEntryDescriptor michael@0: *******************************************************************************/ michael@0: class nsCacheEntryDescriptor : michael@0: public PRCList, michael@0: public nsICacheEntryDescriptor michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSICACHEENTRYDESCRIPTOR michael@0: NS_DECL_NSICACHEENTRYINFO michael@0: michael@0: friend class nsAsyncDoomEvent; michael@0: friend class nsCacheService; michael@0: michael@0: nsCacheEntryDescriptor(nsCacheEntry * entry, nsCacheAccessMode mode); michael@0: virtual ~nsCacheEntryDescriptor(); michael@0: michael@0: /** michael@0: * utility method to attempt changing data size of associated entry michael@0: */ michael@0: nsresult RequestDataSizeChange(int32_t deltaSize); michael@0: michael@0: /** michael@0: * methods callbacks for nsCacheService michael@0: */ michael@0: nsCacheEntry * CacheEntry(void) { return mCacheEntry; } michael@0: bool ClearCacheEntry(void) michael@0: { michael@0: NS_ASSERTION(mInputWrappers.Count() == 0, "Bad state"); michael@0: NS_ASSERTION(!mOutputWrapper, "Bad state"); michael@0: michael@0: bool doomEntry = false; michael@0: bool asyncDoomPending; michael@0: { michael@0: mozilla::MutexAutoLock lock(mLock); michael@0: asyncDoomPending = mAsyncDoomPending; michael@0: } michael@0: michael@0: if (asyncDoomPending && mCacheEntry) { michael@0: doomEntry = true; michael@0: mDoomedOnClose = true; michael@0: } michael@0: mCacheEntry = nullptr; michael@0: michael@0: return doomEntry; michael@0: } michael@0: michael@0: private: michael@0: /************************************************************************* michael@0: * input stream wrapper class - michael@0: * michael@0: * The input stream wrapper references the descriptor, but the descriptor michael@0: * doesn't need any references to the stream wrapper. michael@0: *************************************************************************/ michael@0: class nsInputStreamWrapper : public nsIInputStream { michael@0: friend class nsCacheEntryDescriptor; michael@0: michael@0: private: michael@0: nsCacheEntryDescriptor * mDescriptor; michael@0: nsCOMPtr mInput; michael@0: uint32_t mStartOffset; michael@0: bool mInitialized; michael@0: mozilla::Mutex mLock; michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIINPUTSTREAM michael@0: michael@0: nsInputStreamWrapper(nsCacheEntryDescriptor * desc, uint32_t off) michael@0: : mDescriptor(desc) michael@0: , mStartOffset(off) michael@0: , mInitialized(false) michael@0: , mLock("nsInputStreamWrapper.mLock") michael@0: { michael@0: NS_ADDREF(mDescriptor); michael@0: } michael@0: virtual ~nsInputStreamWrapper() michael@0: { michael@0: NS_IF_RELEASE(mDescriptor); michael@0: } michael@0: michael@0: private: michael@0: nsresult LazyInit(); michael@0: nsresult EnsureInit(); michael@0: nsresult Read_Locked(char *buf, uint32_t count, uint32_t *countRead); michael@0: nsresult Close_Locked(); michael@0: void CloseInternal(); michael@0: }; michael@0: michael@0: michael@0: class nsDecompressInputStreamWrapper : public nsInputStreamWrapper { michael@0: private: michael@0: unsigned char* mReadBuffer; michael@0: uint32_t mReadBufferLen; michael@0: z_stream mZstream; michael@0: bool mStreamInitialized; michael@0: bool mStreamEnded; michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: nsDecompressInputStreamWrapper(nsCacheEntryDescriptor * desc, michael@0: uint32_t off) michael@0: : nsInputStreamWrapper(desc, off) michael@0: , mReadBuffer(0) michael@0: , mReadBufferLen(0) michael@0: , mStreamInitialized(false) michael@0: , mStreamEnded(false) michael@0: { michael@0: } michael@0: virtual ~nsDecompressInputStreamWrapper() michael@0: { michael@0: Close(); michael@0: } michael@0: NS_IMETHOD Read(char* buf, uint32_t count, uint32_t * result); michael@0: NS_IMETHOD Close(); michael@0: private: michael@0: nsresult InitZstream(); michael@0: nsresult EndZstream(); michael@0: }; michael@0: michael@0: michael@0: /************************************************************************* michael@0: * output stream wrapper class - michael@0: * michael@0: * The output stream wrapper references the descriptor, but the descriptor michael@0: * doesn't need any references to the stream wrapper. michael@0: *************************************************************************/ michael@0: class nsOutputStreamWrapper : public nsIOutputStream { michael@0: friend class nsCacheEntryDescriptor; michael@0: michael@0: protected: michael@0: nsCacheEntryDescriptor * mDescriptor; michael@0: nsCOMPtr mOutput; michael@0: uint32_t mStartOffset; michael@0: bool mInitialized; michael@0: mozilla::Mutex mLock; michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIOUTPUTSTREAM michael@0: michael@0: nsOutputStreamWrapper(nsCacheEntryDescriptor * desc, uint32_t off) michael@0: : mDescriptor(desc) michael@0: , mStartOffset(off) michael@0: , mInitialized(false) michael@0: , mLock("nsOutputStreamWrapper.mLock") michael@0: { michael@0: NS_ADDREF(mDescriptor); // owning ref michael@0: } michael@0: virtual ~nsOutputStreamWrapper() michael@0: { michael@0: Close(); michael@0: michael@0: NS_ASSERTION(!mOutput, "Bad state"); michael@0: NS_ASSERTION(!mDescriptor, "Bad state"); michael@0: } michael@0: michael@0: private: michael@0: nsresult LazyInit(); michael@0: nsresult EnsureInit(); michael@0: nsresult OnWrite(uint32_t count); michael@0: nsresult Write_Locked(const char * buf, michael@0: uint32_t count, michael@0: uint32_t * result); michael@0: nsresult Close_Locked(); michael@0: void CloseInternal(); michael@0: }; michael@0: michael@0: michael@0: class nsCompressOutputStreamWrapper : public nsOutputStreamWrapper { michael@0: private: michael@0: unsigned char* mWriteBuffer; michael@0: uint32_t mWriteBufferLen; michael@0: z_stream mZstream; michael@0: bool mStreamInitialized; michael@0: bool mStreamEnded; michael@0: uint32_t mUncompressedCount; michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: nsCompressOutputStreamWrapper(nsCacheEntryDescriptor * desc, michael@0: uint32_t off) michael@0: : nsOutputStreamWrapper(desc, off) michael@0: , mWriteBuffer(0) michael@0: , mWriteBufferLen(0) michael@0: , mStreamInitialized(false) michael@0: , mStreamEnded(false) michael@0: , mUncompressedCount(0) michael@0: { michael@0: } michael@0: virtual ~nsCompressOutputStreamWrapper() michael@0: { michael@0: Close(); michael@0: } michael@0: NS_IMETHOD Write(const char* buf, uint32_t count, uint32_t * result); michael@0: NS_IMETHOD Close(); michael@0: private: michael@0: nsresult InitZstream(); michael@0: nsresult WriteBuffer(); michael@0: }; michael@0: michael@0: private: michael@0: /** michael@0: * nsCacheEntryDescriptor data members michael@0: */ michael@0: nsCacheEntry * mCacheEntry; // we are a child of the entry michael@0: nsCacheAccessMode mAccessGranted; michael@0: nsVoidArray mInputWrappers; michael@0: nsOutputStreamWrapper * mOutputWrapper; michael@0: mozilla::Mutex mLock; michael@0: bool mAsyncDoomPending; michael@0: bool mDoomedOnClose; michael@0: bool mClosingDescriptor; michael@0: }; michael@0: michael@0: michael@0: #endif // _nsCacheEntryDescriptor_h_