Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /**
7 * This file contains implementations of the nsIBinaryInputStream and
8 * nsIBinaryOutputStream interfaces. Together, these interfaces allows reading
9 * and writing of primitive data types (integers, floating-point values,
10 * booleans, etc.) to a stream in a binary, untagged, fixed-endianness format.
11 * This might be used, for example, to implement network protocols or to
12 * produce architecture-neutral binary disk files, i.e. ones that can be read
13 * and written by both big-endian and little-endian platforms. Output is
14 * written in big-endian order (high-order byte first), as this is traditional
15 * network order.
16 *
17 * @See nsIBinaryInputStream
18 * @See nsIBinaryOutputStream
19 */
20 #include <algorithm>
21 #include <string.h>
23 #include "nsBinaryStream.h"
25 #include "mozilla/Endian.h"
26 #include "mozilla/PodOperations.h"
27 #include "mozilla/Scoped.h"
29 #include "nsCRT.h"
30 #include "nsString.h"
31 #include "nsISerializable.h"
32 #include "nsIClassInfo.h"
33 #include "nsComponentManagerUtils.h"
34 #include "nsIURI.h" // for NS_IURI_IID
36 #include "jsfriendapi.h"
38 using mozilla::PodCopy;
39 using mozilla::ScopedDeleteArray;
41 NS_IMPL_ISUPPORTS(nsBinaryOutputStream, nsIObjectOutputStream, nsIBinaryOutputStream, nsIOutputStream)
43 NS_IMETHODIMP
44 nsBinaryOutputStream::Flush()
45 {
46 if (NS_WARN_IF(!mOutputStream))
47 return NS_ERROR_UNEXPECTED;
48 return mOutputStream->Flush();
49 }
51 NS_IMETHODIMP
52 nsBinaryOutputStream::Close()
53 {
54 if (NS_WARN_IF(!mOutputStream))
55 return NS_ERROR_UNEXPECTED;
56 return mOutputStream->Close();
57 }
59 NS_IMETHODIMP
60 nsBinaryOutputStream::Write(const char *aBuf, uint32_t aCount, uint32_t *aActualBytes)
61 {
62 if (NS_WARN_IF(!mOutputStream))
63 return NS_ERROR_UNEXPECTED;
64 return mOutputStream->Write(aBuf, aCount, aActualBytes);
65 }
67 NS_IMETHODIMP
68 nsBinaryOutputStream::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval)
69 {
70 NS_NOTREACHED("WriteFrom");
71 return NS_ERROR_NOT_IMPLEMENTED;
72 }
74 NS_IMETHODIMP
75 nsBinaryOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval)
76 {
77 NS_NOTREACHED("WriteSegments");
78 return NS_ERROR_NOT_IMPLEMENTED;
79 }
81 NS_IMETHODIMP
82 nsBinaryOutputStream::IsNonBlocking(bool *aNonBlocking)
83 {
84 if (NS_WARN_IF(!mOutputStream))
85 return NS_ERROR_UNEXPECTED;
86 return mOutputStream->IsNonBlocking(aNonBlocking);
87 }
89 nsresult
90 nsBinaryOutputStream::WriteFully(const char *aBuf, uint32_t aCount)
91 {
92 if (NS_WARN_IF(!mOutputStream))
93 return NS_ERROR_UNEXPECTED;
95 nsresult rv;
96 uint32_t bytesWritten;
98 rv = mOutputStream->Write(aBuf, aCount, &bytesWritten);
99 if (NS_FAILED(rv)) return rv;
100 if (bytesWritten != aCount)
101 return NS_ERROR_FAILURE;
102 return NS_OK;
103 }
105 NS_IMETHODIMP
106 nsBinaryOutputStream::SetOutputStream(nsIOutputStream *aOutputStream)
107 {
108 if (NS_WARN_IF(!aOutputStream))
109 return NS_ERROR_INVALID_ARG;
110 mOutputStream = aOutputStream;
111 mBufferAccess = do_QueryInterface(aOutputStream);
112 return NS_OK;
113 }
115 NS_IMETHODIMP
116 nsBinaryOutputStream::WriteBoolean(bool aBoolean)
117 {
118 return Write8(aBoolean);
119 }
121 NS_IMETHODIMP
122 nsBinaryOutputStream::Write8(uint8_t aByte)
123 {
124 return WriteFully((const char*)&aByte, sizeof aByte);
125 }
127 NS_IMETHODIMP
128 nsBinaryOutputStream::Write16(uint16_t a16)
129 {
130 a16 = mozilla::NativeEndian::swapToBigEndian(a16);
131 return WriteFully((const char*)&a16, sizeof a16);
132 }
134 NS_IMETHODIMP
135 nsBinaryOutputStream::Write32(uint32_t a32)
136 {
137 a32 = mozilla::NativeEndian::swapToBigEndian(a32);
138 return WriteFully((const char*)&a32, sizeof a32);
139 }
141 NS_IMETHODIMP
142 nsBinaryOutputStream::Write64(uint64_t a64)
143 {
144 nsresult rv;
145 uint32_t bytesWritten;
147 a64 = mozilla::NativeEndian::swapToBigEndian(a64);
148 rv = Write(reinterpret_cast<char*>(&a64), sizeof a64, &bytesWritten);
149 if (NS_FAILED(rv)) return rv;
150 if (bytesWritten != sizeof a64)
151 return NS_ERROR_FAILURE;
152 return rv;
153 }
155 NS_IMETHODIMP
156 nsBinaryOutputStream::WriteFloat(float aFloat)
157 {
158 NS_ASSERTION(sizeof(float) == sizeof (uint32_t),
159 "False assumption about sizeof(float)");
160 return Write32(*reinterpret_cast<uint32_t*>(&aFloat));
161 }
163 NS_IMETHODIMP
164 nsBinaryOutputStream::WriteDouble(double aDouble)
165 {
166 NS_ASSERTION(sizeof(double) == sizeof(uint64_t),
167 "False assumption about sizeof(double)");
168 return Write64(*reinterpret_cast<uint64_t*>(&aDouble));
169 }
171 NS_IMETHODIMP
172 nsBinaryOutputStream::WriteStringZ(const char *aString)
173 {
174 uint32_t length;
175 nsresult rv;
177 length = strlen(aString);
178 rv = Write32(length);
179 if (NS_FAILED(rv)) return rv;
180 return WriteFully(aString, length);
181 }
183 NS_IMETHODIMP
184 nsBinaryOutputStream::WriteWStringZ(const char16_t* aString)
185 {
186 uint32_t length, byteCount;
187 nsresult rv;
189 length = NS_strlen(aString);
190 rv = Write32(length);
191 if (NS_FAILED(rv)) return rv;
193 if (length == 0)
194 return NS_OK;
195 byteCount = length * sizeof(char16_t);
197 #ifdef IS_BIG_ENDIAN
198 rv = WriteBytes(reinterpret_cast<const char*>(aString), byteCount);
199 #else
200 // XXX use WriteSegments here to avoid copy!
201 char16_t *copy, temp[64];
202 if (length <= 64) {
203 copy = temp;
204 } else {
205 copy = reinterpret_cast<char16_t*>(moz_malloc(byteCount));
206 if (!copy)
207 return NS_ERROR_OUT_OF_MEMORY;
208 }
209 NS_ASSERTION((uintptr_t(aString) & 0x1) == 0, "aString not properly aligned");
210 mozilla::NativeEndian::copyAndSwapToBigEndian(copy, aString, length);
211 rv = WriteBytes(reinterpret_cast<const char*>(copy), byteCount);
212 if (copy != temp)
213 moz_free(copy);
214 #endif
216 return rv;
217 }
219 NS_IMETHODIMP
220 nsBinaryOutputStream::WriteUtf8Z(const char16_t* aString)
221 {
222 return WriteStringZ(NS_ConvertUTF16toUTF8(aString).get());
223 }
225 NS_IMETHODIMP
226 nsBinaryOutputStream::WriteBytes(const char *aString, uint32_t aLength)
227 {
228 nsresult rv;
229 uint32_t bytesWritten;
231 rv = Write(aString, aLength, &bytesWritten);
232 if (NS_FAILED(rv)) return rv;
233 if (bytesWritten != aLength)
234 return NS_ERROR_FAILURE;
235 return rv;
236 }
238 NS_IMETHODIMP
239 nsBinaryOutputStream::WriteByteArray(uint8_t *aBytes, uint32_t aLength)
240 {
241 return WriteBytes(reinterpret_cast<char *>(aBytes), aLength);
242 }
244 NS_IMETHODIMP
245 nsBinaryOutputStream::WriteObject(nsISupports* aObject, bool aIsStrongRef)
246 {
247 return WriteCompoundObject(aObject, NS_GET_IID(nsISupports),
248 aIsStrongRef);
249 }
251 NS_IMETHODIMP
252 nsBinaryOutputStream::WriteSingleRefObject(nsISupports* aObject)
253 {
254 return WriteCompoundObject(aObject, NS_GET_IID(nsISupports),
255 true);
256 }
258 NS_IMETHODIMP
259 nsBinaryOutputStream::WriteCompoundObject(nsISupports* aObject,
260 const nsIID& aIID,
261 bool aIsStrongRef)
262 {
263 nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aObject);
264 nsCOMPtr<nsISerializable> serializable = do_QueryInterface(aObject);
266 // Can't deal with weak refs
267 if (NS_WARN_IF(!aIsStrongRef))
268 return NS_ERROR_UNEXPECTED;
269 if (NS_WARN_IF(!classInfo) || NS_WARN_IF(!serializable))
270 return NS_ERROR_NOT_AVAILABLE;
272 nsCID cid;
273 nsresult rv = classInfo->GetClassIDNoAlloc(&cid);
274 if (NS_SUCCEEDED(rv)) {
275 rv = WriteID(cid);
276 } else {
277 nsCID *cidptr = nullptr;
278 rv = classInfo->GetClassID(&cidptr);
279 if (NS_WARN_IF(NS_FAILED(rv))) {
280 return rv;
281 }
283 rv = WriteID(*cidptr);
285 NS_Free(cidptr);
286 }
288 if (NS_WARN_IF(NS_FAILED(rv)))
289 return rv;
291 rv = WriteID(aIID);
292 if (NS_WARN_IF(NS_FAILED(rv)))
293 return rv;
295 return serializable->Write(this);
296 }
298 NS_IMETHODIMP
299 nsBinaryOutputStream::WriteID(const nsIID& aIID)
300 {
301 nsresult rv = Write32(aIID.m0);
302 if (NS_WARN_IF(NS_FAILED(rv)))
303 return rv;
305 rv = Write16(aIID.m1);
306 if (NS_WARN_IF(NS_FAILED(rv)))
307 return rv;
309 rv = Write16(aIID.m2);
310 if (NS_WARN_IF(NS_FAILED(rv)))
311 return rv;
313 for (int i = 0; i < 8; ++i) {
314 rv = Write8(aIID.m3[i]);
315 if (NS_WARN_IF(NS_FAILED(rv)))
316 return rv;
317 }
319 return NS_OK;
320 }
322 NS_IMETHODIMP_(char*)
323 nsBinaryOutputStream::GetBuffer(uint32_t aLength, uint32_t aAlignMask)
324 {
325 if (mBufferAccess)
326 return mBufferAccess->GetBuffer(aLength, aAlignMask);
327 return nullptr;
328 }
330 NS_IMETHODIMP_(void)
331 nsBinaryOutputStream::PutBuffer(char* aBuffer, uint32_t aLength)
332 {
333 if (mBufferAccess)
334 mBufferAccess->PutBuffer(aBuffer, aLength);
335 }
337 NS_IMPL_ISUPPORTS(nsBinaryInputStream, nsIObjectInputStream, nsIBinaryInputStream, nsIInputStream)
339 NS_IMETHODIMP
340 nsBinaryInputStream::Available(uint64_t* aResult)
341 {
342 if (NS_WARN_IF(!mInputStream))
343 return NS_ERROR_UNEXPECTED;
344 return mInputStream->Available(aResult);
345 }
347 NS_IMETHODIMP
348 nsBinaryInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t *aNumRead)
349 {
350 if (NS_WARN_IF(!mInputStream))
351 return NS_ERROR_UNEXPECTED;
353 // mInputStream might give us short reads, so deal with that.
354 uint32_t totalRead = 0;
356 uint32_t bytesRead;
357 do {
358 nsresult rv = mInputStream->Read(aBuffer, aCount, &bytesRead);
359 if (rv == NS_BASE_STREAM_WOULD_BLOCK && totalRead != 0) {
360 // We already read some data. Return it.
361 break;
362 }
364 if (NS_FAILED(rv)) {
365 return rv;
366 }
368 totalRead += bytesRead;
369 aBuffer += bytesRead;
370 aCount -= bytesRead;
371 } while (aCount != 0 && bytesRead != 0);
373 *aNumRead = totalRead;
375 return NS_OK;
376 }
379 // when forwarding ReadSegments to mInputStream, we need to make sure
380 // 'this' is being passed to the writer each time. To do this, we need
381 // a thunking function which keeps the real input stream around.
383 // the closure wrapper
384 struct ReadSegmentsClosure {
385 nsIInputStream* mRealInputStream;
386 void* mRealClosure;
387 nsWriteSegmentFun mRealWriter;
388 nsresult mRealResult;
389 uint32_t mBytesRead; // to properly implement aToOffset
390 };
392 // the thunking function
393 static NS_METHOD
394 ReadSegmentForwardingThunk(nsIInputStream* aStream,
395 void *aClosure,
396 const char* aFromSegment,
397 uint32_t aToOffset,
398 uint32_t aCount,
399 uint32_t *aWriteCount)
400 {
401 ReadSegmentsClosure* thunkClosure =
402 reinterpret_cast<ReadSegmentsClosure*>(aClosure);
404 NS_ASSERTION(NS_SUCCEEDED(thunkClosure->mRealResult),
405 "How did this get to be a failure status?");
407 thunkClosure->mRealResult =
408 thunkClosure->mRealWriter(thunkClosure->mRealInputStream,
409 thunkClosure->mRealClosure,
410 aFromSegment,
411 thunkClosure->mBytesRead + aToOffset,
412 aCount, aWriteCount);
414 return thunkClosure->mRealResult;
415 }
418 NS_IMETHODIMP
419 nsBinaryInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, uint32_t count, uint32_t *_retval)
420 {
421 if (NS_WARN_IF(!mInputStream))
422 return NS_ERROR_UNEXPECTED;
424 ReadSegmentsClosure thunkClosure = { this, closure, writer, NS_OK, 0 };
426 // mInputStream might give us short reads, so deal with that.
427 uint32_t bytesRead;
428 do {
429 nsresult rv = mInputStream->ReadSegments(ReadSegmentForwardingThunk,
430 &thunkClosure,
431 count, &bytesRead);
433 if (rv == NS_BASE_STREAM_WOULD_BLOCK && thunkClosure.mBytesRead != 0) {
434 // We already read some data. Return it.
435 break;
436 }
438 if (NS_FAILED(rv)) {
439 return rv;
440 }
442 thunkClosure.mBytesRead += bytesRead;
443 count -= bytesRead;
444 } while (count != 0 && bytesRead != 0 &&
445 NS_SUCCEEDED(thunkClosure.mRealResult));
447 *_retval = thunkClosure.mBytesRead;
449 return NS_OK;
450 }
452 NS_IMETHODIMP
453 nsBinaryInputStream::IsNonBlocking(bool *aNonBlocking)
454 {
455 if (NS_WARN_IF(!mInputStream))
456 return NS_ERROR_UNEXPECTED;
457 return mInputStream->IsNonBlocking(aNonBlocking);
458 }
460 NS_IMETHODIMP
461 nsBinaryInputStream::Close()
462 {
463 if (NS_WARN_IF(!mInputStream))
464 return NS_ERROR_UNEXPECTED;
465 return mInputStream->Close();
466 }
468 NS_IMETHODIMP
469 nsBinaryInputStream::SetInputStream(nsIInputStream *aInputStream)
470 {
471 if (NS_WARN_IF(!aInputStream))
472 return NS_ERROR_INVALID_ARG;
473 mInputStream = aInputStream;
474 mBufferAccess = do_QueryInterface(aInputStream);
475 return NS_OK;
476 }
478 NS_IMETHODIMP
479 nsBinaryInputStream::ReadBoolean(bool* aBoolean)
480 {
481 uint8_t byteResult;
482 nsresult rv = Read8(&byteResult);
483 if (NS_FAILED(rv)) return rv;
484 *aBoolean = !!byteResult;
485 return rv;
486 }
488 NS_IMETHODIMP
489 nsBinaryInputStream::Read8(uint8_t* aByte)
490 {
491 nsresult rv;
492 uint32_t bytesRead;
494 rv = Read(reinterpret_cast<char*>(aByte), sizeof(*aByte), &bytesRead);
495 if (NS_FAILED(rv)) return rv;
496 if (bytesRead != 1)
497 return NS_ERROR_FAILURE;
498 return rv;
499 }
501 NS_IMETHODIMP
502 nsBinaryInputStream::Read16(uint16_t* a16)
503 {
504 nsresult rv;
505 uint32_t bytesRead;
507 rv = Read(reinterpret_cast<char*>(a16), sizeof *a16, &bytesRead);
508 if (NS_FAILED(rv)) return rv;
509 if (bytesRead != sizeof *a16)
510 return NS_ERROR_FAILURE;
511 *a16 = mozilla::NativeEndian::swapFromBigEndian(*a16);
512 return rv;
513 }
515 NS_IMETHODIMP
516 nsBinaryInputStream::Read32(uint32_t* a32)
517 {
518 nsresult rv;
519 uint32_t bytesRead;
521 rv = Read(reinterpret_cast<char*>(a32), sizeof *a32, &bytesRead);
522 if (NS_FAILED(rv)) return rv;
523 if (bytesRead != sizeof *a32)
524 return NS_ERROR_FAILURE;
525 *a32 = mozilla::NativeEndian::swapFromBigEndian(*a32);
526 return rv;
527 }
529 NS_IMETHODIMP
530 nsBinaryInputStream::Read64(uint64_t* a64)
531 {
532 nsresult rv;
533 uint32_t bytesRead;
535 rv = Read(reinterpret_cast<char*>(a64), sizeof *a64, &bytesRead);
536 if (NS_FAILED(rv)) return rv;
537 if (bytesRead != sizeof *a64)
538 return NS_ERROR_FAILURE;
539 *a64 = mozilla::NativeEndian::swapFromBigEndian(*a64);
540 return rv;
541 }
543 NS_IMETHODIMP
544 nsBinaryInputStream::ReadFloat(float* aFloat)
545 {
546 NS_ASSERTION(sizeof(float) == sizeof (uint32_t),
547 "False assumption about sizeof(float)");
548 return Read32(reinterpret_cast<uint32_t*>(aFloat));
549 }
551 NS_IMETHODIMP
552 nsBinaryInputStream::ReadDouble(double* aDouble)
553 {
554 NS_ASSERTION(sizeof(double) == sizeof(uint64_t),
555 "False assumption about sizeof(double)");
556 return Read64(reinterpret_cast<uint64_t*>(aDouble));
557 }
559 static NS_METHOD
560 WriteSegmentToCString(nsIInputStream* aStream,
561 void *aClosure,
562 const char* aFromSegment,
563 uint32_t aToOffset,
564 uint32_t aCount,
565 uint32_t *aWriteCount)
566 {
567 nsACString* outString = static_cast<nsACString*>(aClosure);
569 outString->Append(aFromSegment, aCount);
571 *aWriteCount = aCount;
573 return NS_OK;
574 }
576 NS_IMETHODIMP
577 nsBinaryInputStream::ReadCString(nsACString& aString)
578 {
579 nsresult rv;
580 uint32_t length, bytesRead;
582 rv = Read32(&length);
583 if (NS_FAILED(rv)) return rv;
585 aString.Truncate();
586 rv = ReadSegments(WriteSegmentToCString, &aString, length, &bytesRead);
587 if (NS_FAILED(rv)) return rv;
589 if (bytesRead != length)
590 return NS_ERROR_FAILURE;
592 return NS_OK;
593 }
596 // sometimes, WriteSegmentToString will be handed an odd-number of
597 // bytes, which means we only have half of the last char16_t
598 struct WriteStringClosure {
599 char16_t *mWriteCursor;
600 bool mHasCarryoverByte;
601 char mCarryoverByte;
602 };
604 // there are a few cases we have to account for here:
605 // * even length buffer, no carryover - easy, just append
606 // * odd length buffer, no carryover - the last byte needs to be saved
607 // for carryover
608 // * odd length buffer, with carryover - first byte needs to be used
609 // with the carryover byte, and
610 // the rest of the even length
611 // buffer is appended as normal
612 // * even length buffer, with carryover - the first byte needs to be
613 // used with the previous carryover byte.
614 // this gives you an odd length buffer,
615 // so you have to save the last byte for
616 // the next carryover
619 // same version of the above, but with correct casting and endian swapping
620 static NS_METHOD
621 WriteSegmentToString(nsIInputStream* aStream,
622 void *aClosure,
623 const char* aFromSegment,
624 uint32_t aToOffset,
625 uint32_t aCount,
626 uint32_t *aWriteCount)
627 {
628 NS_PRECONDITION(aCount > 0, "Why are we being told to write 0 bytes?");
629 NS_PRECONDITION(sizeof(char16_t) == 2, "We can't handle other sizes!");
631 WriteStringClosure* closure = static_cast<WriteStringClosure*>(aClosure);
632 char16_t *cursor = closure->mWriteCursor;
634 // we're always going to consume the whole buffer no matter what
635 // happens, so take care of that right now.. that allows us to
636 // tweak aCount later. Do NOT move this!
637 *aWriteCount = aCount;
639 // if the last Write had an odd-number of bytes read, then
640 if (closure->mHasCarryoverByte) {
641 // re-create the two-byte sequence we want to work with
642 char bytes[2] = { closure->mCarryoverByte, *aFromSegment };
643 *cursor = *(char16_t*)bytes;
644 // Now the little endianness dance
645 mozilla::NativeEndian::swapToBigEndianInPlace(cursor, 1);
646 ++cursor;
648 // now skip past the first byte of the buffer.. code from here
649 // can assume normal operations, but should not assume aCount
650 // is relative to the ORIGINAL buffer
651 ++aFromSegment;
652 --aCount;
654 closure->mHasCarryoverByte = false;
655 }
657 // this array is possibly unaligned... be careful how we access it!
658 const char16_t *unicodeSegment =
659 reinterpret_cast<const char16_t*>(aFromSegment);
661 // calculate number of full characters in segment (aCount could be odd!)
662 uint32_t segmentLength = aCount / sizeof(char16_t);
664 // copy all data into our aligned buffer. byte swap if necessary.
665 // cursor may be unaligned, so we cannot use copyAndSwapToBigEndian directly
666 memcpy(cursor, unicodeSegment, segmentLength * sizeof(char16_t));
667 char16_t *end = cursor + segmentLength;
668 mozilla::NativeEndian::swapToBigEndianInPlace(cursor, segmentLength);
669 closure->mWriteCursor = end;
671 // remember this is the modifed aCount and aFromSegment,
672 // so that will take into account the fact that we might have
673 // skipped the first byte in the buffer
674 if (aCount % sizeof(char16_t) != 0) {
675 // we must have had a carryover byte, that we'll need the next
676 // time around
677 closure->mCarryoverByte = aFromSegment[aCount - 1];
678 closure->mHasCarryoverByte = true;
679 }
681 return NS_OK;
682 }
685 NS_IMETHODIMP
686 nsBinaryInputStream::ReadString(nsAString& aString)
687 {
688 nsresult rv;
689 uint32_t length, bytesRead;
691 rv = Read32(&length);
692 if (NS_FAILED(rv)) return rv;
694 if (length == 0) {
695 aString.Truncate();
696 return NS_OK;
697 }
699 // pre-allocate output buffer, and get direct access to buffer...
700 if (!aString.SetLength(length, mozilla::fallible_t()))
701 return NS_ERROR_OUT_OF_MEMORY;
703 nsAString::iterator start;
704 aString.BeginWriting(start);
706 WriteStringClosure closure;
707 closure.mWriteCursor = start.get();
708 closure.mHasCarryoverByte = false;
710 rv = ReadSegments(WriteSegmentToString, &closure,
711 length*sizeof(char16_t), &bytesRead);
712 if (NS_FAILED(rv)) return rv;
714 NS_ASSERTION(!closure.mHasCarryoverByte, "some strange stream corruption!");
716 if (bytesRead != length*sizeof(char16_t))
717 return NS_ERROR_FAILURE;
719 return NS_OK;
720 }
722 NS_IMETHODIMP
723 nsBinaryInputStream::ReadBytes(uint32_t aLength, char* *_rval)
724 {
725 nsresult rv;
726 uint32_t bytesRead;
727 char* s;
729 s = reinterpret_cast<char*>(moz_malloc(aLength));
730 if (!s)
731 return NS_ERROR_OUT_OF_MEMORY;
733 rv = Read(s, aLength, &bytesRead);
734 if (NS_FAILED(rv)) {
735 moz_free(s);
736 return rv;
737 }
738 if (bytesRead != aLength) {
739 moz_free(s);
740 return NS_ERROR_FAILURE;
741 }
743 *_rval = s;
744 return NS_OK;
745 }
747 NS_IMETHODIMP
748 nsBinaryInputStream::ReadByteArray(uint32_t aLength, uint8_t* *_rval)
749 {
750 return ReadBytes(aLength, reinterpret_cast<char **>(_rval));
751 }
753 NS_IMETHODIMP
754 nsBinaryInputStream::ReadArrayBuffer(uint32_t aLength, JS::Handle<JS::Value> aBuffer, JSContext* cx)
755 {
756 if (!aBuffer.isObject()) {
757 return NS_ERROR_FAILURE;
758 }
759 JS::RootedObject buffer(cx, &aBuffer.toObject());
760 if (!JS_IsArrayBufferObject(buffer)) {
761 return NS_ERROR_FAILURE;
762 }
764 uint32_t bufferLength = JS_GetArrayBufferByteLength(buffer);
765 if (bufferLength < aLength) {
766 return NS_ERROR_FAILURE;
767 }
769 char* data = reinterpret_cast<char*>(JS_GetStableArrayBufferData(cx, buffer));
770 if (!data) {
771 return NS_ERROR_FAILURE;
772 }
774 uint32_t bufSize = std::min<uint32_t>(aLength, 4096);
775 ScopedDeleteArray<char> buf(new char[bufSize]);
777 uint32_t remaining = aLength;
778 do {
779 // Read data into temporary buffer.
780 uint32_t bytesRead;
781 uint32_t amount = std::min(remaining, bufSize);
782 nsresult rv = Read(buf, amount, &bytesRead);
783 if (NS_WARN_IF(NS_FAILED(rv))) {
784 return rv;
785 }
786 MOZ_ASSERT(bytesRead <= amount);
788 if (bytesRead == 0) {
789 break;
790 }
792 // Copy data into actual buffer.
793 if (bufferLength != JS_GetArrayBufferByteLength(buffer)) {
794 return NS_ERROR_FAILURE;
795 }
796 PodCopy(data, buf.get(), bytesRead);
798 remaining -= bytesRead;
799 data += bytesRead;
800 } while (remaining > 0);
802 return remaining > 0 ? NS_ERROR_FAILURE : NS_OK;
803 }
805 NS_IMETHODIMP
806 nsBinaryInputStream::ReadObject(bool aIsStrongRef, nsISupports* *aObject)
807 {
808 nsCID cid;
809 nsIID iid;
810 nsresult rv = ReadID(&cid);
811 if (NS_WARN_IF(NS_FAILED(rv)))
812 return rv;
814 rv = ReadID(&iid);
815 if (NS_WARN_IF(NS_FAILED(rv)))
816 return rv;
818 // HACK: Intercept old (pre-gecko6) nsIURI IID, and replace with
819 // the updated IID, so that we're QI'ing to an actual interface.
820 // (As soon as we drop support for upgrading from pre-gecko6, we can
821 // remove this chunk.)
822 static const nsIID oldURIiid =
823 { 0x7a22cc0, 0xce5, 0x11d3,
824 { 0x93, 0x31, 0x0, 0x10, 0x4b, 0xa0, 0xfd, 0x40 }};
826 // hackaround for bug 670542
827 static const nsIID oldURIiid2 =
828 { 0xd6d04c36, 0x0fa4, 0x4db3,
829 { 0xbe, 0x05, 0x4a, 0x18, 0x39, 0x71, 0x03, 0xe2 }};
831 // hackaround for bug 682031
832 static const nsIID oldURIiid3 =
833 { 0x12120b20, 0x0929, 0x40e9,
834 { 0x88, 0xcf, 0x6e, 0x08, 0x76, 0x6e, 0x8b, 0x23 }};
836 if (iid.Equals(oldURIiid) ||
837 iid.Equals(oldURIiid2) ||
838 iid.Equals(oldURIiid3)) {
839 const nsIID newURIiid = NS_IURI_IID;
840 iid = newURIiid;
841 }
842 // END HACK
844 nsCOMPtr<nsISupports> object = do_CreateInstance(cid, &rv);
845 if (NS_WARN_IF(NS_FAILED(rv)))
846 return rv;
848 nsCOMPtr<nsISerializable> serializable = do_QueryInterface(object);
849 if (NS_WARN_IF(!serializable))
850 return NS_ERROR_UNEXPECTED;
852 rv = serializable->Read(this);
853 if (NS_WARN_IF(NS_FAILED(rv)))
854 return rv;
856 return object->QueryInterface(iid, reinterpret_cast<void**>(aObject));
857 }
859 NS_IMETHODIMP
860 nsBinaryInputStream::ReadID(nsID *aResult)
861 {
862 nsresult rv = Read32(&aResult->m0);
863 if (NS_WARN_IF(NS_FAILED(rv)))
864 return rv;
866 rv = Read16(&aResult->m1);
867 if (NS_WARN_IF(NS_FAILED(rv)))
868 return rv;
870 rv = Read16(&aResult->m2);
871 if (NS_WARN_IF(NS_FAILED(rv)))
872 return rv;
874 for (int i = 0; i < 8; ++i) {
875 rv = Read8(&aResult->m3[i]);
876 if (NS_WARN_IF(NS_FAILED(rv)))
877 return rv;
878 }
880 return NS_OK;
881 }
883 NS_IMETHODIMP_(char*)
884 nsBinaryInputStream::GetBuffer(uint32_t aLength, uint32_t aAlignMask)
885 {
886 if (mBufferAccess)
887 return mBufferAccess->GetBuffer(aLength, aAlignMask);
888 return nullptr;
889 }
891 NS_IMETHODIMP_(void)
892 nsBinaryInputStream::PutBuffer(char* aBuffer, uint32_t aLength)
893 {
894 if (mBufferAccess)
895 mBufferAccess->PutBuffer(aBuffer, aLength);
896 }