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/. */
8 * This file contains implementations of the nsIBinaryInputStream and
9 * nsIBinaryOutputStream interfaces. Together, these interfaces allows reading
10 * and writing of primitive data types (integers, floating-point values,
11 * booleans, etc.) to a stream in a binary, untagged, fixed-endianness format.
12 * This might be used, for example, to implement network protocols or to
13 * produce architecture-neutral binary disk files, i.e. ones that can be read
14 * and written by both big-endian and little-endian platforms. Output is
15 * written in big-endian order (high-order byte first), as this is traditional
18 * @See nsIBinaryInputStream
19 * @See nsIBinaryOutputStream
24 #include "nsBinaryStream.h"
26 #include "mozilla/EndianUtils.h"
27 #include "mozilla/PodOperations.h"
28 #include "mozilla/RefPtr.h"
29 #include "mozilla/Span.h"
30 #include "mozilla/UniquePtr.h"
34 #include "nsISerializable.h"
35 #include "nsIClassInfo.h"
36 #include "nsComponentManagerUtils.h"
37 #include "nsIURI.h" // for NS_IURI_IID
38 #include "nsIX509Cert.h" // for NS_IX509CERT_IID
40 #include "js/ArrayBuffer.h" // JS::{GetArrayBuffer{,ByteLength},IsArrayBufferObject}
41 #include "js/GCAPI.h" // JS::AutoCheckCannotGC
42 #include "js/RootingAPI.h" // JS::{Handle,Rooted}
43 #include "js/Value.h" // JS::Value
45 using mozilla::AsBytes
;
46 using mozilla::MakeUnique
;
47 using mozilla::PodCopy
;
49 using mozilla::UniquePtr
;
51 already_AddRefed
<nsIObjectOutputStream
> NS_NewObjectOutputStream(
52 nsIOutputStream
* aOutputStream
) {
53 MOZ_ASSERT(aOutputStream
);
54 auto stream
= mozilla::MakeRefPtr
<nsBinaryOutputStream
>();
56 MOZ_ALWAYS_SUCCEEDS(stream
->SetOutputStream(aOutputStream
));
57 return stream
.forget();
60 already_AddRefed
<nsIObjectInputStream
> NS_NewObjectInputStream(
61 nsIInputStream
* aInputStream
) {
62 MOZ_ASSERT(aInputStream
);
63 auto stream
= mozilla::MakeRefPtr
<nsBinaryInputStream
>();
65 MOZ_ALWAYS_SUCCEEDS(stream
->SetInputStream(aInputStream
));
66 return stream
.forget();
69 NS_IMPL_ISUPPORTS(nsBinaryOutputStream
, nsIObjectOutputStream
,
70 nsIBinaryOutputStream
, nsIOutputStream
)
73 nsBinaryOutputStream::Flush() {
74 if (NS_WARN_IF(!mOutputStream
)) {
75 return NS_ERROR_UNEXPECTED
;
77 return mOutputStream
->Flush();
81 nsBinaryOutputStream::Close() {
82 if (NS_WARN_IF(!mOutputStream
)) {
83 return NS_ERROR_UNEXPECTED
;
85 return mOutputStream
->Close();
89 nsBinaryOutputStream::StreamStatus() {
90 if (NS_WARN_IF(!mOutputStream
)) {
91 return NS_ERROR_UNEXPECTED
;
93 return mOutputStream
->StreamStatus();
97 nsBinaryOutputStream::Write(const char* aBuf
, uint32_t aCount
,
98 uint32_t* aActualBytes
) {
99 if (NS_WARN_IF(!mOutputStream
)) {
100 return NS_ERROR_UNEXPECTED
;
102 return mOutputStream
->Write(aBuf
, aCount
, aActualBytes
);
106 nsBinaryOutputStream::WriteFrom(nsIInputStream
* aInStr
, uint32_t aCount
,
108 MOZ_ASSERT_UNREACHABLE("WriteFrom");
109 return NS_ERROR_NOT_IMPLEMENTED
;
113 nsBinaryOutputStream::WriteSegments(nsReadSegmentFun aReader
, void* aClosure
,
114 uint32_t aCount
, uint32_t* aResult
) {
115 MOZ_ASSERT_UNREACHABLE("WriteSegments");
116 return NS_ERROR_NOT_IMPLEMENTED
;
120 nsBinaryOutputStream::IsNonBlocking(bool* aNonBlocking
) {
121 if (NS_WARN_IF(!mOutputStream
)) {
122 return NS_ERROR_UNEXPECTED
;
124 return mOutputStream
->IsNonBlocking(aNonBlocking
);
127 nsresult
nsBinaryOutputStream::WriteFully(const char* aBuf
, uint32_t aCount
) {
128 if (NS_WARN_IF(!mOutputStream
)) {
129 return NS_ERROR_UNEXPECTED
;
133 uint32_t bytesWritten
;
135 rv
= mOutputStream
->Write(aBuf
, aCount
, &bytesWritten
);
139 if (bytesWritten
!= aCount
) {
140 return NS_ERROR_FAILURE
;
146 nsBinaryOutputStream::SetOutputStream(nsIOutputStream
* aOutputStream
) {
147 if (NS_WARN_IF(!aOutputStream
)) {
148 return NS_ERROR_INVALID_ARG
;
150 mOutputStream
= aOutputStream
;
151 mBufferAccess
= do_QueryInterface(aOutputStream
);
156 nsBinaryOutputStream::WriteBoolean(bool aBoolean
) { return Write8(aBoolean
); }
159 nsBinaryOutputStream::Write8(uint8_t aByte
) {
160 return WriteFully((const char*)&aByte
, sizeof(aByte
));
164 nsBinaryOutputStream::Write16(uint16_t aNum
) {
165 aNum
= mozilla::NativeEndian::swapToBigEndian(aNum
);
166 return WriteFully((const char*)&aNum
, sizeof(aNum
));
170 nsBinaryOutputStream::Write32(uint32_t aNum
) {
171 aNum
= mozilla::NativeEndian::swapToBigEndian(aNum
);
172 return WriteFully((const char*)&aNum
, sizeof(aNum
));
176 nsBinaryOutputStream::Write64(uint64_t aNum
) {
178 uint32_t bytesWritten
;
180 aNum
= mozilla::NativeEndian::swapToBigEndian(aNum
);
181 rv
= Write(reinterpret_cast<char*>(&aNum
), sizeof(aNum
), &bytesWritten
);
185 if (bytesWritten
!= sizeof(aNum
)) {
186 return NS_ERROR_FAILURE
;
192 nsBinaryOutputStream::WriteFloat(float aFloat
) {
193 static_assert(sizeof(float) == sizeof(uint32_t),
194 "False assumption about sizeof(float)");
195 return Write32(*reinterpret_cast<uint32_t*>(&aFloat
));
199 nsBinaryOutputStream::WriteDouble(double aDouble
) {
200 static_assert(sizeof(double) == sizeof(uint64_t),
201 "False assumption about sizeof(double)");
202 return Write64(*reinterpret_cast<uint64_t*>(&aDouble
));
206 nsBinaryOutputStream::WriteStringZ(const char* aString
) {
210 length
= strlen(aString
);
211 rv
= Write32(length
);
215 return WriteFully(aString
, length
);
219 nsBinaryOutputStream::WriteWStringZ(const char16_t
* aString
) {
220 uint32_t length
= NS_strlen(aString
);
221 nsresult rv
= Write32(length
);
231 rv
= WriteBytes(AsBytes(Span(aString
, length
)));
233 // XXX use WriteSegments here to avoid copy!
239 copy
= static_cast<char16_t
*>(malloc(length
* sizeof(char16_t
)));
241 return NS_ERROR_OUT_OF_MEMORY
;
244 NS_ASSERTION((uintptr_t(aString
) & 0x1) == 0, "aString not properly aligned");
245 mozilla::NativeEndian::copyAndSwapToBigEndian(copy
, aString
, length
);
246 rv
= WriteBytes(AsBytes(Span(copy
, length
)));
256 nsBinaryOutputStream::WriteUtf8Z(const char16_t
* aString
) {
257 return WriteStringZ(NS_ConvertUTF16toUTF8(aString
).get());
260 nsresult
nsBinaryOutputStream::WriteBytes(Span
<const uint8_t> aBytes
) {
262 uint32_t bytesWritten
;
264 rv
= Write(reinterpret_cast<const char*>(aBytes
.Elements()), aBytes
.Length(),
269 if (bytesWritten
!= aBytes
.Length()) {
270 return NS_ERROR_FAILURE
;
276 nsBinaryOutputStream::WriteBytesFromJS(const char* aString
, uint32_t aLength
) {
277 return WriteBytes(AsBytes(Span(aString
, aLength
)));
281 nsBinaryOutputStream::WriteByteArray(const nsTArray
<uint8_t>& aByteArray
) {
282 return WriteBytes(aByteArray
);
286 nsBinaryOutputStream::WriteObject(nsISupports
* aObject
, bool aIsStrongRef
) {
287 return WriteCompoundObject(aObject
, NS_GET_IID(nsISupports
), aIsStrongRef
);
291 nsBinaryOutputStream::WriteSingleRefObject(nsISupports
* aObject
) {
292 return WriteCompoundObject(aObject
, NS_GET_IID(nsISupports
), true);
296 nsBinaryOutputStream::WriteCompoundObject(nsISupports
* aObject
,
299 nsCOMPtr
<nsIClassInfo
> classInfo
= do_QueryInterface(aObject
);
300 nsCOMPtr
<nsISerializable
> serializable
= do_QueryInterface(aObject
);
302 // Can't deal with weak refs
303 if (NS_WARN_IF(!aIsStrongRef
)) {
304 return NS_ERROR_UNEXPECTED
;
306 if (NS_WARN_IF(!classInfo
) || NS_WARN_IF(!serializable
)) {
307 return NS_ERROR_NOT_AVAILABLE
;
311 nsresult rv
= classInfo
->GetClassIDNoAlloc(&cid
);
312 if (NS_SUCCEEDED(rv
)) {
315 nsCID
* cidptr
= nullptr;
316 rv
= classInfo
->GetClassID(&cidptr
);
317 if (NS_WARN_IF(NS_FAILED(rv
))) {
321 rv
= WriteID(*cidptr
);
326 if (NS_WARN_IF(NS_FAILED(rv
))) {
331 if (NS_WARN_IF(NS_FAILED(rv
))) {
335 return serializable
->Write(this);
339 nsBinaryOutputStream::WriteID(const nsIID
& aIID
) {
340 nsresult rv
= Write32(aIID
.m0
);
341 if (NS_WARN_IF(NS_FAILED(rv
))) {
345 rv
= Write16(aIID
.m1
);
346 if (NS_WARN_IF(NS_FAILED(rv
))) {
350 rv
= Write16(aIID
.m2
);
351 if (NS_WARN_IF(NS_FAILED(rv
))) {
355 rv
= WriteBytes(aIID
.m3
);
356 if (NS_WARN_IF(NS_FAILED(rv
))) {
363 NS_IMETHODIMP_(char*)
364 nsBinaryOutputStream::GetBuffer(uint32_t aLength
, uint32_t aAlignMask
) {
366 return mBufferAccess
->GetBuffer(aLength
, aAlignMask
);
372 nsBinaryOutputStream::PutBuffer(char* aBuffer
, uint32_t aLength
) {
374 mBufferAccess
->PutBuffer(aBuffer
, aLength
);
378 NS_IMPL_ISUPPORTS(nsBinaryInputStream
, nsIObjectInputStream
,
379 nsIBinaryInputStream
, nsIInputStream
)
382 nsBinaryInputStream::Available(uint64_t* aResult
) {
383 if (NS_WARN_IF(!mInputStream
)) {
384 return NS_ERROR_UNEXPECTED
;
386 return mInputStream
->Available(aResult
);
390 nsBinaryInputStream::StreamStatus() {
391 if (NS_WARN_IF(!mInputStream
)) {
392 return NS_ERROR_UNEXPECTED
;
394 return mInputStream
->StreamStatus();
398 nsBinaryInputStream::Read(char* aBuffer
, uint32_t aCount
, uint32_t* aNumRead
) {
399 if (NS_WARN_IF(!mInputStream
)) {
400 return NS_ERROR_UNEXPECTED
;
403 // mInputStream might give us short reads, so deal with that.
404 uint32_t totalRead
= 0;
408 nsresult rv
= mInputStream
->Read(aBuffer
, aCount
, &bytesRead
);
409 if (rv
== NS_BASE_STREAM_WOULD_BLOCK
&& totalRead
!= 0) {
410 // We already read some data. Return it.
418 totalRead
+= bytesRead
;
419 aBuffer
+= bytesRead
;
421 } while (aCount
!= 0 && bytesRead
!= 0);
423 *aNumRead
= totalRead
;
428 // when forwarding ReadSegments to mInputStream, we need to make sure
429 // 'this' is being passed to the writer each time. To do this, we need
430 // a thunking function which keeps the real input stream around.
432 // the closure wrapper
433 struct MOZ_STACK_CLASS ReadSegmentsClosure
{
434 nsCOMPtr
<nsIInputStream
> mRealInputStream
;
436 nsWriteSegmentFun mRealWriter
;
437 nsresult mRealResult
;
438 uint32_t mBytesRead
; // to properly implement aToOffset
441 // the thunking function
442 static nsresult
ReadSegmentForwardingThunk(nsIInputStream
* aStream
,
444 const char* aFromSegment
,
445 uint32_t aToOffset
, uint32_t aCount
,
446 uint32_t* aWriteCount
) {
447 ReadSegmentsClosure
* thunkClosure
=
448 reinterpret_cast<ReadSegmentsClosure
*>(aClosure
);
450 NS_ASSERTION(NS_SUCCEEDED(thunkClosure
->mRealResult
),
451 "How did this get to be a failure status?");
453 thunkClosure
->mRealResult
= thunkClosure
->mRealWriter(
454 thunkClosure
->mRealInputStream
, thunkClosure
->mRealClosure
, aFromSegment
,
455 thunkClosure
->mBytesRead
+ aToOffset
, aCount
, aWriteCount
);
457 return thunkClosure
->mRealResult
;
461 nsBinaryInputStream::ReadSegments(nsWriteSegmentFun aWriter
, void* aClosure
,
462 uint32_t aCount
, uint32_t* aResult
) {
463 if (NS_WARN_IF(!mInputStream
)) {
464 return NS_ERROR_UNEXPECTED
;
467 ReadSegmentsClosure thunkClosure
= {this, aClosure
, aWriter
, NS_OK
, 0};
469 // mInputStream might give us short reads, so deal with that.
472 nsresult rv
= mInputStream
->ReadSegments(ReadSegmentForwardingThunk
,
473 &thunkClosure
, aCount
, &bytesRead
);
475 if (rv
== NS_BASE_STREAM_WOULD_BLOCK
&& thunkClosure
.mBytesRead
!= 0) {
476 // We already read some data. Return it.
484 thunkClosure
.mBytesRead
+= bytesRead
;
486 } while (aCount
!= 0 && bytesRead
!= 0 &&
487 NS_SUCCEEDED(thunkClosure
.mRealResult
));
489 *aResult
= thunkClosure
.mBytesRead
;
495 nsBinaryInputStream::IsNonBlocking(bool* aNonBlocking
) {
496 if (NS_WARN_IF(!mInputStream
)) {
497 return NS_ERROR_UNEXPECTED
;
499 return mInputStream
->IsNonBlocking(aNonBlocking
);
503 nsBinaryInputStream::Close() {
504 if (NS_WARN_IF(!mInputStream
)) {
505 return NS_ERROR_UNEXPECTED
;
507 return mInputStream
->Close();
511 nsBinaryInputStream::SetInputStream(nsIInputStream
* aInputStream
) {
512 if (NS_WARN_IF(!aInputStream
)) {
513 return NS_ERROR_INVALID_ARG
;
515 mInputStream
= aInputStream
;
516 mBufferAccess
= do_QueryInterface(aInputStream
);
521 nsBinaryInputStream::ReadBoolean(bool* aBoolean
) {
523 nsresult rv
= Read8(&byteResult
);
527 *aBoolean
= !!byteResult
;
532 nsBinaryInputStream::Read8(uint8_t* aByte
) {
536 rv
= Read(reinterpret_cast<char*>(aByte
), sizeof(*aByte
), &bytesRead
);
540 if (bytesRead
!= 1) {
541 return NS_ERROR_FAILURE
;
547 nsBinaryInputStream::Read16(uint16_t* aNum
) {
549 nsresult rv
= Read(reinterpret_cast<char*>(aNum
), sizeof(*aNum
), &bytesRead
);
553 if (bytesRead
!= sizeof(*aNum
)) {
554 return NS_ERROR_FAILURE
;
556 *aNum
= mozilla::NativeEndian::swapFromBigEndian(*aNum
);
561 nsBinaryInputStream::Read32(uint32_t* aNum
) {
563 nsresult rv
= Read(reinterpret_cast<char*>(aNum
), sizeof(*aNum
), &bytesRead
);
567 if (bytesRead
!= sizeof(*aNum
)) {
568 return NS_ERROR_FAILURE
;
570 *aNum
= mozilla::NativeEndian::swapFromBigEndian(*aNum
);
575 nsBinaryInputStream::Read64(uint64_t* aNum
) {
577 nsresult rv
= Read(reinterpret_cast<char*>(aNum
), sizeof(*aNum
), &bytesRead
);
581 if (bytesRead
!= sizeof(*aNum
)) {
582 return NS_ERROR_FAILURE
;
584 *aNum
= mozilla::NativeEndian::swapFromBigEndian(*aNum
);
589 nsBinaryInputStream::ReadFloat(float* aFloat
) {
590 static_assert(sizeof(float) == sizeof(uint32_t),
591 "False assumption about sizeof(float)");
592 return Read32(reinterpret_cast<uint32_t*>(aFloat
));
596 nsBinaryInputStream::ReadDouble(double* aDouble
) {
597 static_assert(sizeof(double) == sizeof(uint64_t),
598 "False assumption about sizeof(double)");
599 return Read64(reinterpret_cast<uint64_t*>(aDouble
));
602 static nsresult
WriteSegmentToCString(nsIInputStream
* aStream
, void* aClosure
,
603 const char* aFromSegment
,
604 uint32_t aToOffset
, uint32_t aCount
,
605 uint32_t* aWriteCount
) {
606 nsACString
* outString
= static_cast<nsACString
*>(aClosure
);
608 outString
->Append(aFromSegment
, aCount
);
610 *aWriteCount
= aCount
;
616 nsBinaryInputStream::ReadCString(nsACString
& aString
) {
618 uint32_t length
, bytesRead
;
620 rv
= Read32(&length
);
626 rv
= ReadSegments(WriteSegmentToCString
, &aString
, length
, &bytesRead
);
631 if (bytesRead
!= length
) {
632 return NS_ERROR_FAILURE
;
638 // sometimes, WriteSegmentToString will be handed an odd-number of
639 // bytes, which means we only have half of the last char16_t
640 struct WriteStringClosure
{
641 char16_t
* mWriteCursor
;
642 bool mHasCarryoverByte
;
646 // there are a few cases we have to account for here:
647 // * even length buffer, no carryover - easy, just append
648 // * odd length buffer, no carryover - the last byte needs to be saved
650 // * odd length buffer, with carryover - first byte needs to be used
651 // with the carryover byte, and
652 // the rest of the even length
653 // buffer is appended as normal
654 // * even length buffer, with carryover - the first byte needs to be
655 // used with the previous carryover byte.
656 // this gives you an odd length buffer,
657 // so you have to save the last byte for
658 // the next carryover
660 // same version of the above, but with correct casting and endian swapping
661 static nsresult
WriteSegmentToString(nsIInputStream
* aStream
, void* aClosure
,
662 const char* aFromSegment
,
663 uint32_t aToOffset
, uint32_t aCount
,
664 uint32_t* aWriteCount
) {
665 MOZ_ASSERT(aCount
> 0, "Why are we being told to write 0 bytes?");
666 static_assert(sizeof(char16_t
) == 2, "We can't handle other sizes!");
668 WriteStringClosure
* closure
= static_cast<WriteStringClosure
*>(aClosure
);
669 char16_t
* cursor
= closure
->mWriteCursor
;
671 // we're always going to consume the whole buffer no matter what
672 // happens, so take care of that right now.. that allows us to
673 // tweak aCount later. Do NOT move this!
674 *aWriteCount
= aCount
;
676 // if the last Write had an odd-number of bytes read, then
677 if (closure
->mHasCarryoverByte
) {
678 // re-create the two-byte sequence we want to work with
679 char bytes
[2] = {closure
->mCarryoverByte
, *aFromSegment
};
680 *cursor
= *(char16_t
*)bytes
;
681 // Now the little endianness dance
682 mozilla::NativeEndian::swapToBigEndianInPlace(cursor
, 1);
685 // now skip past the first byte of the buffer.. code from here
686 // can assume normal operations, but should not assume aCount
687 // is relative to the ORIGINAL buffer
691 closure
->mHasCarryoverByte
= false;
694 // this array is possibly unaligned... be careful how we access it!
695 const char16_t
* unicodeSegment
=
696 reinterpret_cast<const char16_t
*>(aFromSegment
);
698 // calculate number of full characters in segment (aCount could be odd!)
699 uint32_t segmentLength
= aCount
/ sizeof(char16_t
);
701 // copy all data into our aligned buffer. byte swap if necessary.
702 // cursor may be unaligned, so we cannot use copyAndSwapToBigEndian directly
703 memcpy(cursor
, unicodeSegment
, segmentLength
* sizeof(char16_t
));
704 char16_t
* end
= cursor
+ segmentLength
;
705 mozilla::NativeEndian::swapToBigEndianInPlace(cursor
, segmentLength
);
706 closure
->mWriteCursor
= end
;
708 // remember this is the modifed aCount and aFromSegment,
709 // so that will take into account the fact that we might have
710 // skipped the first byte in the buffer
711 if (aCount
% sizeof(char16_t
) != 0) {
712 // we must have had a carryover byte, that we'll need the next
714 closure
->mCarryoverByte
= aFromSegment
[aCount
- 1];
715 closure
->mHasCarryoverByte
= true;
722 nsBinaryInputStream::ReadString(nsAString
& aString
) {
724 uint32_t length
, bytesRead
;
726 rv
= Read32(&length
);
736 // pre-allocate output buffer, and get direct access to buffer...
737 if (!aString
.SetLength(length
, mozilla::fallible
)) {
738 return NS_ERROR_OUT_OF_MEMORY
;
741 WriteStringClosure closure
;
742 closure
.mWriteCursor
= aString
.BeginWriting();
743 closure
.mHasCarryoverByte
= false;
745 rv
= ReadSegments(WriteSegmentToString
, &closure
, length
* sizeof(char16_t
),
751 NS_ASSERTION(!closure
.mHasCarryoverByte
, "some strange stream corruption!");
753 if (bytesRead
!= length
* sizeof(char16_t
)) {
754 return NS_ERROR_FAILURE
;
760 nsresult
nsBinaryInputStream::ReadBytesToBuffer(uint32_t aLength
,
763 nsresult rv
= Read(reinterpret_cast<char*>(aBuffer
), aLength
, &bytesRead
);
767 if (bytesRead
!= aLength
) {
768 return NS_ERROR_FAILURE
;
775 nsBinaryInputStream::ReadBytes(uint32_t aLength
, char** aResult
) {
776 char* s
= static_cast<char*>(malloc(aLength
));
778 return NS_ERROR_OUT_OF_MEMORY
;
781 nsresult rv
= ReadBytesToBuffer(aLength
, reinterpret_cast<uint8_t*>(s
));
792 nsBinaryInputStream::ReadByteArray(uint32_t aLength
,
793 nsTArray
<uint8_t>& aResult
) {
794 if (!aResult
.SetLength(aLength
, mozilla::fallible
)) {
795 return NS_ERROR_OUT_OF_MEMORY
;
797 nsresult rv
= ReadBytesToBuffer(aLength
, aResult
.Elements());
805 nsBinaryInputStream::ReadArrayBuffer(uint64_t aLength
,
806 JS::Handle
<JS::Value
> aBuffer
,
807 JSContext
* aCx
, uint64_t* aReadLength
) {
808 if (!aBuffer
.isObject()) {
809 return NS_ERROR_FAILURE
;
811 JS::Rooted
<JSObject
*> buffer(aCx
, &aBuffer
.toObject());
812 if (!JS::IsArrayBufferObject(buffer
)) {
813 return NS_ERROR_FAILURE
;
816 size_t bufferLength
= JS::GetArrayBufferByteLength(buffer
);
817 if (bufferLength
< aLength
) {
818 return NS_ERROR_FAILURE
;
821 uint32_t bufSize
= std::min
<uint64_t>(aLength
, 4096);
822 UniquePtr
<char[]> buf
= MakeUnique
<char[]>(bufSize
);
827 // Read data into temporary buffer.
829 uint32_t amount
= std::min
<uint64_t>(aLength
- pos
, bufSize
);
830 nsresult rv
= Read(buf
.get(), amount
, &bytesRead
);
831 if (NS_WARN_IF(NS_FAILED(rv
))) {
834 MOZ_ASSERT(bytesRead
<= amount
);
836 if (bytesRead
== 0) {
840 // Copy data into actual buffer.
842 JS::AutoCheckCannotGC nogc
;
844 if (bufferLength
!= JS::GetArrayBufferByteLength(buffer
)) {
845 return NS_ERROR_FAILURE
;
848 char* data
= reinterpret_cast<char*>(
849 JS::GetArrayBufferData(buffer
, &isShared
, nogc
));
850 MOZ_ASSERT(!isShared
); // Implied by JS::GetArrayBufferData()
852 return NS_ERROR_FAILURE
;
855 *aReadLength
+= bytesRead
;
856 PodCopy(data
+ pos
, buf
.get(), bytesRead
);
859 } while (pos
< aLength
);
865 nsBinaryInputStream::ReadObject(bool aIsStrongRef
, nsISupports
** aObject
) {
868 nsresult rv
= ReadID(&cid
);
869 if (NS_WARN_IF(NS_FAILED(rv
))) {
874 if (NS_WARN_IF(NS_FAILED(rv
))) {
878 // HACK: Intercept old (pre-gecko6) nsIURI IID, and replace with
879 // the updated IID, so that we're QI'ing to an actual interface.
880 // (As soon as we drop support for upgrading from pre-gecko6, we can
881 // remove this chunk.)
882 static const nsIID oldURIiid
= {
886 {0x93, 0x31, 0x0, 0x10, 0x4b, 0xa0, 0xfd, 0x40}};
888 // hackaround for bug 670542
889 static const nsIID oldURIiid2
= {
893 {0xbe, 0x05, 0x4a, 0x18, 0x39, 0x71, 0x03, 0xe2}};
895 // hackaround for bug 682031
896 static const nsIID oldURIiid3
= {
900 {0x88, 0xcf, 0x6e, 0x08, 0x76, 0x6e, 0x8b, 0x23}};
902 // hackaround for bug 1195415
903 static const nsIID oldURIiid4
= {
907 {0xa3, 0xfd, 0xaf, 0x98, 0xc8, 0xa1, 0xaf, 0x11}};
909 if (iid
.Equals(oldURIiid
) || iid
.Equals(oldURIiid2
) ||
910 iid
.Equals(oldURIiid3
) || iid
.Equals(oldURIiid4
)) {
911 const nsIID newURIiid
= NS_IURI_IID
;
915 // Hack around bug 1508939
916 // The old CSP serialization can't be handled cleanly when
917 // it's embedded in an old style principal
918 static const nsIID oldCSPiid
= {
922 {0x87, 0xe0, 0x8d, 0x21, 0x0d, 0xbb, 0x3f, 0x9f}};
923 if (iid
.Equals(oldCSPiid
)) {
924 return NS_ERROR_FAILURE
;
928 // HACK: Service workers store resource security info on disk in the dom
929 // Cache API. When the uuid of the nsIX509Cert interface changes
930 // these serialized objects cannot be loaded any more. This hack
931 // works around this issue.
933 // hackaround for bug 1247580 (FF45 to FF46 transition)
934 static const nsIID oldCertIID
= {
938 {0x86, 0xba, 0x48, 0xaf, 0x53, 0xc3, 0x93, 0xe6}};
940 if (iid
.Equals(oldCertIID
)) {
941 const nsIID newCertIID
= NS_IX509CERT_IID
;
946 nsCOMPtr
<nsISupports
> object
= do_CreateInstance(cid
, &rv
);
947 if (NS_WARN_IF(NS_FAILED(rv
))) {
951 nsCOMPtr
<nsISerializable
> serializable
= do_QueryInterface(object
);
952 if (NS_WARN_IF(!serializable
)) {
953 return NS_ERROR_UNEXPECTED
;
956 rv
= serializable
->Read(this);
957 if (NS_WARN_IF(NS_FAILED(rv
))) {
961 return object
->QueryInterface(iid
, reinterpret_cast<void**>(aObject
));
965 nsBinaryInputStream::ReadID(nsID
* aResult
) {
966 nsresult rv
= Read32(&aResult
->m0
);
967 if (NS_WARN_IF(NS_FAILED(rv
))) {
971 rv
= Read16(&aResult
->m1
);
972 if (NS_WARN_IF(NS_FAILED(rv
))) {
976 rv
= Read16(&aResult
->m2
);
977 if (NS_WARN_IF(NS_FAILED(rv
))) {
981 const uint32_t toRead
= sizeof(aResult
->m3
);
982 uint32_t bytesRead
= 0;
983 rv
= Read(reinterpret_cast<char*>(&aResult
->m3
[0]), toRead
, &bytesRead
);
984 if (NS_WARN_IF(NS_FAILED(rv
))) {
987 if (bytesRead
!= toRead
) {
988 return NS_ERROR_FAILURE
;
994 NS_IMETHODIMP_(char*)
995 nsBinaryInputStream::GetBuffer(uint32_t aLength
, uint32_t aAlignMask
) {
997 return mBufferAccess
->GetBuffer(aLength
, aAlignMask
);
1002 NS_IMETHODIMP_(void)
1003 nsBinaryInputStream::PutBuffer(char* aBuffer
, uint32_t aLength
) {
1004 if (mBufferAccess
) {
1005 mBufferAccess
->PutBuffer(aBuffer
, aLength
);