Line data Source code
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 : /*
8 : * The storage stream provides an internal buffer that can be filled by a
9 : * client using a single output stream. One or more independent input streams
10 : * can be created to read the data out non-destructively. The implementation
11 : * uses a segmented buffer internally to avoid realloc'ing of large buffers,
12 : * with the attendant performance loss and heap fragmentation.
13 : */
14 :
15 : #include "nsAlgorithm.h"
16 : #include "nsStorageStream.h"
17 : #include "nsSegmentedBuffer.h"
18 : #include "nsStreamUtils.h"
19 : #include "nsCOMPtr.h"
20 : #include "nsICloneableInputStream.h"
21 : #include "nsIInputStream.h"
22 : #include "nsIIPCSerializableInputStream.h"
23 : #include "nsISeekableStream.h"
24 : #include "mozilla/Logging.h"
25 : #include "mozilla/Attributes.h"
26 : #include "mozilla/Likely.h"
27 : #include "mozilla/MathAlgorithms.h"
28 : #include "mozilla/ipc/InputStreamUtils.h"
29 :
30 : using mozilla::ipc::InputStreamParams;
31 : using mozilla::ipc::StringInputStreamParams;
32 : using mozilla::Maybe;
33 : using mozilla::Some;
34 :
35 : //
36 : // Log module for StorageStream logging...
37 : //
38 : // To enable logging (see prlog.h for full details):
39 : //
40 : // set MOZ_LOG=StorageStreamLog:5
41 : // set MOZ_LOG_FILE=storage.log
42 : //
43 : // This enables LogLevel::Debug level information and places all output in
44 : // the file storage.log.
45 : //
46 : static LazyLogModule sStorageStreamLog("nsStorageStream");
47 : #ifdef LOG
48 : #undef LOG
49 : #endif
50 : #define LOG(args) MOZ_LOG(sStorageStreamLog, mozilla::LogLevel::Debug, args)
51 :
52 0 : nsStorageStream::nsStorageStream()
53 : : mSegmentedBuffer(0), mSegmentSize(0), mWriteInProgress(false),
54 0 : mLastSegmentNum(-1), mWriteCursor(0), mSegmentEnd(0), mLogicalLength(0)
55 : {
56 0 : LOG(("Creating nsStorageStream [%p].\n", this));
57 0 : }
58 :
59 0 : nsStorageStream::~nsStorageStream()
60 : {
61 0 : delete mSegmentedBuffer;
62 0 : }
63 :
64 0 : NS_IMPL_ISUPPORTS(nsStorageStream,
65 : nsIStorageStream,
66 : nsIOutputStream)
67 :
68 : NS_IMETHODIMP
69 0 : nsStorageStream::Init(uint32_t aSegmentSize, uint32_t aMaxSize)
70 : {
71 0 : mSegmentedBuffer = new nsSegmentedBuffer();
72 0 : mSegmentSize = aSegmentSize;
73 0 : mSegmentSizeLog2 = mozilla::FloorLog2(aSegmentSize);
74 :
75 : // Segment size must be a power of two
76 0 : if (mSegmentSize != ((uint32_t)1 << mSegmentSizeLog2)) {
77 0 : return NS_ERROR_INVALID_ARG;
78 : }
79 :
80 0 : return mSegmentedBuffer->Init(aSegmentSize, aMaxSize);
81 : }
82 :
83 : NS_IMETHODIMP
84 0 : nsStorageStream::GetOutputStream(int32_t aStartingOffset,
85 : nsIOutputStream** aOutputStream)
86 : {
87 0 : if (NS_WARN_IF(!aOutputStream)) {
88 0 : return NS_ERROR_INVALID_ARG;
89 : }
90 0 : if (NS_WARN_IF(!mSegmentedBuffer)) {
91 0 : return NS_ERROR_NOT_INITIALIZED;
92 : }
93 :
94 0 : if (mWriteInProgress) {
95 0 : return NS_ERROR_NOT_AVAILABLE;
96 : }
97 :
98 0 : nsresult rv = Seek(aStartingOffset);
99 0 : if (NS_FAILED(rv)) {
100 0 : return rv;
101 : }
102 :
103 : // Enlarge the last segment in the buffer so that it is the same size as
104 : // all the other segments in the buffer. (It may have been realloc'ed
105 : // smaller in the Close() method.)
106 0 : if (mLastSegmentNum >= 0)
107 0 : if (mSegmentedBuffer->ReallocLastSegment(mSegmentSize)) {
108 : // Need to re-Seek, since realloc changed segment base pointer
109 0 : rv = Seek(aStartingOffset);
110 0 : if (NS_FAILED(rv)) {
111 0 : return rv;
112 : }
113 : }
114 :
115 0 : NS_ADDREF(this);
116 0 : *aOutputStream = static_cast<nsIOutputStream*>(this);
117 0 : mWriteInProgress = true;
118 0 : return NS_OK;
119 : }
120 :
121 : NS_IMETHODIMP
122 0 : nsStorageStream::Close()
123 : {
124 0 : if (NS_WARN_IF(!mSegmentedBuffer)) {
125 0 : return NS_ERROR_NOT_INITIALIZED;
126 : }
127 :
128 0 : mWriteInProgress = false;
129 :
130 0 : int32_t segmentOffset = SegOffset(mLogicalLength);
131 :
132 : // Shrink the final segment in the segmented buffer to the minimum size
133 : // needed to contain the data, so as to conserve memory.
134 0 : if (segmentOffset) {
135 0 : mSegmentedBuffer->ReallocLastSegment(segmentOffset);
136 : }
137 :
138 0 : mWriteCursor = 0;
139 0 : mSegmentEnd = 0;
140 :
141 0 : LOG(("nsStorageStream [%p] Close mWriteCursor=%p mSegmentEnd=%p\n",
142 : this, mWriteCursor, mSegmentEnd));
143 :
144 0 : return NS_OK;
145 : }
146 :
147 : NS_IMETHODIMP
148 0 : nsStorageStream::Flush()
149 : {
150 0 : return NS_OK;
151 : }
152 :
153 : NS_IMETHODIMP
154 0 : nsStorageStream::Write(const char* aBuffer, uint32_t aCount,
155 : uint32_t* aNumWritten)
156 : {
157 0 : if (NS_WARN_IF(!aNumWritten) || NS_WARN_IF(!aBuffer)) {
158 0 : return NS_ERROR_INVALID_ARG;
159 : }
160 0 : if (NS_WARN_IF(!mSegmentedBuffer)) {
161 0 : return NS_ERROR_NOT_INITIALIZED;
162 : }
163 :
164 : const char* readCursor;
165 : uint32_t count, availableInSegment, remaining;
166 0 : nsresult rv = NS_OK;
167 :
168 0 : LOG(("nsStorageStream [%p] Write mWriteCursor=%p mSegmentEnd=%p aCount=%d\n",
169 : this, mWriteCursor, mSegmentEnd, aCount));
170 :
171 0 : remaining = aCount;
172 0 : readCursor = aBuffer;
173 : // If no segments have been created yet, create one even if we don't have
174 : // to write any data; this enables creating an input stream which reads from
175 : // the very end of the data for any amount of data in the stream (i.e.
176 : // this stream contains N bytes of data and newInputStream(N) is called),
177 : // even for N=0 (with the caveat that we require .write("", 0) be called to
178 : // initialize internal buffers).
179 0 : bool firstTime = mSegmentedBuffer->GetSegmentCount() == 0;
180 0 : while (remaining || MOZ_UNLIKELY(firstTime)) {
181 0 : firstTime = false;
182 0 : availableInSegment = mSegmentEnd - mWriteCursor;
183 0 : if (!availableInSegment) {
184 0 : mWriteCursor = mSegmentedBuffer->AppendNewSegment();
185 0 : if (!mWriteCursor) {
186 0 : mSegmentEnd = 0;
187 0 : rv = NS_ERROR_OUT_OF_MEMORY;
188 0 : goto out;
189 : }
190 0 : mLastSegmentNum++;
191 0 : mSegmentEnd = mWriteCursor + mSegmentSize;
192 0 : availableInSegment = mSegmentEnd - mWriteCursor;
193 0 : LOG(("nsStorageStream [%p] Write (new seg) mWriteCursor=%p mSegmentEnd=%p\n",
194 : this, mWriteCursor, mSegmentEnd));
195 : }
196 :
197 0 : count = XPCOM_MIN(availableInSegment, remaining);
198 0 : memcpy(mWriteCursor, readCursor, count);
199 0 : remaining -= count;
200 0 : readCursor += count;
201 0 : mWriteCursor += count;
202 0 : LOG(("nsStorageStream [%p] Writing mWriteCursor=%p mSegmentEnd=%p count=%d\n",
203 : this, mWriteCursor, mSegmentEnd, count));
204 : }
205 :
206 : out:
207 0 : *aNumWritten = aCount - remaining;
208 0 : mLogicalLength += *aNumWritten;
209 :
210 0 : LOG(("nsStorageStream [%p] Wrote mWriteCursor=%p mSegmentEnd=%p numWritten=%d\n",
211 : this, mWriteCursor, mSegmentEnd, *aNumWritten));
212 0 : return rv;
213 : }
214 :
215 : NS_IMETHODIMP
216 0 : nsStorageStream::WriteFrom(nsIInputStream* aInStr, uint32_t aCount,
217 : uint32_t* aResult)
218 : {
219 0 : return NS_ERROR_NOT_IMPLEMENTED;
220 : }
221 :
222 : NS_IMETHODIMP
223 0 : nsStorageStream::WriteSegments(nsReadSegmentFun aReader, void* aClosure,
224 : uint32_t aCount, uint32_t* aResult)
225 : {
226 0 : return NS_ERROR_NOT_IMPLEMENTED;
227 : }
228 :
229 : NS_IMETHODIMP
230 0 : nsStorageStream::IsNonBlocking(bool* aNonBlocking)
231 : {
232 0 : *aNonBlocking = false;
233 0 : return NS_OK;
234 : }
235 :
236 : NS_IMETHODIMP
237 0 : nsStorageStream::GetLength(uint32_t* aLength)
238 : {
239 0 : *aLength = mLogicalLength;
240 0 : return NS_OK;
241 : }
242 :
243 : // Truncate the buffer by deleting the end segments
244 : NS_IMETHODIMP
245 0 : nsStorageStream::SetLength(uint32_t aLength)
246 : {
247 0 : if (NS_WARN_IF(!mSegmentedBuffer)) {
248 0 : return NS_ERROR_NOT_INITIALIZED;
249 : }
250 :
251 0 : if (mWriteInProgress) {
252 0 : return NS_ERROR_NOT_AVAILABLE;
253 : }
254 :
255 0 : if (aLength > mLogicalLength) {
256 0 : return NS_ERROR_INVALID_ARG;
257 : }
258 :
259 0 : int32_t newLastSegmentNum = SegNum(aLength);
260 0 : int32_t segmentOffset = SegOffset(aLength);
261 0 : if (segmentOffset == 0) {
262 0 : newLastSegmentNum--;
263 : }
264 :
265 0 : while (newLastSegmentNum < mLastSegmentNum) {
266 0 : mSegmentedBuffer->DeleteLastSegment();
267 0 : mLastSegmentNum--;
268 : }
269 :
270 0 : mLogicalLength = aLength;
271 0 : return NS_OK;
272 : }
273 :
274 : NS_IMETHODIMP
275 0 : nsStorageStream::GetWriteInProgress(bool* aWriteInProgress)
276 : {
277 0 : *aWriteInProgress = mWriteInProgress;
278 0 : return NS_OK;
279 : }
280 :
281 : nsresult
282 0 : nsStorageStream::Seek(int32_t aPosition)
283 : {
284 0 : if (NS_WARN_IF(!mSegmentedBuffer)) {
285 0 : return NS_ERROR_NOT_INITIALIZED;
286 : }
287 :
288 : // An argument of -1 means "seek to end of stream"
289 0 : if (aPosition == -1) {
290 0 : aPosition = mLogicalLength;
291 : }
292 :
293 : // Seeking beyond the buffer end is illegal
294 0 : if ((uint32_t)aPosition > mLogicalLength) {
295 0 : return NS_ERROR_INVALID_ARG;
296 : }
297 :
298 : // Seeking backwards in the write stream results in truncation
299 0 : SetLength(aPosition);
300 :
301 : // Special handling for seek to start-of-buffer
302 0 : if (aPosition == 0) {
303 0 : mWriteCursor = 0;
304 0 : mSegmentEnd = 0;
305 0 : LOG(("nsStorageStream [%p] Seek mWriteCursor=%p mSegmentEnd=%p\n",
306 : this, mWriteCursor, mSegmentEnd));
307 0 : return NS_OK;
308 : }
309 :
310 : // Segment may have changed, so reset pointers
311 0 : mWriteCursor = mSegmentedBuffer->GetSegment(mLastSegmentNum);
312 0 : NS_ASSERTION(mWriteCursor, "null mWriteCursor");
313 0 : mSegmentEnd = mWriteCursor + mSegmentSize;
314 :
315 : // Adjust write cursor for current segment offset. This test is necessary
316 : // because SegNum may reference the next-to-be-allocated segment, in which
317 : // case we need to be pointing at the end of the last segment.
318 0 : int32_t segmentOffset = SegOffset(aPosition);
319 0 : if (segmentOffset == 0 && (SegNum(aPosition) > (uint32_t) mLastSegmentNum)) {
320 0 : mWriteCursor = mSegmentEnd;
321 : } else {
322 0 : mWriteCursor += segmentOffset;
323 : }
324 :
325 0 : LOG(("nsStorageStream [%p] Seek mWriteCursor=%p mSegmentEnd=%p\n",
326 : this, mWriteCursor, mSegmentEnd));
327 0 : return NS_OK;
328 : }
329 :
330 : ////////////////////////////////////////////////////////////////////////////////
331 :
332 : // There can be many nsStorageInputStreams for a single nsStorageStream
333 : class nsStorageInputStream final
334 : : public nsIInputStream
335 : , public nsISeekableStream
336 : , public nsIIPCSerializableInputStream
337 : , public nsICloneableInputStream
338 : {
339 : public:
340 0 : nsStorageInputStream(nsStorageStream* aStorageStream, uint32_t aSegmentSize)
341 0 : : mStorageStream(aStorageStream), mReadCursor(0),
342 : mSegmentEnd(0), mSegmentNum(0),
343 : mSegmentSize(aSegmentSize), mLogicalCursor(0),
344 0 : mStatus(NS_OK)
345 : {
346 0 : }
347 :
348 : NS_DECL_THREADSAFE_ISUPPORTS
349 : NS_DECL_NSIINPUTSTREAM
350 : NS_DECL_NSISEEKABLESTREAM
351 : NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
352 : NS_DECL_NSICLONEABLEINPUTSTREAM
353 :
354 : private:
355 0 : ~nsStorageInputStream()
356 0 : {
357 0 : }
358 :
359 : protected:
360 : nsresult Seek(uint32_t aPosition);
361 :
362 : friend class nsStorageStream;
363 :
364 : private:
365 : RefPtr<nsStorageStream> mStorageStream;
366 : uint32_t mReadCursor; // Next memory location to read byte, or 0
367 : uint32_t mSegmentEnd; // One byte past end of current buffer segment
368 : uint32_t mSegmentNum; // Segment number containing read cursor
369 : uint32_t mSegmentSize; // All segments, except the last, are of this size
370 : uint32_t mLogicalCursor; // Logical offset into stream
371 : nsresult mStatus;
372 :
373 0 : uint32_t SegNum(uint32_t aPosition)
374 : {
375 0 : return aPosition >> mStorageStream->mSegmentSizeLog2;
376 : }
377 0 : uint32_t SegOffset(uint32_t aPosition)
378 : {
379 0 : return aPosition & (mSegmentSize - 1);
380 : }
381 : };
382 :
383 0 : NS_IMPL_ISUPPORTS(nsStorageInputStream,
384 : nsIInputStream,
385 : nsISeekableStream,
386 : nsIIPCSerializableInputStream,
387 : nsICloneableInputStream)
388 :
389 : NS_IMETHODIMP
390 0 : nsStorageStream::NewInputStream(int32_t aStartingOffset,
391 : nsIInputStream** aInputStream)
392 : {
393 0 : if (NS_WARN_IF(!mSegmentedBuffer)) {
394 0 : return NS_ERROR_NOT_INITIALIZED;
395 : }
396 :
397 : RefPtr<nsStorageInputStream> inputStream =
398 0 : new nsStorageInputStream(this, mSegmentSize);
399 :
400 0 : nsresult rv = inputStream->Seek(aStartingOffset);
401 0 : if (NS_FAILED(rv)) {
402 0 : return rv;
403 : }
404 :
405 0 : inputStream.forget(aInputStream);
406 0 : return NS_OK;
407 : }
408 :
409 : NS_IMETHODIMP
410 0 : nsStorageInputStream::Close()
411 : {
412 0 : mStatus = NS_BASE_STREAM_CLOSED;
413 0 : return NS_OK;
414 : }
415 :
416 : NS_IMETHODIMP
417 0 : nsStorageInputStream::Available(uint64_t* aAvailable)
418 : {
419 0 : if (NS_FAILED(mStatus)) {
420 0 : return mStatus;
421 : }
422 :
423 0 : *aAvailable = mStorageStream->mLogicalLength - mLogicalCursor;
424 0 : return NS_OK;
425 : }
426 :
427 : NS_IMETHODIMP
428 0 : nsStorageInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aNumRead)
429 : {
430 0 : return ReadSegments(NS_CopySegmentToBuffer, aBuffer, aCount, aNumRead);
431 : }
432 :
433 : NS_IMETHODIMP
434 0 : nsStorageInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
435 : uint32_t aCount, uint32_t* aNumRead)
436 : {
437 0 : *aNumRead = 0;
438 0 : if (mStatus == NS_BASE_STREAM_CLOSED) {
439 0 : return NS_OK;
440 : }
441 0 : if (NS_FAILED(mStatus)) {
442 0 : return mStatus;
443 : }
444 :
445 : uint32_t count, availableInSegment, remainingCapacity, bytesConsumed;
446 : nsresult rv;
447 :
448 0 : remainingCapacity = aCount;
449 0 : while (remainingCapacity) {
450 0 : availableInSegment = mSegmentEnd - mReadCursor;
451 0 : if (!availableInSegment) {
452 0 : uint32_t available = mStorageStream->mLogicalLength - mLogicalCursor;
453 0 : if (!available) {
454 0 : goto out;
455 : }
456 :
457 : // We have data in the stream, but if mSegmentEnd is zero, then we
458 : // were likely constructed prior to any data being written into
459 : // the stream. Therefore, if mSegmentEnd is non-zero, we should
460 : // move into the next segment; otherwise, we should stay in this
461 : // segment so our input state can be updated and we can properly
462 : // perform the initial read.
463 0 : if (mSegmentEnd > 0) {
464 0 : mSegmentNum++;
465 : }
466 0 : mReadCursor = 0;
467 0 : mSegmentEnd = XPCOM_MIN(mSegmentSize, available);
468 0 : availableInSegment = mSegmentEnd;
469 : }
470 0 : const char* cur = mStorageStream->mSegmentedBuffer->GetSegment(mSegmentNum);
471 :
472 0 : count = XPCOM_MIN(availableInSegment, remainingCapacity);
473 0 : rv = aWriter(this, aClosure, cur + mReadCursor, aCount - remainingCapacity,
474 0 : count, &bytesConsumed);
475 0 : if (NS_FAILED(rv) || (bytesConsumed == 0)) {
476 0 : break;
477 : }
478 0 : remainingCapacity -= bytesConsumed;
479 0 : mReadCursor += bytesConsumed;
480 0 : mLogicalCursor += bytesConsumed;
481 : }
482 :
483 : out:
484 0 : *aNumRead = aCount - remainingCapacity;
485 :
486 0 : bool isWriteInProgress = false;
487 0 : if (NS_FAILED(mStorageStream->GetWriteInProgress(&isWriteInProgress))) {
488 0 : isWriteInProgress = false;
489 : }
490 :
491 0 : if (*aNumRead == 0 && isWriteInProgress) {
492 0 : return NS_BASE_STREAM_WOULD_BLOCK;
493 : }
494 :
495 0 : return NS_OK;
496 : }
497 :
498 : NS_IMETHODIMP
499 0 : nsStorageInputStream::IsNonBlocking(bool* aNonBlocking)
500 : {
501 : // TODO: This class should implement nsIAsyncInputStream so that callers
502 : // have some way of dealing with NS_BASE_STREAM_WOULD_BLOCK errors.
503 :
504 0 : *aNonBlocking = true;
505 0 : return NS_OK;
506 : }
507 :
508 : NS_IMETHODIMP
509 0 : nsStorageInputStream::Seek(int32_t aWhence, int64_t aOffset)
510 : {
511 0 : if (NS_FAILED(mStatus)) {
512 0 : return mStatus;
513 : }
514 :
515 0 : int64_t pos = aOffset;
516 :
517 0 : switch (aWhence) {
518 : case NS_SEEK_SET:
519 0 : break;
520 : case NS_SEEK_CUR:
521 0 : pos += mLogicalCursor;
522 0 : break;
523 : case NS_SEEK_END:
524 0 : pos += mStorageStream->mLogicalLength;
525 0 : break;
526 : default:
527 0 : NS_NOTREACHED("unexpected whence value");
528 0 : return NS_ERROR_UNEXPECTED;
529 : }
530 0 : if (pos == int64_t(mLogicalCursor)) {
531 0 : return NS_OK;
532 : }
533 :
534 0 : return Seek(pos);
535 : }
536 :
537 : NS_IMETHODIMP
538 0 : nsStorageInputStream::Tell(int64_t* aResult)
539 : {
540 0 : if (NS_FAILED(mStatus)) {
541 0 : return mStatus;
542 : }
543 :
544 0 : *aResult = mLogicalCursor;
545 0 : return NS_OK;
546 : }
547 :
548 : NS_IMETHODIMP
549 0 : nsStorageInputStream::SetEOF()
550 : {
551 0 : NS_NOTREACHED("nsStorageInputStream::SetEOF");
552 0 : return NS_ERROR_NOT_IMPLEMENTED;
553 : }
554 :
555 : nsresult
556 0 : nsStorageInputStream::Seek(uint32_t aPosition)
557 : {
558 0 : uint32_t length = mStorageStream->mLogicalLength;
559 0 : if (aPosition > length) {
560 0 : return NS_ERROR_INVALID_ARG;
561 : }
562 :
563 0 : if (length == 0) {
564 0 : return NS_OK;
565 : }
566 :
567 0 : mSegmentNum = SegNum(aPosition);
568 0 : mReadCursor = SegOffset(aPosition);
569 0 : uint32_t available = length - aPosition;
570 0 : mSegmentEnd = mReadCursor + XPCOM_MIN(mSegmentSize - mReadCursor, available);
571 0 : mLogicalCursor = aPosition;
572 0 : return NS_OK;
573 : }
574 :
575 : void
576 0 : nsStorageInputStream::Serialize(InputStreamParams& aParams, FileDescriptorArray&)
577 : {
578 0 : nsCString combined;
579 : int64_t offset;
580 0 : mozilla::DebugOnly<nsresult> rv = Tell(&offset);
581 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
582 :
583 : uint64_t remaining;
584 0 : rv = Available(&remaining);
585 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
586 :
587 0 : combined.SetCapacity(remaining);
588 0 : uint32_t numRead = 0;
589 :
590 0 : rv = Read(combined.BeginWriting(), remaining, &numRead);
591 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
592 0 : MOZ_ASSERT(numRead == remaining);
593 0 : combined.SetLength(numRead);
594 :
595 0 : rv = Seek(NS_SEEK_SET, offset);
596 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
597 :
598 0 : StringInputStreamParams params;
599 0 : params.data() = combined;
600 0 : aParams = params;
601 0 : }
602 :
603 : Maybe<uint64_t>
604 0 : nsStorageInputStream::ExpectedSerializedLength()
605 : {
606 0 : uint64_t remaining = 0;
607 0 : DebugOnly<nsresult> rv = Available(&remaining);
608 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
609 0 : return Some(remaining);
610 : }
611 :
612 : bool
613 0 : nsStorageInputStream::Deserialize(const InputStreamParams& aParams,
614 : const FileDescriptorArray&)
615 : {
616 0 : NS_NOTREACHED("We should never attempt to deserialize a storage input stream.");
617 0 : return false;
618 : }
619 :
620 : NS_IMETHODIMP
621 0 : nsStorageInputStream::GetCloneable(bool* aCloneableOut)
622 : {
623 0 : *aCloneableOut = true;
624 0 : return NS_OK;
625 : }
626 :
627 : NS_IMETHODIMP
628 0 : nsStorageInputStream::Clone(nsIInputStream** aCloneOut)
629 : {
630 0 : return mStorageStream->NewInputStream(mLogicalCursor, aCloneOut);
631 : }
632 :
633 : nsresult
634 0 : NS_NewStorageStream(uint32_t aSegmentSize, uint32_t aMaxSize,
635 : nsIStorageStream** aResult)
636 : {
637 0 : RefPtr<nsStorageStream> storageStream = new nsStorageStream();
638 0 : nsresult rv = storageStream->Init(aSegmentSize, aMaxSize);
639 0 : if (NS_FAILED(rv)) {
640 0 : return rv;
641 : }
642 0 : storageStream.forget(aResult);
643 0 : return NS_OK;
644 : }
645 :
646 : // Undefine LOG, so that other .cpp files (or their includes) won't complain
647 : // about it already being defined, when we build in unified mode.
648 : #undef LOG
|