1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef nsBufferedStreams_h__
7 #define nsBufferedStreams_h__
8 
9 #include "nsIBufferedStreams.h"
10 #include "nsIInputStream.h"
11 #include "nsIOutputStream.h"
12 #include "nsISafeOutputStream.h"
13 #include "nsISeekableStream.h"
14 #include "nsIStreamBufferAccess.h"
15 #include "nsCOMPtr.h"
16 #include "nsIIPCSerializableInputStream.h"
17 #include "nsIAsyncInputStream.h"
18 #include "nsICloneableInputStream.h"
19 #include "nsIInputStreamLength.h"
20 #include "mozilla/Mutex.h"
21 
22 ////////////////////////////////////////////////////////////////////////////////
23 
24 class nsBufferedStream : public nsISeekableStream {
25  public:
26   NS_DECL_THREADSAFE_ISUPPORTS
27   NS_DECL_NSISEEKABLESTREAM
28   NS_DECL_NSITELLABLESTREAM
29 
30   nsBufferedStream() = default;
31 
32   void Close();
33 
34  protected:
35   virtual ~nsBufferedStream();
36 
37   nsresult Init(nsISupports* stream, uint32_t bufferSize);
38   nsresult GetData(nsISupports** aResult);
39   NS_IMETHOD Fill() = 0;
40   NS_IMETHOD Flush() = 0;
41 
42   uint32_t mBufferSize{0};
43   char* mBuffer{nullptr};
44 
45   // mBufferStartOffset is the offset relative to the start of mStream.
46   int64_t mBufferStartOffset{0};
47 
48   // mCursor is the read cursor for input streams, or write cursor for
49   // output streams, and is relative to mBufferStartOffset.
50   uint32_t mCursor{0};
51 
52   // mFillPoint is the amount available in the buffer for input streams,
53   // or the high watermark of bytes written into the buffer, and therefore
54   // is relative to mBufferStartOffset.
55   uint32_t mFillPoint{0};
56 
57   nsCOMPtr<nsISupports> mStream;  // cast to appropriate subclass
58 
59   bool mBufferDisabled{false};
60   bool mEOF{false};  // True if mStream is at EOF
61   uint8_t mGetBufferCount{0};
62 };
63 
64 ////////////////////////////////////////////////////////////////////////////////
65 
66 class nsBufferedInputStream final : public nsBufferedStream,
67                                     public nsIBufferedInputStream,
68                                     public nsIStreamBufferAccess,
69                                     public nsIIPCSerializableInputStream,
70                                     public nsIAsyncInputStream,
71                                     public nsIInputStreamCallback,
72                                     public nsICloneableInputStream,
73                                     public nsIInputStreamLength,
74                                     public nsIAsyncInputStreamLength,
75                                     public nsIInputStreamLengthCallback {
76  public:
77   NS_DECL_ISUPPORTS_INHERITED
78   NS_DECL_NSIINPUTSTREAM
79   NS_DECL_NSIBUFFEREDINPUTSTREAM
80   NS_DECL_NSISTREAMBUFFERACCESS
81   NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
82   NS_DECL_NSIASYNCINPUTSTREAM
83   NS_DECL_NSIINPUTSTREAMCALLBACK
84   NS_DECL_NSICLONEABLEINPUTSTREAM
85   NS_DECL_NSIINPUTSTREAMLENGTH
86   NS_DECL_NSIASYNCINPUTSTREAMLENGTH
87   NS_DECL_NSIINPUTSTREAMLENGTHCALLBACK
88 
nsBufferedInputStream()89   nsBufferedInputStream() : nsBufferedStream() {}
90 
91   static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
92 
Source()93   nsIInputStream* Source() { return (nsIInputStream*)mStream.get(); }
94 
95   /**
96    * If there's a reference/pointer to an nsBufferedInputStream BEFORE calling
97    * Init() AND the intent is to ultimately convert/assign that
98    * reference/pointer to an nsIInputStream, DO NOT use that initial
99    * reference/pointer. Instead, use the value of QueryInterface-ing to an
100    * nsIInputStream (and, again, the QueryInterface must be performed after
101    * Init()). This is because nsBufferedInputStream has multiple underlying
102    * nsIInputStreams (one from nsIBufferedInputStream and one from
103    * nsIAsyncInputStream), and the correct base nsIInputStream to use will be
104    * unknown until the final value of mIsAsyncInputStream is set in Init().
105    *
106    * This method, however, does just that but also hides the QI details and
107    * will assert if called before Init().
108    */
109   already_AddRefed<nsIInputStream> GetInputStream();
110 
111  protected:
112   virtual ~nsBufferedInputStream() = default;
113 
114   template <typename M>
115   void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
116                          FileDescriptorArray& aFileDescriptors,
117                          bool aDelayedStart, uint32_t aMaxSize,
118                          uint32_t* aSizeUsed, M* aManager);
119 
120   NS_IMETHOD Fill() override;
Flush()121   NS_IMETHOD Flush() override { return NS_OK; }  // no-op for input streams
122 
123   mozilla::Mutex mMutex{"nsBufferedInputStream::mMutex"};
124 
125   // This value is protected by mutex.
126   nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback;
127 
128   // This value is protected by mutex.
129   nsCOMPtr<nsIInputStreamLengthCallback> mAsyncInputStreamLengthCallback;
130 
131   bool mIsIPCSerializable{true};
132   bool mIsAsyncInputStream{false};
133   bool mIsCloneableInputStream{false};
134   bool mIsInputStreamLength{false};
135   bool mIsAsyncInputStreamLength{false};
136 };
137 
138 ////////////////////////////////////////////////////////////////////////////////
139 
140 class nsBufferedOutputStream : public nsBufferedStream,
141                                public nsISafeOutputStream,
142                                public nsIBufferedOutputStream,
143                                public nsIStreamBufferAccess {
144  public:
145   NS_DECL_ISUPPORTS_INHERITED
146   NS_DECL_NSIOUTPUTSTREAM
147   NS_DECL_NSISAFEOUTPUTSTREAM
148   NS_DECL_NSIBUFFEREDOUTPUTSTREAM
149   NS_DECL_NSISTREAMBUFFERACCESS
150 
nsBufferedOutputStream()151   nsBufferedOutputStream() : nsBufferedStream() {}
152 
153   static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult);
154 
Sink()155   nsIOutputStream* Sink() { return (nsIOutputStream*)mStream.get(); }
156 
157  protected:
~nsBufferedOutputStream()158   virtual ~nsBufferedOutputStream() { nsBufferedOutputStream::Close(); }
159 
Fill()160   NS_IMETHOD Fill() override { return NS_OK; }  // no-op for output streams
161 
162   nsCOMPtr<nsISafeOutputStream> mSafeStream;  // QI'd from mStream
163 };
164 
165 ////////////////////////////////////////////////////////////////////////////////
166 
167 #endif  // nsBufferedStreams_h__
168