Coverage Report

Created: 2018-09-25 14:53

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