Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/io/nsStringStream.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
 * Based on original code from nsIStringStream.cpp
9
 */
10
11
#include "ipc/IPCMessageUtils.h"
12
13
#include "nsStringStream.h"
14
#include "nsStreamUtils.h"
15
#include "nsReadableUtils.h"
16
#include "nsICloneableInputStream.h"
17
#include "nsISeekableStream.h"
18
#include "nsISupportsPrimitives.h"
19
#include "nsCRT.h"
20
#include "prerror.h"
21
#include "plstr.h"
22
#include "nsIClassInfoImpl.h"
23
#include "mozilla/Attributes.h"
24
#include "mozilla/ipc/InputStreamUtils.h"
25
#include "nsIIPCSerializableInputStream.h"
26
27
using namespace mozilla::ipc;
28
using mozilla::Maybe;
29
using mozilla::Some;
30
31
//-----------------------------------------------------------------------------
32
// nsIStringInputStream implementation
33
//-----------------------------------------------------------------------------
34
35
class nsStringInputStream final
36
  : public nsIStringInputStream
37
  , public nsISeekableStream
38
  , public nsISupportsCString
39
  , public nsIIPCSerializableInputStream
40
  , public nsICloneableInputStream
41
{
42
public:
43
  NS_DECL_THREADSAFE_ISUPPORTS
44
  NS_DECL_NSIINPUTSTREAM
45
  NS_DECL_NSISTRINGINPUTSTREAM
46
  NS_DECL_NSISEEKABLESTREAM
47
  NS_DECL_NSISUPPORTSPRIMITIVE
48
  NS_DECL_NSISUPPORTSCSTRING
49
  NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
50
  NS_DECL_NSICLONEABLEINPUTSTREAM
51
52
  nsStringInputStream()
53
    : mOffset(0)
54
0
  {
55
0
    Clear();
56
0
  }
57
58
  nsresult Init(nsCString&& aString);
59
60
private:
61
  ~nsStringInputStream()
62
0
  {
63
0
  }
64
65
  uint32_t Length() const
66
0
  {
67
0
    return mData.Length();
68
0
  }
69
70
  uint32_t LengthRemaining() const
71
0
  {
72
0
    return Length() - mOffset;
73
0
  }
74
75
  void Clear()
76
0
  {
77
0
    mData.SetIsVoid(true);
78
0
  }
79
80
  bool Closed()
81
0
  {
82
0
    return mData.IsVoid();
83
0
  }
84
85
  nsDependentCSubstring mData;
86
  uint32_t mOffset;
87
};
88
89
nsresult
90
nsStringInputStream::Init(nsCString&& aString)
91
0
{
92
0
  if (!mData.Assign(std::move(aString), fallible)) {
93
0
    return NS_ERROR_OUT_OF_MEMORY;
94
0
  }
95
0
96
0
  mOffset = 0;
97
0
  return NS_OK;
98
0
}
99
100
// This class needs to support threadsafe refcounting since people often
101
// allocate a string stream, and then read it from a background thread.
102
NS_IMPL_ADDREF(nsStringInputStream)
103
NS_IMPL_RELEASE(nsStringInputStream)
104
105
NS_IMPL_CLASSINFO(nsStringInputStream, nullptr, nsIClassInfo::THREADSAFE,
106
                  NS_STRINGINPUTSTREAM_CID)
107
NS_IMPL_QUERY_INTERFACE_CI(nsStringInputStream,
108
                           nsIStringInputStream,
109
                           nsIInputStream,
110
                           nsISupportsCString,
111
                           nsISeekableStream,
112
                           nsIIPCSerializableInputStream,
113
                           nsICloneableInputStream)
114
NS_IMPL_CI_INTERFACE_GETTER(nsStringInputStream,
115
                            nsIStringInputStream,
116
                            nsIInputStream,
117
                            nsISupportsCString,
118
                            nsISeekableStream,
119
                            nsICloneableInputStream)
120
121
/////////
122
// nsISupportsCString implementation
123
/////////
124
125
NS_IMETHODIMP
126
nsStringInputStream::GetType(uint16_t* aType)
127
0
{
128
0
  *aType = TYPE_CSTRING;
129
0
  return NS_OK;
130
0
}
131
132
NS_IMETHODIMP
133
nsStringInputStream::GetData(nsACString& data)
134
0
{
135
0
  // The stream doesn't have any data when it is closed.  We could fake it
136
0
  // and return an empty string here, but it seems better to keep this return
137
0
  // value consistent with the behavior of the other 'getter' methods.
138
0
  if (NS_WARN_IF(Closed())) {
139
0
    return NS_BASE_STREAM_CLOSED;
140
0
  }
141
0
142
0
  data.Assign(mData);
143
0
  return NS_OK;
144
0
}
145
146
NS_IMETHODIMP
147
nsStringInputStream::SetData(const nsACString& aData)
148
0
{
149
0
  if (NS_WARN_IF(!mData.Assign(aData, fallible))) {
150
0
    return NS_ERROR_OUT_OF_MEMORY;
151
0
  }
152
0
153
0
  mOffset = 0;
154
0
  return NS_OK;
155
0
}
156
157
NS_IMETHODIMP
158
nsStringInputStream::ToString(char** aResult)
159
0
{
160
0
  // NOTE: This method may result in data loss, so we do not implement it.
161
0
  return NS_ERROR_NOT_IMPLEMENTED;
162
0
}
163
164
/////////
165
// nsIStringInputStream implementation
166
/////////
167
168
NS_IMETHODIMP
169
nsStringInputStream::SetData(const char* aData, int32_t aDataLen)
170
0
{
171
0
  if (NS_WARN_IF(!aData)) {
172
0
    return NS_ERROR_INVALID_ARG;
173
0
  }
174
0
175
0
  if (NS_WARN_IF(!mData.Assign(aData, aDataLen, fallible))) {
176
0
    return NS_ERROR_OUT_OF_MEMORY;
177
0
  }
178
0
179
0
  mOffset = 0;
180
0
  return NS_OK;
181
0
}
182
183
NS_IMETHODIMP
184
nsStringInputStream::AdoptData(char* aData, int32_t aDataLen)
185
0
{
186
0
  if (NS_WARN_IF(!aData)) {
187
0
    return NS_ERROR_INVALID_ARG;
188
0
  }
189
0
  mData.Adopt(aData, aDataLen);
190
0
  mOffset = 0;
191
0
  return NS_OK;
192
0
}
193
194
NS_IMETHODIMP
195
nsStringInputStream::ShareData(const char* aData, int32_t aDataLen)
196
0
{
197
0
  if (NS_WARN_IF(!aData)) {
198
0
    return NS_ERROR_INVALID_ARG;
199
0
  }
200
0
201
0
  if (aDataLen < 0) {
202
0
    aDataLen = strlen(aData);
203
0
  }
204
0
205
0
  mData.Rebind(aData, aDataLen);
206
0
  mOffset = 0;
207
0
  return NS_OK;
208
0
}
209
210
NS_IMETHODIMP_(size_t)
211
nsStringInputStream::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
212
0
{
213
0
  size_t n = aMallocSizeOf(this);
214
0
  n += mData.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
215
0
  return n;
216
0
}
217
218
/////////
219
// nsIInputStream implementation
220
/////////
221
222
NS_IMETHODIMP
223
nsStringInputStream::Close()
224
0
{
225
0
  Clear();
226
0
  return NS_OK;
227
0
}
228
229
NS_IMETHODIMP
230
nsStringInputStream::Available(uint64_t* aLength)
231
0
{
232
0
  NS_ASSERTION(aLength, "null ptr");
233
0
234
0
  if (Closed()) {
235
0
    return NS_BASE_STREAM_CLOSED;
236
0
  }
237
0
238
0
  *aLength = LengthRemaining();
239
0
  return NS_OK;
240
0
}
241
242
NS_IMETHODIMP
243
nsStringInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* aReadCount)
244
0
{
245
0
  NS_ASSERTION(aBuf, "null ptr");
246
0
  return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
247
0
}
248
249
NS_IMETHODIMP
250
nsStringInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
251
                                  uint32_t aCount, uint32_t* aResult)
252
0
{
253
0
  NS_ASSERTION(aResult, "null ptr");
254
0
  NS_ASSERTION(Length() >= mOffset, "bad stream state");
255
0
256
0
  if (Closed()) {
257
0
    return NS_BASE_STREAM_CLOSED;
258
0
  }
259
0
260
0
  // We may be at end-of-file
261
0
  uint32_t maxCount = LengthRemaining();
262
0
  if (maxCount == 0) {
263
0
    *aResult = 0;
264
0
    return NS_OK;
265
0
  }
266
0
267
0
  if (aCount > maxCount) {
268
0
    aCount = maxCount;
269
0
  }
270
0
  nsresult rv = aWriter(this, aClosure, mData.BeginReading() + mOffset, 0,
271
0
                        aCount, aResult);
272
0
  if (NS_SUCCEEDED(rv)) {
273
0
    NS_ASSERTION(*aResult <= aCount,
274
0
                 "writer should not write more than we asked it to write");
275
0
    mOffset += *aResult;
276
0
  }
277
0
278
0
  // errors returned from the writer end here!
279
0
  return NS_OK;
280
0
}
281
282
NS_IMETHODIMP
283
nsStringInputStream::IsNonBlocking(bool* aNonBlocking)
284
0
{
285
0
  *aNonBlocking = true;
286
0
  return NS_OK;
287
0
}
288
289
/////////
290
// nsISeekableStream implementation
291
/////////
292
293
NS_IMETHODIMP
294
nsStringInputStream::Seek(int32_t aWhence, int64_t aOffset)
295
0
{
296
0
  if (Closed()) {
297
0
    return NS_BASE_STREAM_CLOSED;
298
0
  }
299
0
300
0
  // Compute new stream position.  The given offset may be a negative value.
301
0
302
0
  int64_t newPos = aOffset;
303
0
  switch (aWhence) {
304
0
    case NS_SEEK_SET:
305
0
      break;
306
0
    case NS_SEEK_CUR:
307
0
      newPos += mOffset;
308
0
      break;
309
0
    case NS_SEEK_END:
310
0
      newPos += Length();
311
0
      break;
312
0
    default:
313
0
      NS_ERROR("invalid aWhence");
314
0
      return NS_ERROR_INVALID_ARG;
315
0
  }
316
0
317
0
  if (NS_WARN_IF(newPos < 0) || NS_WARN_IF(newPos > Length())) {
318
0
    return NS_ERROR_INVALID_ARG;
319
0
  }
320
0
321
0
  mOffset = (uint32_t)newPos;
322
0
  return NS_OK;
323
0
}
324
325
NS_IMETHODIMP
326
nsStringInputStream::Tell(int64_t* aOutWhere)
327
0
{
328
0
  if (Closed()) {
329
0
    return NS_BASE_STREAM_CLOSED;
330
0
  }
331
0
332
0
  *aOutWhere = mOffset;
333
0
  return NS_OK;
334
0
}
335
336
NS_IMETHODIMP
337
nsStringInputStream::SetEOF()
338
0
{
339
0
  if (Closed()) {
340
0
    return NS_BASE_STREAM_CLOSED;
341
0
  }
342
0
343
0
  mOffset = Length();
344
0
  return NS_OK;
345
0
}
346
347
/////////
348
// nsIIPCSerializableInputStream implementation
349
/////////
350
351
void
352
nsStringInputStream::Serialize(InputStreamParams& aParams,
353
                               FileDescriptorArray& /* aFDs */)
354
0
{
355
0
  StringInputStreamParams params;
356
0
  params.data() = PromiseFlatCString(mData);
357
0
  aParams = params;
358
0
}
359
360
bool
361
nsStringInputStream::Deserialize(const InputStreamParams& aParams,
362
                                 const FileDescriptorArray& /* aFDs */)
363
0
{
364
0
  if (aParams.type() != InputStreamParams::TStringInputStreamParams) {
365
0
    NS_ERROR("Received unknown parameters from the other process!");
366
0
    return false;
367
0
  }
368
0
369
0
  const StringInputStreamParams& params =
370
0
    aParams.get_StringInputStreamParams();
371
0
372
0
  if (NS_FAILED(SetData(params.data()))) {
373
0
    NS_WARNING("SetData failed!");
374
0
    return false;
375
0
  }
376
0
377
0
  return true;
378
0
}
379
380
Maybe<uint64_t>
381
nsStringInputStream::ExpectedSerializedLength()
382
0
{
383
0
  return Some(static_cast<uint64_t>(Length()));
384
0
}
385
386
/////////
387
// nsICloneableInputStream implementation
388
/////////
389
390
NS_IMETHODIMP
391
nsStringInputStream::GetCloneable(bool* aCloneableOut)
392
0
{
393
0
  *aCloneableOut = true;
394
0
  return NS_OK;
395
0
}
396
397
NS_IMETHODIMP
398
nsStringInputStream::Clone(nsIInputStream** aCloneOut)
399
0
{
400
0
  RefPtr<nsStringInputStream> ref = new nsStringInputStream();
401
0
  nsresult rv = ref->SetData(mData);
402
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
403
0
    return rv;
404
0
  }
405
0
406
0
  // mOffset is overwritten by SetData().
407
0
  ref->mOffset = mOffset;
408
0
409
0
  ref.forget(aCloneOut);
410
0
  return NS_OK;
411
0
}
412
413
nsresult
414
NS_NewByteInputStream(nsIInputStream** aStreamResult,
415
                      const char* aStringToRead, int32_t aLength,
416
                      nsAssignmentType aAssignment)
417
0
{
418
0
  MOZ_ASSERT(aStreamResult, "null out ptr");
419
0
420
0
  RefPtr<nsStringInputStream> stream = new nsStringInputStream();
421
0
422
0
  nsresult rv;
423
0
  switch (aAssignment) {
424
0
    case NS_ASSIGNMENT_COPY:
425
0
      rv = stream->SetData(aStringToRead, aLength);
426
0
      break;
427
0
    case NS_ASSIGNMENT_DEPEND:
428
0
      rv = stream->ShareData(aStringToRead, aLength);
429
0
      break;
430
0
    case NS_ASSIGNMENT_ADOPT:
431
0
      rv = stream->AdoptData(const_cast<char*>(aStringToRead), aLength);
432
0
      break;
433
0
    default:
434
0
      NS_ERROR("invalid assignment type");
435
0
      rv = NS_ERROR_INVALID_ARG;
436
0
  }
437
0
438
0
  if (NS_FAILED(rv)) {
439
0
    return rv;
440
0
  }
441
0
442
0
  stream.forget(aStreamResult);
443
0
  return NS_OK;
444
0
}
445
446
nsresult
447
NS_NewCStringInputStream(nsIInputStream** aStreamResult,
448
                         const nsACString& aStringToRead)
449
0
{
450
0
  MOZ_ASSERT(aStreamResult, "null out ptr");
451
0
452
0
  RefPtr<nsStringInputStream> stream = new nsStringInputStream();
453
0
454
0
  nsresult rv = stream->SetData(aStringToRead);
455
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
456
0
    return rv;
457
0
  }
458
0
459
0
  stream.forget(aStreamResult);
460
0
  return NS_OK;
461
0
}
462
463
nsresult
464
NS_NewCStringInputStream(nsIInputStream** aStreamResult,
465
                         nsCString&& aStringToRead)
466
0
{
467
0
  MOZ_ASSERT(aStreamResult, "null out ptr");
468
0
469
0
  RefPtr<nsStringInputStream> stream = new nsStringInputStream();
470
0
471
0
  nsresult rv = stream->Init(std::move(aStringToRead));
472
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
473
0
    return rv;
474
0
  }
475
0
476
0
  stream.forget(aStreamResult);
477
0
  return NS_OK;
478
0
}
479
480
// factory method for constructing a nsStringInputStream object
481
nsresult
482
nsStringInputStreamConstructor(nsISupports* aOuter, REFNSIID aIID,
483
                               void** aResult)
484
0
{
485
0
  *aResult = nullptr;
486
0
487
0
  if (NS_WARN_IF(aOuter)) {
488
0
    return NS_ERROR_NO_AGGREGATION;
489
0
  }
490
0
491
0
  RefPtr<nsStringInputStream> inst = new nsStringInputStream();
492
0
  return inst->QueryInterface(aIID, aResult);
493
0
}