xpcom/io/nsBinaryStream.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 }

mercurial