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_CopyBufferToSegment(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 nsIOutputStream::WriteSegments to
218  * copy data into the nsIOutputStream from a nsIInputStream passed as the
219  * aClosure parameter to the WriteSegments function.
220  *
221  * @see nsIOutputStream.idl for a description of this function's parameters.
222  */
223 extern nsresult NS_CopyStreamToSegment(nsIOutputStream* aOutputStream,
224                                        void* aClosure, char* aToSegment,
225                                        uint32_t aFromOffset, uint32_t aCount,
226                                        uint32_t* aReadCount);
227 
228 /**
229  * This function is intended to be passed to nsIInputStream::ReadSegments to
230  * discard data from the nsIInputStream.  This can be used to efficiently read
231  * data from the stream without actually copying any bytes.
232  *
233  * @see nsIInputStream.idl for a description of this function's parameters.
234  */
235 extern nsresult NS_DiscardSegment(nsIInputStream* aInputStream, void* aClosure,
236                                   const char* aFromSegment, uint32_t aToOffset,
237                                   uint32_t aCount, uint32_t* aWriteCount);
238 
239 /**
240  * This function is intended to be passed to nsIInputStream::ReadSegments to
241  * adjust the aInputStream parameter passed to a consumer's WriteSegmentFun.
242  * The aClosure parameter must be a pointer to a nsWriteSegmentThunk object.
243  * The mStream and mClosure members of that object will be passed to the mFun
244  * function, with the remainder of the parameters being what are passed to
245  * NS_WriteSegmentThunk.
246  *
247  * This function comes in handy when implementing ReadSegments in terms of an
248  * inner stream's ReadSegments.
249  */
250 extern nsresult NS_WriteSegmentThunk(nsIInputStream* aInputStream,
251                                      void* aClosure, const char* aFromSegment,
252                                      uint32_t aToOffset, uint32_t aCount,
253                                      uint32_t* aWriteCount);
254 
255 struct MOZ_STACK_CLASS nsWriteSegmentThunk {
256   nsCOMPtr<nsIInputStream> mStream;
257   nsWriteSegmentFun mFun;
258   void* mClosure;
259 };
260 
261 /**
262  * Read data from aInput and store in aDest.  A non-zero aKeep will keep that
263  * many bytes from aDest (from the end).  New data is appended after the kept
264  * bytes (if any).  aDest's new length on returning from this function is
265  * aKeep + aNewBytes and is guaranteed to be less than or equal to aDest's
266  * current capacity.
267  * @param aDest the array to fill
268  * @param aInput the stream to read from
269  * @param aKeep number of bytes to keep (0 <= aKeep <= aDest.Length())
270  * @param aNewBytes (out) number of bytes read from aInput or zero if Read()
271  *        failed
272  * @return the result from aInput->Read(...)
273  */
274 extern nsresult NS_FillArray(FallibleTArray<char>& aDest,
275                              nsIInputStream* aInput, uint32_t aKeep,
276                              uint32_t* aNewBytes);
277 
278 /**
279  * Return true if the given stream can be directly cloned.
280  */
281 extern bool NS_InputStreamIsCloneable(nsIInputStream* aSource);
282 
283 /**
284  * Clone the provided source stream in the most efficient way possible.  This
285  * first attempts to QI to nsICloneableInputStream to use Clone().  If that is
286  * not supported or its cloneable attribute is false, then a fallback clone is
287  * provided by copying the source to a pipe.  In this case the caller must
288  * replace the source stream with the resulting replacement stream.  The clone
289  * and the replacement stream are then cloneable using nsICloneableInputStream
290  * without duplicating memory.  This fallback clone using the pipe is only
291  * performed if a replacement stream parameter is also passed in.
292  * @param aSource         The input stream to clone.
293  * @param aCloneOut       Required out parameter to hold resulting clone.
294  * @param aReplacementOut Optional out parameter to hold stream to replace
295  *                        original source stream after clone.  If not
296  *                        provided then the fallback clone process is not
297  *                        supported and a non-cloneable source will result
298  *                        in failure.  Replacement streams are non-blocking.
299  * @return NS_OK on successful clone.  Error otherwise.
300  */
301 extern nsresult NS_CloneInputStream(nsIInputStream* aSource,
302                                     nsIInputStream** aCloneOut,
303                                     nsIInputStream** aReplacementOut = nullptr);
304 
305 /*
306  * This function returns a non-blocking nsIAsyncInputStream. Internally,
307  * different approaches are used based on what |aSource| is and what it
308  * implements.
309  *
310  * Note that this component takes the owninship of aSource.
311  *
312  * If the |aSource| is already a non-blocking and async stream,
313  * |aAsyncInputStream| will be equal to |aSource|.
314  *
315  * Otherwise, if |aSource| is just non-blocking, NonBlockingAsyncInputStream
316  * class is used in order to make it async.
317  *
318  * The last step is to use nsIStreamTransportService and create a pipe in order
319  * to expose a non-blocking async inputStream and read |aSource| data from
320  * a separate thread.
321  *
322  * In case we need to create a pipe, |aCloseWhenDone| will be used to create the
323  * inputTransport, |aFlags|, |aSegmentSize|, |asegmentCount| will be used to
324  * open the inputStream. If true, the input stream will be closed after it has
325  * been read. Read more in nsITransport.idl.
326  */
327 extern nsresult NS_MakeAsyncNonBlockingInputStream(
328     already_AddRefed<nsIInputStream> aSource,
329     nsIAsyncInputStream** aAsyncInputStream, bool aCloseWhenDone = true,
330     uint32_t aFlags = 0, uint32_t aSegmentSize = 0, uint32_t aSegmentCount = 0);
331 
332 #endif  // !nsStreamUtils_h__
333