xpcom/io/nsStringStream.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim:set ts=4 sts=4 sw=4 cin et: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /**
michael@0 8 * Based on original code from nsIStringStream.cpp
michael@0 9 */
michael@0 10
michael@0 11 #include "ipc/IPCMessageUtils.h"
michael@0 12
michael@0 13 #include "nsStringStream.h"
michael@0 14 #include "nsStreamUtils.h"
michael@0 15 #include "nsReadableUtils.h"
michael@0 16 #include "nsISeekableStream.h"
michael@0 17 #include "nsISupportsPrimitives.h"
michael@0 18 #include "nsCRT.h"
michael@0 19 #include "prerror.h"
michael@0 20 #include "plstr.h"
michael@0 21 #include "nsIClassInfoImpl.h"
michael@0 22 #include "mozilla/Attributes.h"
michael@0 23 #include "mozilla/ipc/InputStreamUtils.h"
michael@0 24 #include "nsIIPCSerializableInputStream.h"
michael@0 25
michael@0 26 using namespace mozilla::ipc;
michael@0 27
michael@0 28 //-----------------------------------------------------------------------------
michael@0 29 // nsIStringInputStream implementation
michael@0 30 //-----------------------------------------------------------------------------
michael@0 31
michael@0 32 class nsStringInputStream MOZ_FINAL : public nsIStringInputStream
michael@0 33 , public nsISeekableStream
michael@0 34 , public nsISupportsCString
michael@0 35 , public nsIIPCSerializableInputStream
michael@0 36 {
michael@0 37 public:
michael@0 38 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 39 NS_DECL_NSIINPUTSTREAM
michael@0 40 NS_DECL_NSISTRINGINPUTSTREAM
michael@0 41 NS_DECL_NSISEEKABLESTREAM
michael@0 42 NS_DECL_NSISUPPORTSPRIMITIVE
michael@0 43 NS_DECL_NSISUPPORTSCSTRING
michael@0 44 NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
michael@0 45
michael@0 46 nsStringInputStream()
michael@0 47 {
michael@0 48 Clear();
michael@0 49 }
michael@0 50
michael@0 51 private:
michael@0 52 ~nsStringInputStream()
michael@0 53 {}
michael@0 54
michael@0 55 uint32_t Length() const
michael@0 56 {
michael@0 57 return mData.Length();
michael@0 58 }
michael@0 59
michael@0 60 uint32_t LengthRemaining() const
michael@0 61 {
michael@0 62 return Length() - mOffset;
michael@0 63 }
michael@0 64
michael@0 65 void Clear()
michael@0 66 {
michael@0 67 mData.SetIsVoid(true);
michael@0 68 }
michael@0 69
michael@0 70 bool Closed()
michael@0 71 {
michael@0 72 return mData.IsVoid();
michael@0 73 }
michael@0 74
michael@0 75 nsDependentCSubstring mData;
michael@0 76 uint32_t mOffset;
michael@0 77 };
michael@0 78
michael@0 79 // This class needs to support threadsafe refcounting since people often
michael@0 80 // allocate a string stream, and then read it from a background thread.
michael@0 81 NS_IMPL_ADDREF(nsStringInputStream)
michael@0 82 NS_IMPL_RELEASE(nsStringInputStream)
michael@0 83
michael@0 84 NS_IMPL_CLASSINFO(nsStringInputStream, nullptr, nsIClassInfo::THREADSAFE,
michael@0 85 NS_STRINGINPUTSTREAM_CID)
michael@0 86 NS_IMPL_QUERY_INTERFACE_CI(nsStringInputStream,
michael@0 87 nsIStringInputStream,
michael@0 88 nsIInputStream,
michael@0 89 nsISupportsCString,
michael@0 90 nsISeekableStream,
michael@0 91 nsIIPCSerializableInputStream)
michael@0 92 NS_IMPL_CI_INTERFACE_GETTER(nsStringInputStream,
michael@0 93 nsIStringInputStream,
michael@0 94 nsIInputStream,
michael@0 95 nsISupportsCString,
michael@0 96 nsISeekableStream)
michael@0 97
michael@0 98 /////////
michael@0 99 // nsISupportsCString implementation
michael@0 100 /////////
michael@0 101
michael@0 102 NS_IMETHODIMP
michael@0 103 nsStringInputStream::GetType(uint16_t *type)
michael@0 104 {
michael@0 105 *type = TYPE_CSTRING;
michael@0 106 return NS_OK;
michael@0 107 }
michael@0 108
michael@0 109 NS_IMETHODIMP
michael@0 110 nsStringInputStream::GetData(nsACString &data)
michael@0 111 {
michael@0 112 // The stream doesn't have any data when it is closed. We could fake it
michael@0 113 // and return an empty string here, but it seems better to keep this return
michael@0 114 // value consistent with the behavior of the other 'getter' methods.
michael@0 115 if (NS_WARN_IF(Closed()))
michael@0 116 return NS_BASE_STREAM_CLOSED;
michael@0 117
michael@0 118 data.Assign(mData);
michael@0 119 return NS_OK;
michael@0 120 }
michael@0 121
michael@0 122 NS_IMETHODIMP
michael@0 123 nsStringInputStream::SetData(const nsACString &data)
michael@0 124 {
michael@0 125 mData.Assign(data);
michael@0 126 mOffset = 0;
michael@0 127 return NS_OK;
michael@0 128 }
michael@0 129
michael@0 130 NS_IMETHODIMP
michael@0 131 nsStringInputStream::ToString(char **result)
michael@0 132 {
michael@0 133 // NOTE: This method may result in data loss, so we do not implement it.
michael@0 134 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 135 }
michael@0 136
michael@0 137 /////////
michael@0 138 // nsIStringInputStream implementation
michael@0 139 /////////
michael@0 140
michael@0 141 NS_IMETHODIMP
michael@0 142 nsStringInputStream::SetData(const char *data, int32_t dataLen)
michael@0 143 {
michael@0 144 if (NS_WARN_IF(!data))
michael@0 145 return NS_ERROR_INVALID_ARG;
michael@0 146 mData.Assign(data, dataLen);
michael@0 147 mOffset = 0;
michael@0 148 return NS_OK;
michael@0 149 }
michael@0 150
michael@0 151 NS_IMETHODIMP
michael@0 152 nsStringInputStream::AdoptData(char *data, int32_t dataLen)
michael@0 153 {
michael@0 154 if (NS_WARN_IF(!data))
michael@0 155 return NS_ERROR_INVALID_ARG;
michael@0 156 mData.Adopt(data, dataLen);
michael@0 157 mOffset = 0;
michael@0 158 return NS_OK;
michael@0 159 }
michael@0 160
michael@0 161 NS_IMETHODIMP
michael@0 162 nsStringInputStream::ShareData(const char *data, int32_t dataLen)
michael@0 163 {
michael@0 164 if (NS_WARN_IF(!data))
michael@0 165 return NS_ERROR_INVALID_ARG;
michael@0 166
michael@0 167 if (dataLen < 0)
michael@0 168 dataLen = strlen(data);
michael@0 169
michael@0 170 mData.Rebind(data, dataLen);
michael@0 171 mOffset = 0;
michael@0 172 return NS_OK;
michael@0 173 }
michael@0 174
michael@0 175 /////////
michael@0 176 // nsIInputStream implementation
michael@0 177 /////////
michael@0 178
michael@0 179 NS_IMETHODIMP
michael@0 180 nsStringInputStream::Close()
michael@0 181 {
michael@0 182 Clear();
michael@0 183 return NS_OK;
michael@0 184 }
michael@0 185
michael@0 186 NS_IMETHODIMP
michael@0 187 nsStringInputStream::Available(uint64_t *aLength)
michael@0 188 {
michael@0 189 NS_ASSERTION(aLength, "null ptr");
michael@0 190
michael@0 191 if (Closed())
michael@0 192 return NS_BASE_STREAM_CLOSED;
michael@0 193
michael@0 194 *aLength = LengthRemaining();
michael@0 195 return NS_OK;
michael@0 196 }
michael@0 197
michael@0 198 NS_IMETHODIMP
michael@0 199 nsStringInputStream::Read(char* aBuf, uint32_t aCount, uint32_t *aReadCount)
michael@0 200 {
michael@0 201 NS_ASSERTION(aBuf, "null ptr");
michael@0 202 return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
michael@0 203 }
michael@0 204
michael@0 205 NS_IMETHODIMP
michael@0 206 nsStringInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
michael@0 207 uint32_t aCount, uint32_t *result)
michael@0 208 {
michael@0 209 NS_ASSERTION(result, "null ptr");
michael@0 210 NS_ASSERTION(Length() >= mOffset, "bad stream state");
michael@0 211
michael@0 212 if (Closed())
michael@0 213 return NS_BASE_STREAM_CLOSED;
michael@0 214
michael@0 215 // We may be at end-of-file
michael@0 216 uint32_t maxCount = LengthRemaining();
michael@0 217 if (maxCount == 0) {
michael@0 218 *result = 0;
michael@0 219 return NS_OK;
michael@0 220 }
michael@0 221
michael@0 222 if (aCount > maxCount)
michael@0 223 aCount = maxCount;
michael@0 224 nsresult rv = writer(this, closure, mData.BeginReading() + mOffset, 0, aCount, result);
michael@0 225 if (NS_SUCCEEDED(rv)) {
michael@0 226 NS_ASSERTION(*result <= aCount,
michael@0 227 "writer should not write more than we asked it to write");
michael@0 228 mOffset += *result;
michael@0 229 }
michael@0 230
michael@0 231 // errors returned from the writer end here!
michael@0 232 return NS_OK;
michael@0 233 }
michael@0 234
michael@0 235 NS_IMETHODIMP
michael@0 236 nsStringInputStream::IsNonBlocking(bool *aNonBlocking)
michael@0 237 {
michael@0 238 *aNonBlocking = true;
michael@0 239 return NS_OK;
michael@0 240 }
michael@0 241
michael@0 242 /////////
michael@0 243 // nsISeekableStream implementation
michael@0 244 /////////
michael@0 245
michael@0 246 NS_IMETHODIMP
michael@0 247 nsStringInputStream::Seek(int32_t whence, int64_t offset)
michael@0 248 {
michael@0 249 if (Closed())
michael@0 250 return NS_BASE_STREAM_CLOSED;
michael@0 251
michael@0 252 // Compute new stream position. The given offset may be a negative value.
michael@0 253
michael@0 254 int64_t newPos = offset;
michael@0 255 switch (whence) {
michael@0 256 case NS_SEEK_SET:
michael@0 257 break;
michael@0 258 case NS_SEEK_CUR:
michael@0 259 newPos += mOffset;
michael@0 260 break;
michael@0 261 case NS_SEEK_END:
michael@0 262 newPos += Length();
michael@0 263 break;
michael@0 264 default:
michael@0 265 NS_ERROR("invalid whence");
michael@0 266 return NS_ERROR_INVALID_ARG;
michael@0 267 }
michael@0 268
michael@0 269 if (NS_WARN_IF(newPos < 0) || NS_WARN_IF(newPos > Length()))
michael@0 270 return NS_ERROR_INVALID_ARG;
michael@0 271
michael@0 272 mOffset = (uint32_t)newPos;
michael@0 273 return NS_OK;
michael@0 274 }
michael@0 275
michael@0 276 NS_IMETHODIMP
michael@0 277 nsStringInputStream::Tell(int64_t* outWhere)
michael@0 278 {
michael@0 279 if (Closed())
michael@0 280 return NS_BASE_STREAM_CLOSED;
michael@0 281
michael@0 282 *outWhere = mOffset;
michael@0 283 return NS_OK;
michael@0 284 }
michael@0 285
michael@0 286 NS_IMETHODIMP
michael@0 287 nsStringInputStream::SetEOF()
michael@0 288 {
michael@0 289 if (Closed())
michael@0 290 return NS_BASE_STREAM_CLOSED;
michael@0 291
michael@0 292 mOffset = Length();
michael@0 293 return NS_OK;
michael@0 294 }
michael@0 295
michael@0 296 void
michael@0 297 nsStringInputStream::Serialize(InputStreamParams& aParams,
michael@0 298 FileDescriptorArray& /* aFDs */)
michael@0 299 {
michael@0 300 StringInputStreamParams params;
michael@0 301 params.data() = PromiseFlatCString(mData);
michael@0 302 aParams = params;
michael@0 303 }
michael@0 304
michael@0 305 bool
michael@0 306 nsStringInputStream::Deserialize(const InputStreamParams& aParams,
michael@0 307 const FileDescriptorArray& /* aFDs */)
michael@0 308 {
michael@0 309 if (aParams.type() != InputStreamParams::TStringInputStreamParams) {
michael@0 310 NS_ERROR("Received unknown parameters from the other process!");
michael@0 311 return false;
michael@0 312 }
michael@0 313
michael@0 314 const StringInputStreamParams& params =
michael@0 315 aParams.get_StringInputStreamParams();
michael@0 316
michael@0 317 if (NS_FAILED(SetData(params.data()))) {
michael@0 318 NS_WARNING("SetData failed!");
michael@0 319 return false;
michael@0 320 }
michael@0 321
michael@0 322 return true;
michael@0 323 }
michael@0 324
michael@0 325 nsresult
michael@0 326 NS_NewByteInputStream(nsIInputStream** aStreamResult,
michael@0 327 const char* aStringToRead, int32_t aLength,
michael@0 328 nsAssignmentType aAssignment)
michael@0 329 {
michael@0 330 NS_PRECONDITION(aStreamResult, "null out ptr");
michael@0 331
michael@0 332 nsStringInputStream* stream = new nsStringInputStream();
michael@0 333 if (! stream)
michael@0 334 return NS_ERROR_OUT_OF_MEMORY;
michael@0 335
michael@0 336 NS_ADDREF(stream);
michael@0 337
michael@0 338 nsresult rv;
michael@0 339 switch (aAssignment) {
michael@0 340 case NS_ASSIGNMENT_COPY:
michael@0 341 rv = stream->SetData(aStringToRead, aLength);
michael@0 342 break;
michael@0 343 case NS_ASSIGNMENT_DEPEND:
michael@0 344 rv = stream->ShareData(aStringToRead, aLength);
michael@0 345 break;
michael@0 346 case NS_ASSIGNMENT_ADOPT:
michael@0 347 rv = stream->AdoptData(const_cast<char*>(aStringToRead), aLength);
michael@0 348 break;
michael@0 349 default:
michael@0 350 NS_ERROR("invalid assignment type");
michael@0 351 rv = NS_ERROR_INVALID_ARG;
michael@0 352 }
michael@0 353
michael@0 354 if (NS_FAILED(rv)) {
michael@0 355 NS_RELEASE(stream);
michael@0 356 return rv;
michael@0 357 }
michael@0 358
michael@0 359 *aStreamResult = stream;
michael@0 360 return NS_OK;
michael@0 361 }
michael@0 362
michael@0 363 nsresult
michael@0 364 NS_NewStringInputStream(nsIInputStream** aStreamResult,
michael@0 365 const nsAString& aStringToRead)
michael@0 366 {
michael@0 367 NS_LossyConvertUTF16toASCII data(aStringToRead); // truncates high-order bytes
michael@0 368 return NS_NewCStringInputStream(aStreamResult, data);
michael@0 369 }
michael@0 370
michael@0 371 nsresult
michael@0 372 NS_NewCStringInputStream(nsIInputStream** aStreamResult,
michael@0 373 const nsACString& aStringToRead)
michael@0 374 {
michael@0 375 NS_PRECONDITION(aStreamResult, "null out ptr");
michael@0 376
michael@0 377 nsStringInputStream* stream = new nsStringInputStream();
michael@0 378 if (! stream)
michael@0 379 return NS_ERROR_OUT_OF_MEMORY;
michael@0 380
michael@0 381 NS_ADDREF(stream);
michael@0 382
michael@0 383 stream->SetData(aStringToRead);
michael@0 384
michael@0 385 *aStreamResult = stream;
michael@0 386 return NS_OK;
michael@0 387 }
michael@0 388
michael@0 389 // factory method for constructing a nsStringInputStream object
michael@0 390 nsresult
michael@0 391 nsStringInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result)
michael@0 392 {
michael@0 393 *result = nullptr;
michael@0 394
michael@0 395 if (NS_WARN_IF(outer))
michael@0 396 return NS_ERROR_NO_AGGREGATION;
michael@0 397
michael@0 398 nsStringInputStream *inst = new nsStringInputStream();
michael@0 399 if (!inst)
michael@0 400 return NS_ERROR_OUT_OF_MEMORY;
michael@0 401
michael@0 402 NS_ADDREF(inst);
michael@0 403 nsresult rv = inst->QueryInterface(iid, result);
michael@0 404 NS_RELEASE(inst);
michael@0 405
michael@0 406 return rv;
michael@0 407 }

mercurial