Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / netwerk / base / src / nsBufferedStreams.cpp
blob4d5fb996b9f1c31d4186063c4631cf9728f67490
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsBufferedStreams.h"
39 #include "nsStreamUtils.h"
40 #include "nsCRT.h"
42 #ifdef DEBUG_brendan
43 # define METERING
44 #endif
46 #ifdef METERING
47 # include <stdio.h>
48 # define METER(x) x
49 # define MAX_BIG_SEEKS 20
51 static struct {
52 PRUint32 mSeeksWithinBuffer;
53 PRUint32 mSeeksOutsideBuffer;
54 PRUint32 mBufferReadUponSeek;
55 PRUint32 mBufferUnreadUponSeek;
56 PRUint32 mBytesReadFromBuffer;
57 PRUint32 mBigSeekIndex;
58 struct {
59 PRInt64 mOldOffset;
60 PRInt64 mNewOffset;
61 } mBigSeek[MAX_BIG_SEEKS];
62 } bufstats;
63 #else
64 # define METER(x) /* nothing */
65 #endif
67 ////////////////////////////////////////////////////////////////////////////////
68 // nsBufferedStream
70 nsBufferedStream::nsBufferedStream()
71 : mBuffer(nsnull),
72 mBufferStartOffset(0),
73 mCursor(0),
74 mFillPoint(0),
75 mStream(nsnull),
76 mBufferDisabled(PR_FALSE),
77 mGetBufferCount(0)
81 nsBufferedStream::~nsBufferedStream()
83 Close();
86 NS_IMPL_THREADSAFE_ISUPPORTS1(nsBufferedStream, nsISeekableStream)
88 nsresult
89 nsBufferedStream::Init(nsISupports* stream, PRUint32 bufferSize)
91 NS_ASSERTION(stream, "need to supply a stream");
92 NS_ASSERTION(mStream == nsnull, "already inited");
93 mStream = stream;
94 NS_IF_ADDREF(mStream);
95 mBufferSize = bufferSize;
96 mBufferStartOffset = 0;
97 mCursor = 0;
98 mBuffer = new char[bufferSize];
99 if (mBuffer == nsnull)
100 return NS_ERROR_OUT_OF_MEMORY;
101 return NS_OK;
104 nsresult
105 nsBufferedStream::Close()
107 NS_IF_RELEASE(mStream);
108 if (mBuffer) {
109 delete[] mBuffer;
110 mBuffer = nsnull;
111 mBufferSize = 0;
112 mBufferStartOffset = 0;
113 mCursor = 0;
114 mFillPoint = 0;
116 #ifdef METERING
118 static FILE *tfp;
119 if (!tfp) {
120 tfp = fopen("/tmp/bufstats", "w");
121 if (tfp)
122 setvbuf(tfp, NULL, _IOLBF, 0);
124 if (tfp) {
125 fprintf(tfp, "seeks within buffer: %u\n",
126 bufstats.mSeeksWithinBuffer);
127 fprintf(tfp, "seeks outside buffer: %u\n",
128 bufstats.mSeeksOutsideBuffer);
129 fprintf(tfp, "buffer read on seek: %u\n",
130 bufstats.mBufferReadUponSeek);
131 fprintf(tfp, "buffer unread on seek: %u\n",
132 bufstats.mBufferUnreadUponSeek);
133 fprintf(tfp, "bytes read from buffer: %u\n",
134 bufstats.mBytesReadFromBuffer);
135 for (PRUint32 i = 0; i < bufstats.mBigSeekIndex; i++) {
136 fprintf(tfp, "bigseek[%u] = {old: %u, new: %u}\n",
138 bufstats.mBigSeek[i].mOldOffset,
139 bufstats.mBigSeek[i].mNewOffset);
143 #endif
144 return NS_OK;
147 NS_IMETHODIMP
148 nsBufferedStream::Seek(PRInt32 whence, PRInt64 offset)
150 if (mStream == nsnull)
151 return NS_BASE_STREAM_CLOSED;
153 // If the underlying stream isn't a random access store, then fail early.
154 // We could possibly succeed for the case where the seek position denotes
155 // something that happens to be read into the buffer, but that would make
156 // the failure data-dependent.
157 nsresult rv;
158 nsCOMPtr<nsISeekableStream> ras = do_QueryInterface(mStream, &rv);
159 if (NS_FAILED(rv)) return rv;
161 nsInt64 absPos;
162 switch (whence) {
163 case nsISeekableStream::NS_SEEK_SET:
164 absPos = offset;
165 break;
166 case nsISeekableStream::NS_SEEK_CUR:
167 absPos = mBufferStartOffset;
168 absPos += mCursor;
169 absPos += offset;
170 break;
171 case nsISeekableStream::NS_SEEK_END:
172 absPos = -1;
173 break;
174 default:
175 NS_NOTREACHED("bogus seek whence parameter");
176 return NS_ERROR_UNEXPECTED;
179 // Let mCursor point into the existing buffer if the new position is
180 // between the current cursor and the mFillPoint "fencepost" -- the
181 // client may never get around to a Read or Write after this Seek.
182 // Read and Write worry about flushing and filling in that event.
183 PRUint32 offsetInBuffer = PRUint32(absPos - mBufferStartOffset);
184 if (offsetInBuffer <= mFillPoint) {
185 METER(bufstats.mSeeksWithinBuffer++);
186 mCursor = offsetInBuffer;
187 return NS_OK;
190 METER(bufstats.mSeeksOutsideBuffer++);
191 METER(bufstats.mBufferReadUponSeek += mCursor);
192 METER(bufstats.mBufferUnreadUponSeek += mFillPoint - mCursor);
193 rv = Flush();
194 if (NS_FAILED(rv)) return rv;
196 rv = ras->Seek(whence, offset);
197 if (NS_FAILED(rv)) return rv;
199 METER(if (bufstats.mBigSeekIndex < MAX_BIG_SEEKS)
200 bufstats.mBigSeek[bufstats.mBigSeekIndex].mOldOffset =
201 mBufferStartOffset + nsInt64(mCursor));
202 const nsInt64 minus1 = -1;
203 if (absPos == minus1) {
204 // then we had the SEEK_END case, above
205 PRInt64 tellPos;
206 rv = ras->Tell(&tellPos);
207 mBufferStartOffset = tellPos;
208 if (NS_FAILED(rv)) return rv;
210 else {
211 mBufferStartOffset = absPos;
213 METER(if (bufstats.mBigSeekIndex < MAX_BIG_SEEKS)
214 bufstats.mBigSeek[bufstats.mBigSeekIndex++].mNewOffset =
215 mBufferStartOffset);
217 mFillPoint = mCursor = 0;
218 return Fill();
221 NS_IMETHODIMP
222 nsBufferedStream::Tell(PRInt64 *result)
224 if (mStream == nsnull)
225 return NS_BASE_STREAM_CLOSED;
227 nsInt64 result64 = mBufferStartOffset;
228 result64 += mCursor;
229 *result = result64;
230 return NS_OK;
233 NS_IMETHODIMP
234 nsBufferedStream::SetEOF()
236 if (mStream == nsnull)
237 return NS_BASE_STREAM_CLOSED;
239 nsresult rv;
240 nsCOMPtr<nsISeekableStream> ras = do_QueryInterface(mStream, &rv);
241 if (NS_FAILED(rv)) return rv;
243 return ras->SetEOF();
246 ////////////////////////////////////////////////////////////////////////////////
247 // nsBufferedInputStream
249 NS_IMPL_ISUPPORTS_INHERITED3(nsBufferedInputStream,
250 nsBufferedStream,
251 nsIInputStream,
252 nsIBufferedInputStream,
253 nsIStreamBufferAccess)
255 NS_METHOD
256 nsBufferedInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
258 NS_ENSURE_NO_AGGREGATION(aOuter);
260 nsBufferedInputStream* stream = new nsBufferedInputStream();
261 if (stream == nsnull)
262 return NS_ERROR_OUT_OF_MEMORY;
263 NS_ADDREF(stream);
264 nsresult rv = stream->QueryInterface(aIID, aResult);
265 NS_RELEASE(stream);
266 return rv;
269 NS_IMETHODIMP
270 nsBufferedInputStream::Init(nsIInputStream* stream, PRUint32 bufferSize)
272 return nsBufferedStream::Init(stream, bufferSize);
275 NS_IMETHODIMP
276 nsBufferedInputStream::Close()
278 nsresult rv1 = NS_OK, rv2;
279 if (mStream) {
280 rv1 = Source()->Close();
281 NS_RELEASE(mStream);
283 rv2 = nsBufferedStream::Close();
284 if (NS_FAILED(rv1)) return rv1;
285 return rv2;
288 NS_IMETHODIMP
289 nsBufferedInputStream::Available(PRUint32 *result)
291 nsresult rv = NS_OK;
292 *result = 0;
293 if (mStream) {
294 rv = Source()->Available(result);
296 *result += (mFillPoint - mCursor);
297 return rv;
300 NS_IMETHODIMP
301 nsBufferedInputStream::Read(char * buf, PRUint32 count, PRUint32 *result)
303 if (mBufferDisabled) {
304 if (!mStream) {
305 *result = 0;
306 return NS_OK;
308 nsresult rv = Source()->Read(buf, count, result);
309 if (NS_SUCCEEDED(rv))
310 mBufferStartOffset += *result; // so nsBufferedStream::Tell works
311 return rv;
314 return ReadSegments(NS_CopySegmentToBuffer, buf, count, result);
317 NS_IMETHODIMP
318 nsBufferedInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
319 PRUint32 count, PRUint32 *result)
321 *result = 0;
323 if (!mStream)
324 return NS_OK;
326 nsresult rv = NS_OK;
327 while (count > 0) {
328 PRUint32 amt = PR_MIN(count, mFillPoint - mCursor);
329 if (amt > 0) {
330 PRUint32 read = 0;
331 rv = writer(this, closure, mBuffer + mCursor, *result, amt, &read);
332 if (NS_FAILED(rv)) {
333 // errors returned from the writer end here!
334 rv = NS_OK;
335 break;
337 *result += read;
338 count -= read;
339 mCursor += read;
341 else {
342 rv = Fill();
343 if (NS_FAILED(rv) || mFillPoint == mCursor)
344 break;
347 return (*result > 0) ? NS_OK : rv;
350 NS_IMETHODIMP
351 nsBufferedInputStream::IsNonBlocking(PRBool *aNonBlocking)
353 if (mStream)
354 return Source()->IsNonBlocking(aNonBlocking);
355 return NS_ERROR_NOT_INITIALIZED;
358 NS_IMETHODIMP
359 nsBufferedInputStream::Fill()
361 if (mBufferDisabled)
362 return NS_OK;
363 NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_INITIALIZED);
365 nsresult rv;
366 PRInt32 rem = PRInt32(mFillPoint - mCursor);
367 if (rem > 0) {
368 // slide the remainder down to the start of the buffer
369 // |<------------->|<--rem-->|<--->|
370 // b c f s
371 memcpy(mBuffer, mBuffer + mCursor, rem);
373 mBufferStartOffset += mCursor;
374 mFillPoint = rem;
375 mCursor = 0;
377 PRUint32 amt;
378 rv = Source()->Read(mBuffer + mFillPoint, mBufferSize - mFillPoint, &amt);
379 if (NS_FAILED(rv)) return rv;
381 mFillPoint += amt;
382 return NS_OK;
385 NS_IMETHODIMP_(char*)
386 nsBufferedInputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask)
388 NS_ASSERTION(mGetBufferCount == 0, "nested GetBuffer!");
389 if (mGetBufferCount != 0)
390 return nsnull;
392 if (mBufferDisabled)
393 return nsnull;
395 char* buf = mBuffer + mCursor;
396 PRUint32 rem = mFillPoint - mCursor;
397 if (rem == 0) {
398 if (NS_FAILED(Fill()))
399 return nsnull;
400 buf = mBuffer + mCursor;
401 rem = mFillPoint - mCursor;
404 PRUint32 mod = (NS_PTR_TO_INT32(buf) & aAlignMask);
405 if (mod) {
406 PRUint32 pad = aAlignMask + 1 - mod;
407 if (pad > rem)
408 return nsnull;
410 memset(buf, 0, pad);
411 mCursor += pad;
412 buf += pad;
413 rem -= pad;
416 if (aLength > rem)
417 return nsnull;
418 mGetBufferCount++;
419 return buf;
422 NS_IMETHODIMP_(void)
423 nsBufferedInputStream::PutBuffer(char* aBuffer, PRUint32 aLength)
425 NS_ASSERTION(mGetBufferCount == 1, "stray PutBuffer!");
426 if (--mGetBufferCount != 0)
427 return;
429 NS_ASSERTION(mCursor + aLength <= mFillPoint, "PutBuffer botch");
430 mCursor += aLength;
433 NS_IMETHODIMP
434 nsBufferedInputStream::DisableBuffering()
436 NS_ASSERTION(!mBufferDisabled, "redundant call to DisableBuffering!");
437 NS_ASSERTION(mGetBufferCount == 0,
438 "DisableBuffer call between GetBuffer and PutBuffer!");
439 if (mGetBufferCount != 0)
440 return NS_ERROR_UNEXPECTED;
442 // Empty the buffer so nsBufferedStream::Tell works.
443 mBufferStartOffset += mCursor;
444 mFillPoint = mCursor = 0;
445 mBufferDisabled = PR_TRUE;
446 return NS_OK;
449 NS_IMETHODIMP
450 nsBufferedInputStream::EnableBuffering()
452 NS_ASSERTION(mBufferDisabled, "gratuitous call to EnableBuffering!");
453 mBufferDisabled = PR_FALSE;
454 return NS_OK;
457 NS_IMETHODIMP
458 nsBufferedInputStream::GetUnbufferedStream(nsISupports* *aStream)
460 // Empty the buffer so subsequent i/o trumps any buffered data.
461 mBufferStartOffset += mCursor;
462 mFillPoint = mCursor = 0;
464 *aStream = mStream;
465 NS_IF_ADDREF(*aStream);
466 return NS_OK;
469 ////////////////////////////////////////////////////////////////////////////////
470 // nsBufferedOutputStream
472 NS_IMPL_ADDREF_INHERITED(nsBufferedOutputStream, nsBufferedStream)
473 NS_IMPL_RELEASE_INHERITED(nsBufferedOutputStream, nsBufferedStream)
474 // This QI uses NS_INTERFACE_MAP_ENTRY_CONDITIONAL to check for
475 // non-nullness of mSafeStream.
476 NS_INTERFACE_MAP_BEGIN(nsBufferedOutputStream)
477 NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
478 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISafeOutputStream, mSafeStream)
479 NS_INTERFACE_MAP_ENTRY(nsIBufferedOutputStream)
480 NS_INTERFACE_MAP_ENTRY(nsIStreamBufferAccess)
481 NS_INTERFACE_MAP_END_INHERITING(nsBufferedStream)
483 NS_METHOD
484 nsBufferedOutputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
486 NS_ENSURE_NO_AGGREGATION(aOuter);
488 nsBufferedOutputStream* stream = new nsBufferedOutputStream();
489 if (stream == nsnull)
490 return NS_ERROR_OUT_OF_MEMORY;
491 NS_ADDREF(stream);
492 nsresult rv = stream->QueryInterface(aIID, aResult);
493 NS_RELEASE(stream);
494 return rv;
497 NS_IMETHODIMP
498 nsBufferedOutputStream::Init(nsIOutputStream* stream, PRUint32 bufferSize)
500 // QI stream to an nsISafeOutputStream, to see if we should support it
501 mSafeStream = do_QueryInterface(stream);
503 return nsBufferedStream::Init(stream, bufferSize);
506 NS_IMETHODIMP
507 nsBufferedOutputStream::Close()
509 nsresult rv1, rv2 = NS_OK, rv3;
510 rv1 = Flush();
511 // If we fail to Flush all the data, then we close anyway and drop the
512 // remaining data in the buffer. We do this because it's what Unix does
513 // for fclose and close. However, we report the error from Flush anyway.
514 if (mStream) {
515 rv2 = Sink()->Close();
516 NS_RELEASE(mStream);
518 rv3 = nsBufferedStream::Close();
519 if (NS_FAILED(rv1)) return rv1;
520 if (NS_FAILED(rv2)) return rv2;
521 return rv3;
524 NS_IMETHODIMP
525 nsBufferedOutputStream::Write(const char *buf, PRUint32 count, PRUint32 *result)
527 nsresult rv = NS_OK;
528 PRUint32 written = 0;
529 while (count > 0) {
530 PRUint32 amt = PR_MIN(count, mBufferSize - mCursor);
531 if (amt > 0) {
532 memcpy(mBuffer + mCursor, buf + written, amt);
533 written += amt;
534 count -= amt;
535 mCursor += amt;
536 if (mFillPoint < mCursor)
537 mFillPoint = mCursor;
539 else {
540 NS_ASSERTION(mFillPoint, "iloop in nsBufferedOutputStream::Write!");
541 rv = Flush();
542 if (NS_FAILED(rv)) break;
545 *result = written;
546 return (written > 0) ? NS_OK : rv;
549 NS_IMETHODIMP
550 nsBufferedOutputStream::Flush()
552 nsresult rv;
553 PRUint32 amt;
554 if (!mStream) {
555 // Stream already cancelled/flushed; probably because of error.
556 return NS_OK;
558 rv = Sink()->Write(mBuffer, mFillPoint, &amt);
559 if (NS_FAILED(rv)) return rv;
560 mBufferStartOffset += amt;
561 if (amt == mFillPoint) {
562 mFillPoint = mCursor = 0;
563 return NS_OK; // flushed everything
566 // slide the remainder down to the start of the buffer
567 // |<-------------->|<---|----->|
568 // b a c s
569 PRUint32 rem = mFillPoint - amt;
570 memcpy(mBuffer, mBuffer + amt, rem);
571 mFillPoint = mCursor = rem;
572 return NS_ERROR_FAILURE; // didn't flush all
575 // nsISafeOutputStream
576 NS_IMETHODIMP
577 nsBufferedOutputStream::Finish()
579 // flush the stream, to write out any buffered data...
580 nsresult rv = nsBufferedOutputStream::Flush();
581 if (NS_FAILED(rv))
582 NS_WARNING("failed to flush buffered data! possible dataloss");
584 // ... and finish the underlying stream...
585 if (NS_SUCCEEDED(rv))
586 rv = mSafeStream->Finish();
587 else
588 Sink()->Close();
590 // ... and close the buffered stream, so any further attempts to flush/close
591 // the buffered stream won't cause errors.
592 nsBufferedStream::Close();
594 return rv;
597 static NS_METHOD
598 nsReadFromInputStream(nsIOutputStream* outStr,
599 void* closure,
600 char* toRawSegment,
601 PRUint32 offset,
602 PRUint32 count,
603 PRUint32 *readCount)
605 nsIInputStream* fromStream = (nsIInputStream*)closure;
606 return fromStream->Read(toRawSegment, count, readCount);
609 NS_IMETHODIMP
610 nsBufferedOutputStream::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
612 return WriteSegments(nsReadFromInputStream, inStr, count, _retval);
615 NS_IMETHODIMP
616 nsBufferedOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
618 *_retval = 0;
619 nsresult rv;
620 while (count > 0) {
621 PRUint32 left = PR_MIN(count, mBufferSize - mCursor);
622 if (left == 0) {
623 rv = Flush();
624 if (NS_FAILED(rv))
625 return rv;
627 continue;
630 PRUint32 read = 0;
631 rv = reader(this, closure, mBuffer + mCursor, *_retval, left, &read);
633 if (NS_FAILED(rv)) // If we have written some data, return ok
634 return (*_retval > 0) ? NS_OK : rv;
635 mCursor += read;
636 *_retval += read;
637 count -= read;
638 mFillPoint = PR_MAX(mFillPoint, mCursor);
640 return NS_OK;
643 NS_IMETHODIMP
644 nsBufferedOutputStream::IsNonBlocking(PRBool *aNonBlocking)
646 if (mStream)
647 return Sink()->IsNonBlocking(aNonBlocking);
648 return NS_ERROR_NOT_INITIALIZED;
651 NS_IMETHODIMP_(char*)
652 nsBufferedOutputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask)
654 NS_ASSERTION(mGetBufferCount == 0, "nested GetBuffer!");
655 if (mGetBufferCount != 0)
656 return nsnull;
658 if (mBufferDisabled)
659 return nsnull;
661 char* buf = mBuffer + mCursor;
662 PRUint32 rem = mBufferSize - mCursor;
663 if (rem == 0) {
664 if (NS_FAILED(Flush()))
665 return nsnull;
666 buf = mBuffer + mCursor;
667 rem = mBufferSize - mCursor;
670 PRUint32 mod = (NS_PTR_TO_INT32(buf) & aAlignMask);
671 if (mod) {
672 PRUint32 pad = aAlignMask + 1 - mod;
673 if (pad > rem)
674 return nsnull;
676 memset(buf, 0, pad);
677 mCursor += pad;
678 buf += pad;
679 rem -= pad;
682 if (aLength > rem)
683 return nsnull;
684 mGetBufferCount++;
685 return buf;
688 NS_IMETHODIMP_(void)
689 nsBufferedOutputStream::PutBuffer(char* aBuffer, PRUint32 aLength)
691 NS_ASSERTION(mGetBufferCount == 1, "stray PutBuffer!");
692 if (--mGetBufferCount != 0)
693 return;
695 NS_ASSERTION(mCursor + aLength <= mBufferSize, "PutBuffer botch");
696 mCursor += aLength;
697 if (mFillPoint < mCursor)
698 mFillPoint = mCursor;
701 NS_IMETHODIMP
702 nsBufferedOutputStream::DisableBuffering()
704 NS_ASSERTION(!mBufferDisabled, "redundant call to DisableBuffering!");
705 NS_ASSERTION(mGetBufferCount == 0,
706 "DisableBuffer call between GetBuffer and PutBuffer!");
707 if (mGetBufferCount != 0)
708 return NS_ERROR_UNEXPECTED;
710 // Empty the buffer so nsBufferedStream::Tell works.
711 nsresult rv = Flush();
712 if (NS_FAILED(rv))
713 return rv;
715 mBufferDisabled = PR_TRUE;
716 return NS_OK;
719 NS_IMETHODIMP
720 nsBufferedOutputStream::EnableBuffering()
722 NS_ASSERTION(mBufferDisabled, "gratuitous call to EnableBuffering!");
723 mBufferDisabled = PR_FALSE;
724 return NS_OK;
727 NS_IMETHODIMP
728 nsBufferedOutputStream::GetUnbufferedStream(nsISupports* *aStream)
730 // Empty the buffer so subsequent i/o trumps any buffered data.
731 if (mFillPoint) {
732 nsresult rv = Flush();
733 if (NS_FAILED(rv))
734 return rv;
737 *aStream = mStream;
738 NS_IF_ADDREF(*aStream);
739 return NS_OK;
742 ////////////////////////////////////////////////////////////////////////////////