1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef nsStreamUtils_h__
8 #define nsStreamUtils_h__
9 
10 #include "nsCOMPtr.h"
11 #include "nsStringFwd.h"
12 #include "nsIInputStream.h"
13 #include "nsTArray.h"
14 #include "nsIRunnable.h"
15 
16 class nsIAsyncInputStream;
17 class nsIOutputStream;
18 class nsIInputStreamCallback;
19 class nsIOutputStreamCallback;
20 class nsIEventTarget;
21 
22 /**
23  * A "one-shot" proxy of the OnInputStreamReady callback.  The resulting
24  * proxy object's OnInputStreamReady function may only be called once!  The
25  * proxy object ensures that the real notify object will be free'd on the
26  * thread corresponding to the given event target regardless of what thread
27  * the proxy object is destroyed on.
28  *
29  * This function is designed to be used to implement AsyncWait when the
30  * aTarget parameter is non-null.
31  *
32  * The optional aPriority parameter allows the input stream runnable events
33  * to be dispatched with a different priority than normal.
34  */
35 extern already_AddRefed<nsIInputStreamCallback> NS_NewInputStreamReadyEvent(
36     const char* aName, nsIInputStreamCallback* aNotify, nsIEventTarget* aTarget,
37     uint32_t aPriority = nsIRunnablePriority::PRIORITY_NORMAL);
38 
39 /**
40  * A "one-shot" proxy of the OnOutputStreamReady callback.  The resulting
41  * proxy object's OnOutputStreamReady function may only be called once!  The
42  * proxy object ensures that the real notify object will be free'd on the
43  * thread corresponding to the given event target regardless of what thread
44  * the proxy object is destroyed on.
45  *
46  * This function is designed to be used to implement AsyncWait when the
47  * aTarget parameter is non-null.
48  */
49 extern already_AddRefed<nsIOutputStreamCallback> NS_NewOutputStreamReadyEvent(
50     nsIOutputStreamCallback* aNotify, nsIEventTarget* aTarget);
51 
52 /* ------------------------------------------------------------------------- */
53 
54 enum nsAsyncCopyMode {
55   NS_ASYNCCOPY_VIA_READSEGMENTS,
56   NS_ASYNCCOPY_VIA_WRITESEGMENTS
57 };
58 
59 /**
60  * This function is called when a new chunk of data has been copied.  The
61  * reported count is the size of the current chunk.
62  */
63 typedef void (*nsAsyncCopyProgressFun)(void* closure, uint32_t count);
64 
65 /**
66  * This function is called when the async copy process completes.  The reported
67  * status is NS_OK on success and some error code on failure.
68  */
69 typedef void (*nsAsyncCopyCallbackFun)(void* closure, nsresult status);
70 
71 /**
72  * This function asynchronously copies data from the source to the sink. All
73  * data transfer occurs on the thread corresponding to the given event target.
74  * A null event target is not permitted.
75  *
76  * The copier handles blocking or non-blocking streams transparently.  If a
77  * stream operation returns NS_BASE_STREAM_WOULD_BLOCK, then the stream will
78  * be QI'd to nsIAsync{In,Out}putStream and its AsyncWait method will be used
79  * to determine when to resume copying.
80  *
81  * Source and sink are closed by default when copying finishes or when error
82  * occurs. Caller can prevent closing source or sink by setting aCloseSource
83  * or aCloseSink to false.
84  *
85  * Caller can obtain aCopierCtx to be able to cancel copying.
86  */
87 extern nsresult NS_AsyncCopy(
88     nsIInputStream* aSource, nsIOutputStream* aSink, nsIEventTarget* aTarget,
89     nsAsyncCopyMode aMode = NS_ASYNCCOPY_VIA_READSEGMENTS,
90     uint32_t aChunkSize = 4096, nsAsyncCopyCallbackFun aCallbackFun = nullptr,
91     void* aCallbackClosure = nullptr, bool aCloseSource = true,
92     bool aCloseSink = true, nsISupports** aCopierCtx = nullptr,
93     nsAsyncCopyProgressFun aProgressCallbackFun = nullptr);
94 
95 /**
96  * This function cancels copying started by function NS_AsyncCopy.
97  *
98  * @param aCopierCtx
99  *        Copier context returned by NS_AsyncCopy.
100  * @param aReason
101  *        A failure code indicating why the operation is being canceled.
102  *        It is an error to pass a success code.
103  */
104 extern nsresult NS_CancelAsyncCopy(nsISupports* aCopierCtx, nsresult aReason);
105 
106 /**
107  * This function copies all of the available data from the stream (up to at
108  * most aMaxCount bytes) into the given buffer.  The buffer is truncated at
109  * the start of the function.
110  *
111  * If an error occurs while reading from the stream or while attempting to
112  * resize the buffer, then the corresponding error code is returned from this
113  * function, and any data that has already been read will be returned in the
114  * output buffer.  This allows one to use this function with a non-blocking
115  * input stream that may return NS_BASE_STREAM_WOULD_BLOCK if it only has
116  * partial data available.
117  *
118  * @param aSource
119  *        The input stream to read.
120  * @param aMaxCount
121  *        The maximum number of bytes to consume from the stream.  Pass the
122  *        value UINT32_MAX to consume the entire stream.  The number of
123  *        bytes actually read is given by the length of aBuffer upon return.
124  * @param aBuffer
125  *        The string object that will contain the stream data upon return.
126  *        Note: The data copied to the string may contain null bytes and may
127  *        contain non-ASCII values.
128  */
129 extern nsresult NS_ConsumeStream(nsIInputStream* aSource, uint32_t aMaxCount,
130                                  nsACString& aBuffer);
131 
132 /**
133  * Just like the above, but consumes into an nsTArray<uint8_t>.
134  */
135 extern nsresult NS_ConsumeStream(nsIInputStream* aSource, uint32_t aMaxCount,
136                                  nsTArray<uint8_t>& aBuffer);
137 
138 /**
139  * This function tests whether or not the input stream is buffered. A buffered
140  * input stream is one that implements readSegments.  The test for this is to
141  * 1/ check whether the input stream implements nsIBufferedInputStream;
142  * 2/ if not, call readSegments, without actually consuming any data from the
143  * stream, to verify that it functions.
144  *
145  * NOTE: If the stream is non-blocking and has no data available yet, then this
146  * test will fail.  In that case, we return false even though the test is not
147  * really conclusive.
148  *
149  * PERFORMANCE NOTE: If the stream does not implement nsIBufferedInputStream,
150  * calling readSegments may cause I/O. Therefore, you should avoid calling
151  * this function from the main thread.
152  *
153  * @param aInputStream
154  *        The input stream to test.
155  */
156 extern bool NS_InputStreamIsBuffered(nsIInputStream* aInputStream);
157 
158 /**
159  * This function tests whether or not the output stream is buffered.  A
160  * buffered output stream is one that implements writeSegments.  The test for
161  * this is to:
162  * 1/ check whether the output stream implements nsIBufferedOutputStream;
163  * 2/ if not, call writeSegments, without actually writing any data into
164  * the stream, to verify that it functions.
165  *
166  * NOTE: If the stream is non-blocking and has no available space yet, then
167  * this test will fail.  In that case, we return false even though the test is
168  * not really conclusive.
169  *
170  * PERFORMANCE NOTE: If the stream does not implement nsIBufferedOutputStream,
171  * calling writeSegments may cause I/O. Therefore, you should avoid calling
172  * this function from the main thread.
173  *
174  * @param aOutputStream
175  *        The output stream to test.
176  */
177 extern bool NS_OutputStreamIsBuffered(nsIOutputStream* aOutputStream);
178 
179 /**
180  * This function is intended to be passed to nsIInputStream::ReadSegments to
181  * copy data from the nsIInputStream into a nsIOutputStream passed as the
182  * aClosure parameter to the ReadSegments function.
183  *
184  * @see nsIInputStream.idl for a description of this function's parameters.
185  */
186 extern nsresult NS_CopySegmentToStream(nsIInputStream* aInputStream,
187                                        void* aClosure, const char* aFromSegment,
188                                        uint32_t aToOffset, uint32_t aCount,
189                                        uint32_t* aWriteCount);
190 
191 /**
192  * This function is intended to be passed to nsIInputStream::ReadSegments to
193  * copy data from the nsIInputStream into a character buffer passed as the
194  * aClosure parameter to the ReadSegments function.  The character buffer
195  * must be at least as large as the aCount parameter passed to ReadSegments.
196  *
197  * @see nsIInputStream.idl for a description of this function's parameters.
198  */
199 extern nsresult NS_CopySegmentToBuffer(nsIInputStream* aInputStream,
200                                        void* aClosure, const char* aFromSegment,
201                                        uint32_t aToOffset, uint32_t aCount,
202                                        uint32_t* aWriteCount);
203 
204 /**
205  * This function is intended to be passed to nsIOutputStream::WriteSegments to
206  * copy data into the nsIOutputStream from a character buffer passed as the
207  * aClosure parameter to the WriteSegments function.
208  *
209  * @see nsIOutputStream.idl for a description of this function's parameters.
210  */
211 extern nsresult NS_CopySegmentToBuffer(nsIOutputStream* aOutputStream,
212                                        void* aClosure, char* aToSegment,
213                                        uint32_t aFromOffset, uint32_t aCount,
214                                        uint32_t* aReadCount);
215 
216 /**
217  * This function is intended to be passed to nsIInputStream::ReadSegments to
218  * discard data from the nsIInputStream.  This can be used to efficiently read
219  * data from the stream without actually copying any bytes.
220  *
221  * @see nsIInputStream.idl for a description of this function's parameters.
222  */
223 extern nsresult NS_DiscardSegment(nsIInputStream* aInputStream, void* aClosure,
224                                   const char* aFromSegment, uint32_t aToOffset,
225                                   uint32_t aCount, uint32_t* aWriteCount);
226 
227 /**
228  * This function is intended to be passed to nsIInputStream::ReadSegments to
229  * adjust the aInputStream parameter passed to a consumer's WriteSegmentFun.
230  * The aClosure parameter must be a pointer to a nsWriteSegmentThunk object.
231  * The mStream and mClosure members of that object will be passed to the mFun
232  * function, with the remainder of the parameters being what are passed to
233  * NS_WriteSegmentThunk.
234  *
235  * This function comes in handy when implementing ReadSegments in terms of an
236  * inner stream's ReadSegments.
237  */
238 extern nsresult NS_WriteSegmentThunk(nsIInputStream* aInputStream,
239                                      void* aClosure, const char* aFromSegment,
240                                      uint32_t aToOffset, uint32_t aCount,
241                                      uint32_t* aWriteCount);
242 
243 struct MOZ_STACK_CLASS nsWriteSegmentThunk {
244   nsCOMPtr<nsIInputStream> mStream;
245   nsWriteSegmentFun mFun;
246   void* mClosure;
247 };
248 
249 /**
250  * Read data from aInput and store in aDest.  A non-zero aKeep will keep that
251  * many bytes from aDest (from the end).  New data is appended after the kept
252  * bytes (if any).  aDest's new length on returning from this function is
253  * aKeep + aNewBytes and is guaranteed to be less than or equal to aDest's
254  * current capacity.
255  * @param aDest the array to fill
256  * @param aInput the stream to read from
257  * @param aKeep number of bytes to keep (0 <= aKeep <= aDest.Length())
258  * @param aNewBytes (out) number of bytes read from aInput or zero if Read()
259  *        failed
260  * @return the result from aInput->Read(...)
261  */
262 extern nsresult NS_FillArray(FallibleTArray<char>& aDest,
263                              nsIInputStream* aInput, uint32_t aKeep,
264                              uint32_t* aNewBytes);
265 
266 /**
267  * Return true if the given stream can be directly cloned.
268  */
269 extern bool NS_InputStreamIsCloneable(nsIInputStream* aSource);
270 
271 /**
272  * Clone the provided source stream in the most efficient way possible.  This
273  * first attempts to QI to nsICloneableInputStream to use Clone().  If that is
274  * not supported or its cloneable attribute is false, then a fallback clone is
275  * provided by copying the source to a pipe.  In this case the caller must
276  * replace the source stream with the resulting replacement stream.  The clone
277  * and the replacement stream are then cloneable using nsICloneableInputStream
278  * without duplicating memory.  This fallback clone using the pipe is only
279  * performed if a replacement stream parameter is also passed in.
280  * @param aSource         The input stream to clone.
281  * @param aCloneOut       Required out parameter to hold resulting clone.
282  * @param aReplacementOut Optional out parameter to hold stream to replace
283  *                        original source stream after clone.  If not
284  *                        provided then the fallback clone process is not
285  *                        supported and a non-cloneable source will result
286  *                        in failure.  Replacement streams are non-blocking.
287  * @return NS_OK on successful clone.  Error otherwise.
288  */
289 extern nsresult NS_CloneInputStream(nsIInputStream* aSource,
290                                     nsIInputStream** aCloneOut,
291                                     nsIInputStream** aReplacementOut = nullptr);
292 
293 /*
294  * This function returns a non-blocking nsIAsyncInputStream. Internally,
295  * different approaches are used based on what |aSource| is and what it
296  * implements.
297  *
298  * Note that this component takes the owninship of aSource.
299  *
300  * If the |aSource| is already a non-blocking and async stream,
301  * |aAsyncInputStream| will be equal to |aSource|.
302  *
303  * Otherwise, if |aSource| is just non-blocking, NonBlockingAsyncInputStream
304  * class is used in order to make it async.
305  *
306  * The last step is to use nsIStreamTransportService and create a pipe in order
307  * to expose a non-blocking async inputStream and read |aSource| data from
308  * a separate thread.
309  *
310  * In case we need to create a pipe, |aCloseWhenDone| will be used to create the
311  * inputTransport, |aFlags|, |aSegmentSize|, |asegmentCount| will be used to
312  * open the inputStream. If true, the input stream will be closed after it has
313  * been read. Read more in nsITransport.idl.
314  */
315 extern nsresult NS_MakeAsyncNonBlockingInputStream(
316     already_AddRefed<nsIInputStream> aSource,
317     nsIAsyncInputStream** aAsyncInputStream, bool aCloseWhenDone = true,
318     uint32_t aFlags = 0, uint32_t aSegmentSize = 0, uint32_t aSegmentCount = 0);
319 
320 #endif  // !nsStreamUtils_h__
321