LCOV - code coverage report
Current view: top level - xpcom/io - nsBinaryStream.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 191 404 47.3 %
Date: 2017-07-14 16:53:18 Functions: 31 58 53.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /**
       8             :  * 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
      16             :  * network order.
      17             :  *
      18             :  * @See nsIBinaryInputStream
      19             :  * @See nsIBinaryOutputStream
      20             :  */
      21             : #include <algorithm>
      22             : #include <string.h>
      23             : 
      24             : #include "nsBinaryStream.h"
      25             : 
      26             : #include "mozilla/EndianUtils.h"
      27             : #include "mozilla/PodOperations.h"
      28             : #include "mozilla/UniquePtr.h"
      29             : 
      30             : #include "nsCRT.h"
      31             : #include "nsString.h"
      32             : #include "nsISerializable.h"
      33             : #include "nsIClassInfo.h"
      34             : #include "nsComponentManagerUtils.h"
      35             : #include "nsIURI.h" // for NS_IURI_IID
      36             : #include "nsIX509Cert.h" // for NS_IX509CERT_IID
      37             : 
      38             : #include "jsfriendapi.h"
      39             : 
      40             : using mozilla::MakeUnique;
      41             : using mozilla::PodCopy;
      42             : using mozilla::UniquePtr;
      43             : 
      44          32 : NS_IMPL_ISUPPORTS(nsBinaryOutputStream,
      45             :                   nsIObjectOutputStream,
      46             :                   nsIBinaryOutputStream,
      47             :                   nsIOutputStream)
      48             : 
      49             : NS_IMETHODIMP
      50           0 : nsBinaryOutputStream::Flush()
      51             : {
      52           0 :   if (NS_WARN_IF(!mOutputStream)) {
      53           0 :     return NS_ERROR_UNEXPECTED;
      54             :   }
      55           0 :   return mOutputStream->Flush();
      56             : }
      57             : 
      58             : NS_IMETHODIMP
      59           0 : nsBinaryOutputStream::Close()
      60             : {
      61           0 :   if (NS_WARN_IF(!mOutputStream)) {
      62           0 :     return NS_ERROR_UNEXPECTED;
      63             :   }
      64           0 :   return mOutputStream->Close();
      65             : }
      66             : 
      67             : NS_IMETHODIMP
      68           0 : nsBinaryOutputStream::Write(const char* aBuf, uint32_t aCount,
      69             :                             uint32_t* aActualBytes)
      70             : {
      71           0 :   if (NS_WARN_IF(!mOutputStream)) {
      72           0 :     return NS_ERROR_UNEXPECTED;
      73             :   }
      74           0 :   return mOutputStream->Write(aBuf, aCount, aActualBytes);
      75             : }
      76             : 
      77             : NS_IMETHODIMP
      78           0 : nsBinaryOutputStream::WriteFrom(nsIInputStream* aInStr, uint32_t aCount,
      79             :                                 uint32_t* aResult)
      80             : {
      81           0 :   NS_NOTREACHED("WriteFrom");
      82           0 :   return NS_ERROR_NOT_IMPLEMENTED;
      83             : }
      84             : 
      85             : NS_IMETHODIMP
      86           0 : nsBinaryOutputStream::WriteSegments(nsReadSegmentFun aReader, void* aClosure,
      87             :                                     uint32_t aCount, uint32_t* aResult)
      88             : {
      89           0 :   NS_NOTREACHED("WriteSegments");
      90           0 :   return NS_ERROR_NOT_IMPLEMENTED;
      91             : }
      92             : 
      93             : NS_IMETHODIMP
      94           0 : nsBinaryOutputStream::IsNonBlocking(bool* aNonBlocking)
      95             : {
      96           0 :   if (NS_WARN_IF(!mOutputStream)) {
      97           0 :     return NS_ERROR_UNEXPECTED;
      98             :   }
      99           0 :   return mOutputStream->IsNonBlocking(aNonBlocking);
     100             : }
     101             : 
     102             : nsresult
     103         152 : nsBinaryOutputStream::WriteFully(const char* aBuf, uint32_t aCount)
     104             : {
     105         152 :   if (NS_WARN_IF(!mOutputStream)) {
     106           0 :     return NS_ERROR_UNEXPECTED;
     107             :   }
     108             : 
     109             :   nsresult rv;
     110             :   uint32_t bytesWritten;
     111             : 
     112         152 :   rv = mOutputStream->Write(aBuf, aCount, &bytesWritten);
     113         152 :   if (NS_FAILED(rv)) {
     114           0 :     return rv;
     115             :   }
     116         152 :   if (bytesWritten != aCount) {
     117           0 :     return NS_ERROR_FAILURE;
     118             :   }
     119         152 :   return NS_OK;
     120             : }
     121             : 
     122             : NS_IMETHODIMP
     123           4 : nsBinaryOutputStream::SetOutputStream(nsIOutputStream* aOutputStream)
     124             : {
     125           4 :   if (NS_WARN_IF(!aOutputStream)) {
     126           0 :     return NS_ERROR_INVALID_ARG;
     127             :   }
     128           4 :   mOutputStream = aOutputStream;
     129           4 :   mBufferAccess = do_QueryInterface(aOutputStream);
     130           4 :   return NS_OK;
     131             : }
     132             : 
     133             : NS_IMETHODIMP
     134           7 : nsBinaryOutputStream::WriteBoolean(bool aBoolean)
     135             : {
     136           7 :   return Write8(aBoolean);
     137             : }
     138             : 
     139             : NS_IMETHODIMP
     140          87 : nsBinaryOutputStream::Write8(uint8_t aByte)
     141             : {
     142          87 :   return WriteFully((const char*)&aByte, sizeof(aByte));
     143             : }
     144             : 
     145             : NS_IMETHODIMP
     146          20 : nsBinaryOutputStream::Write16(uint16_t aNum)
     147             : {
     148          20 :   aNum = mozilla::NativeEndian::swapToBigEndian(aNum);
     149          20 :   return WriteFully((const char*)&aNum, sizeof(aNum));
     150             : }
     151             : 
     152             : NS_IMETHODIMP
     153          42 : nsBinaryOutputStream::Write32(uint32_t aNum)
     154             : {
     155          42 :   aNum = mozilla::NativeEndian::swapToBigEndian(aNum);
     156          42 :   return WriteFully((const char*)&aNum, sizeof(aNum));
     157             : }
     158             : 
     159             : NS_IMETHODIMP
     160           0 : nsBinaryOutputStream::Write64(uint64_t aNum)
     161             : {
     162             :   nsresult rv;
     163             :   uint32_t bytesWritten;
     164             : 
     165           0 :   aNum = mozilla::NativeEndian::swapToBigEndian(aNum);
     166           0 :   rv = Write(reinterpret_cast<char*>(&aNum), sizeof(aNum), &bytesWritten);
     167           0 :   if (NS_FAILED(rv)) {
     168           0 :     return rv;
     169             :   }
     170           0 :   if (bytesWritten != sizeof(aNum)) {
     171           0 :     return NS_ERROR_FAILURE;
     172             :   }
     173           0 :   return rv;
     174             : }
     175             : 
     176             : NS_IMETHODIMP
     177           0 : nsBinaryOutputStream::WriteFloat(float aFloat)
     178             : {
     179             :   NS_ASSERTION(sizeof(float) == sizeof(uint32_t),
     180             :                "False assumption about sizeof(float)");
     181           0 :   return Write32(*reinterpret_cast<uint32_t*>(&aFloat));
     182             : }
     183             : 
     184             : NS_IMETHODIMP
     185           0 : nsBinaryOutputStream::WriteDouble(double aDouble)
     186             : {
     187             :   NS_ASSERTION(sizeof(double) == sizeof(uint64_t),
     188             :                "False assumption about sizeof(double)");
     189           0 :   return Write64(*reinterpret_cast<uint64_t*>(&aDouble));
     190             : }
     191             : 
     192             : NS_IMETHODIMP
     193           3 : nsBinaryOutputStream::WriteStringZ(const char* aString)
     194             : {
     195             :   uint32_t length;
     196             :   nsresult rv;
     197             : 
     198           3 :   length = strlen(aString);
     199           3 :   rv = Write32(length);
     200           3 :   if (NS_FAILED(rv)) {
     201           0 :     return rv;
     202             :   }
     203           3 :   return WriteFully(aString, length);
     204             : }
     205             : 
     206             : NS_IMETHODIMP
     207           0 : nsBinaryOutputStream::WriteWStringZ(const char16_t* aString)
     208             : {
     209             :   uint32_t length, byteCount;
     210             :   nsresult rv;
     211             : 
     212           0 :   length = NS_strlen(aString);
     213           0 :   rv = Write32(length);
     214           0 :   if (NS_FAILED(rv)) {
     215           0 :     return rv;
     216             :   }
     217             : 
     218           0 :   if (length == 0) {
     219           0 :     return NS_OK;
     220             :   }
     221           0 :   byteCount = length * sizeof(char16_t);
     222             : 
     223             : #ifdef IS_BIG_ENDIAN
     224             :   rv = WriteBytes(reinterpret_cast<const char*>(aString), byteCount);
     225             : #else
     226             :   // XXX use WriteSegments here to avoid copy!
     227             :   char16_t* copy;
     228             :   char16_t temp[64];
     229           0 :   if (length <= 64) {
     230           0 :     copy = temp;
     231             :   } else {
     232           0 :     copy = reinterpret_cast<char16_t*>(malloc(byteCount));
     233           0 :     if (!copy) {
     234           0 :       return NS_ERROR_OUT_OF_MEMORY;
     235             :     }
     236             :   }
     237           0 :   NS_ASSERTION((uintptr_t(aString) & 0x1) == 0, "aString not properly aligned");
     238           0 :   mozilla::NativeEndian::copyAndSwapToBigEndian(copy, aString, length);
     239           0 :   rv = WriteBytes(reinterpret_cast<const char*>(copy), byteCount);
     240           0 :   if (copy != temp) {
     241           0 :     free(copy);
     242             :   }
     243             : #endif
     244             : 
     245           0 :   return rv;
     246             : }
     247             : 
     248             : NS_IMETHODIMP
     249           0 : nsBinaryOutputStream::WriteUtf8Z(const char16_t* aString)
     250             : {
     251           0 :   return WriteStringZ(NS_ConvertUTF16toUTF8(aString).get());
     252             : }
     253             : 
     254             : NS_IMETHODIMP
     255           0 : nsBinaryOutputStream::WriteBytes(const char* aString, uint32_t aLength)
     256             : {
     257             :   nsresult rv;
     258             :   uint32_t bytesWritten;
     259             : 
     260           0 :   rv = Write(aString, aLength, &bytesWritten);
     261           0 :   if (NS_FAILED(rv)) {
     262           0 :     return rv;
     263             :   }
     264           0 :   if (bytesWritten != aLength) {
     265           0 :     return NS_ERROR_FAILURE;
     266             :   }
     267           0 :   return rv;
     268             : }
     269             : 
     270             : NS_IMETHODIMP
     271           0 : nsBinaryOutputStream::WriteByteArray(uint8_t* aBytes, uint32_t aLength)
     272             : {
     273           0 :   return WriteBytes(reinterpret_cast<char*>(aBytes), aLength);
     274             : }
     275             : 
     276             : NS_IMETHODIMP
     277           0 : nsBinaryOutputStream::WriteObject(nsISupports* aObject, bool aIsStrongRef)
     278             : {
     279           0 :   return WriteCompoundObject(aObject, NS_GET_IID(nsISupports),
     280           0 :                              aIsStrongRef);
     281             : }
     282             : 
     283             : NS_IMETHODIMP
     284           0 : nsBinaryOutputStream::WriteSingleRefObject(nsISupports* aObject)
     285             : {
     286             :   return WriteCompoundObject(aObject, NS_GET_IID(nsISupports),
     287           0 :                              true);
     288             : }
     289             : 
     290             : NS_IMETHODIMP
     291           5 : nsBinaryOutputStream::WriteCompoundObject(nsISupports* aObject,
     292             :                                           const nsIID& aIID,
     293             :                                           bool aIsStrongRef)
     294             : {
     295          10 :   nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aObject);
     296          10 :   nsCOMPtr<nsISerializable> serializable = do_QueryInterface(aObject);
     297             : 
     298             :   // Can't deal with weak refs
     299           5 :   if (NS_WARN_IF(!aIsStrongRef)) {
     300           0 :     return NS_ERROR_UNEXPECTED;
     301             :   }
     302           5 :   if (NS_WARN_IF(!classInfo) || NS_WARN_IF(!serializable)) {
     303           0 :     return NS_ERROR_NOT_AVAILABLE;
     304             :   }
     305             : 
     306             :   nsCID cid;
     307           5 :   nsresult rv = classInfo->GetClassIDNoAlloc(&cid);
     308           5 :   if (NS_SUCCEEDED(rv)) {
     309           5 :     rv = WriteID(cid);
     310             :   } else {
     311           0 :     nsCID* cidptr = nullptr;
     312           0 :     rv = classInfo->GetClassID(&cidptr);
     313           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     314           0 :       return rv;
     315             :     }
     316             : 
     317           0 :     rv = WriteID(*cidptr);
     318             : 
     319           0 :     free(cidptr);
     320             :   }
     321             : 
     322           5 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     323           0 :     return rv;
     324             :   }
     325             : 
     326           5 :   rv = WriteID(aIID);
     327           5 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     328           0 :     return rv;
     329             :   }
     330             : 
     331           5 :   return serializable->Write(this);
     332             : }
     333             : 
     334             : NS_IMETHODIMP
     335          10 : nsBinaryOutputStream::WriteID(const nsIID& aIID)
     336             : {
     337          10 :   nsresult rv = Write32(aIID.m0);
     338          10 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     339           0 :     return rv;
     340             :   }
     341             : 
     342          10 :   rv = Write16(aIID.m1);
     343          10 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     344           0 :     return rv;
     345             :   }
     346             : 
     347          10 :   rv = Write16(aIID.m2);
     348          10 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     349           0 :     return rv;
     350             :   }
     351             : 
     352          90 :   for (int i = 0; i < 8; ++i) {
     353          80 :     rv = Write8(aIID.m3[i]);
     354          80 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     355           0 :       return rv;
     356             :     }
     357             :   }
     358             : 
     359          10 :   return NS_OK;
     360             : }
     361             : 
     362             : NS_IMETHODIMP_(char*)
     363           0 : nsBinaryOutputStream::GetBuffer(uint32_t aLength, uint32_t aAlignMask)
     364             : {
     365           0 :   if (mBufferAccess) {
     366           0 :     return mBufferAccess->GetBuffer(aLength, aAlignMask);
     367             :   }
     368           0 :   return nullptr;
     369             : }
     370             : 
     371             : NS_IMETHODIMP_(void)
     372           0 : nsBinaryOutputStream::PutBuffer(char* aBuffer, uint32_t aLength)
     373             : {
     374           0 :   if (mBufferAccess) {
     375           0 :     mBufferAccess->PutBuffer(aBuffer, aLength);
     376             :   }
     377           0 : }
     378             : 
     379       62594 : NS_IMPL_ISUPPORTS(nsBinaryInputStream,
     380             :                   nsIObjectInputStream,
     381             :                   nsIBinaryInputStream,
     382             :                   nsIInputStream)
     383             : 
     384             : NS_IMETHODIMP
     385           0 : nsBinaryInputStream::Available(uint64_t* aResult)
     386             : {
     387           0 :   if (NS_WARN_IF(!mInputStream)) {
     388           0 :     return NS_ERROR_UNEXPECTED;
     389             :   }
     390           0 :   return mInputStream->Available(aResult);
     391             : }
     392             : 
     393             : NS_IMETHODIMP
     394       39750 : nsBinaryInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aNumRead)
     395             : {
     396       39750 :   if (NS_WARN_IF(!mInputStream)) {
     397           0 :     return NS_ERROR_UNEXPECTED;
     398             :   }
     399             : 
     400             :   // mInputStream might give us short reads, so deal with that.
     401       39750 :   uint32_t totalRead = 0;
     402             : 
     403             :   uint32_t bytesRead;
     404           0 :   do {
     405       39750 :     nsresult rv = mInputStream->Read(aBuffer, aCount, &bytesRead);
     406       39750 :     if (rv == NS_BASE_STREAM_WOULD_BLOCK && totalRead != 0) {
     407             :       // We already read some data.  Return it.
     408           0 :       break;
     409             :     }
     410             : 
     411       39750 :     if (NS_FAILED(rv)) {
     412           0 :       return rv;
     413             :     }
     414             : 
     415       39750 :     totalRead += bytesRead;
     416       39750 :     aBuffer += bytesRead;
     417       39750 :     aCount -= bytesRead;
     418       39750 :   } while (aCount != 0 && bytesRead != 0);
     419             : 
     420       39750 :   *aNumRead = totalRead;
     421             : 
     422       39750 :   return NS_OK;
     423             : }
     424             : 
     425             : 
     426             : // when forwarding ReadSegments to mInputStream, we need to make sure
     427             : // 'this' is being passed to the writer each time. To do this, we need
     428             : // a thunking function which keeps the real input stream around.
     429             : 
     430             : // the closure wrapper
     431       12246 : struct MOZ_STACK_CLASS ReadSegmentsClosure
     432             : {
     433             :   nsCOMPtr<nsIInputStream> mRealInputStream;
     434             :   void* mRealClosure;
     435             :   nsWriteSegmentFun mRealWriter;
     436             :   nsresult mRealResult;
     437             :   uint32_t mBytesRead;  // to properly implement aToOffset
     438             : };
     439             : 
     440             : // the thunking function
     441             : static nsresult
     442       12246 : ReadSegmentForwardingThunk(nsIInputStream* aStream,
     443             :                            void* aClosure,
     444             :                            const char* aFromSegment,
     445             :                            uint32_t aToOffset,
     446             :                            uint32_t aCount,
     447             :                            uint32_t* aWriteCount)
     448             : {
     449             :   ReadSegmentsClosure* thunkClosure =
     450       12246 :     reinterpret_cast<ReadSegmentsClosure*>(aClosure);
     451             : 
     452       12246 :   NS_ASSERTION(NS_SUCCEEDED(thunkClosure->mRealResult),
     453             :                "How did this get to be a failure status?");
     454             : 
     455       12246 :   thunkClosure->mRealResult =
     456       24492 :     thunkClosure->mRealWriter(thunkClosure->mRealInputStream,
     457             :                               thunkClosure->mRealClosure,
     458             :                               aFromSegment,
     459       12246 :                               thunkClosure->mBytesRead + aToOffset,
     460             :                               aCount, aWriteCount);
     461             : 
     462       12246 :   return thunkClosure->mRealResult;
     463             : }
     464             : 
     465             : 
     466             : NS_IMETHODIMP
     467       12246 : nsBinaryInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
     468             :                                   uint32_t aCount, uint32_t* aResult)
     469             : {
     470       12246 :   if (NS_WARN_IF(!mInputStream)) {
     471           0 :     return NS_ERROR_UNEXPECTED;
     472             :   }
     473             : 
     474       24492 :   ReadSegmentsClosure thunkClosure = { this, aClosure, aWriter, NS_OK, 0 };
     475             : 
     476             :   // mInputStream might give us short reads, so deal with that.
     477             :   uint32_t bytesRead;
     478       12246 :   do {
     479       12246 :     nsresult rv = mInputStream->ReadSegments(ReadSegmentForwardingThunk,
     480             :                                              &thunkClosure,
     481       12246 :                                              aCount, &bytesRead);
     482             : 
     483       12246 :     if (rv == NS_BASE_STREAM_WOULD_BLOCK && thunkClosure.mBytesRead != 0) {
     484             :       // We already read some data.  Return it.
     485           0 :       break;
     486             :     }
     487             : 
     488       12246 :     if (NS_FAILED(rv)) {
     489           0 :       return rv;
     490             :     }
     491             : 
     492       12246 :     thunkClosure.mBytesRead += bytesRead;
     493       12246 :     aCount -= bytesRead;
     494       12246 :   } while (aCount != 0 && bytesRead != 0 &&
     495           0 :            NS_SUCCEEDED(thunkClosure.mRealResult));
     496             : 
     497       12246 :   *aResult = thunkClosure.mBytesRead;
     498             : 
     499       12246 :   return NS_OK;
     500             : }
     501             : 
     502             : NS_IMETHODIMP
     503           0 : nsBinaryInputStream::IsNonBlocking(bool* aNonBlocking)
     504             : {
     505           0 :   if (NS_WARN_IF(!mInputStream)) {
     506           0 :     return NS_ERROR_UNEXPECTED;
     507             :   }
     508           0 :   return mInputStream->IsNonBlocking(aNonBlocking);
     509             : }
     510             : 
     511             : NS_IMETHODIMP
     512           0 : nsBinaryInputStream::Close()
     513             : {
     514           0 :   if (NS_WARN_IF(!mInputStream)) {
     515           0 :     return NS_ERROR_UNEXPECTED;
     516             :   }
     517           0 :   return mInputStream->Close();
     518             : }
     519             : 
     520             : NS_IMETHODIMP
     521          76 : nsBinaryInputStream::SetInputStream(nsIInputStream* aInputStream)
     522             : {
     523          76 :   if (NS_WARN_IF(!aInputStream)) {
     524           0 :     return NS_ERROR_INVALID_ARG;
     525             :   }
     526          76 :   mInputStream = aInputStream;
     527          76 :   mBufferAccess = do_QueryInterface(aInputStream);
     528          76 :   return NS_OK;
     529             : }
     530             : 
     531             : NS_IMETHODIMP
     532         617 : nsBinaryInputStream::ReadBoolean(bool* aBoolean)
     533             : {
     534             :   uint8_t byteResult;
     535         617 :   nsresult rv = Read8(&byteResult);
     536         617 :   if (NS_FAILED(rv)) {
     537           0 :     return rv;
     538             :   }
     539         617 :   *aBoolean = !!byteResult;
     540         617 :   return rv;
     541             : }
     542             : 
     543             : NS_IMETHODIMP
     544       10050 : nsBinaryInputStream::Read8(uint8_t* aByte)
     545             : {
     546             :   nsresult rv;
     547             :   uint32_t bytesRead;
     548             : 
     549       10050 :   rv = Read(reinterpret_cast<char*>(aByte), sizeof(*aByte), &bytesRead);
     550       10050 :   if (NS_FAILED(rv)) {
     551           0 :     return rv;
     552             :   }
     553       10050 :   if (bytesRead != 1) {
     554           0 :     return NS_ERROR_FAILURE;
     555             :   }
     556       10050 :   return rv;
     557             : }
     558             : 
     559             : NS_IMETHODIMP
     560         334 : nsBinaryInputStream::Read16(uint16_t* aNum)
     561             : {
     562             :   uint32_t bytesRead;
     563         334 :   nsresult rv = Read(reinterpret_cast<char*>(aNum), sizeof(*aNum), &bytesRead);
     564         334 :   if (NS_FAILED(rv)) {
     565           0 :     return rv;
     566             :   }
     567         334 :   if (bytesRead != sizeof(*aNum)) {
     568           0 :     return NS_ERROR_FAILURE;
     569             :   }
     570         334 :   *aNum = mozilla::NativeEndian::swapFromBigEndian(*aNum);
     571         334 :   return rv;
     572             : }
     573             : 
     574             : NS_IMETHODIMP
     575       28237 : nsBinaryInputStream::Read32(uint32_t* aNum)
     576             : {
     577             :   uint32_t bytesRead;
     578       28237 :   nsresult rv = Read(reinterpret_cast<char*>(aNum), sizeof(*aNum), &bytesRead);
     579       28237 :   if (NS_FAILED(rv)) {
     580           0 :     return rv;
     581             :   }
     582       28237 :   if (bytesRead != sizeof(*aNum)) {
     583           0 :     return NS_ERROR_FAILURE;
     584             :   }
     585       28237 :   *aNum = mozilla::NativeEndian::swapFromBigEndian(*aNum);
     586       28237 :   return rv;
     587             : }
     588             : 
     589             : NS_IMETHODIMP
     590           0 : nsBinaryInputStream::Read64(uint64_t* aNum)
     591             : {
     592             :   uint32_t bytesRead;
     593           0 :   nsresult rv = Read(reinterpret_cast<char*>(aNum), sizeof(*aNum), &bytesRead);
     594           0 :   if (NS_FAILED(rv)) {
     595           0 :     return rv;
     596             :   }
     597           0 :   if (bytesRead != sizeof(*aNum)) {
     598           0 :     return NS_ERROR_FAILURE;
     599             :   }
     600           0 :   *aNum = mozilla::NativeEndian::swapFromBigEndian(*aNum);
     601           0 :   return rv;
     602             : }
     603             : 
     604             : NS_IMETHODIMP
     605           0 : nsBinaryInputStream::ReadFloat(float* aFloat)
     606             : {
     607             :   NS_ASSERTION(sizeof(float) == sizeof(uint32_t),
     608             :                "False assumption about sizeof(float)");
     609           0 :   return Read32(reinterpret_cast<uint32_t*>(aFloat));
     610             : }
     611             : 
     612             : NS_IMETHODIMP
     613           0 : nsBinaryInputStream::ReadDouble(double* aDouble)
     614             : {
     615             :   NS_ASSERTION(sizeof(double) == sizeof(uint64_t),
     616             :                "False assumption about sizeof(double)");
     617           0 :   return Read64(reinterpret_cast<uint64_t*>(aDouble));
     618             : }
     619             : 
     620             : static nsresult
     621         529 : WriteSegmentToCString(nsIInputStream* aStream,
     622             :                       void* aClosure,
     623             :                       const char* aFromSegment,
     624             :                       uint32_t aToOffset,
     625             :                       uint32_t aCount,
     626             :                       uint32_t* aWriteCount)
     627             : {
     628         529 :   nsACString* outString = static_cast<nsACString*>(aClosure);
     629             : 
     630         529 :   outString->Append(aFromSegment, aCount);
     631             : 
     632         529 :   *aWriteCount = aCount;
     633             : 
     634         529 :   return NS_OK;
     635             : }
     636             : 
     637             : NS_IMETHODIMP
     638         529 : nsBinaryInputStream::ReadCString(nsACString& aString)
     639             : {
     640             :   nsresult rv;
     641             :   uint32_t length, bytesRead;
     642             : 
     643         529 :   rv = Read32(&length);
     644         529 :   if (NS_FAILED(rv)) {
     645           0 :     return rv;
     646             :   }
     647             : 
     648         529 :   aString.Truncate();
     649         529 :   rv = ReadSegments(WriteSegmentToCString, &aString, length, &bytesRead);
     650         529 :   if (NS_FAILED(rv)) {
     651           0 :     return rv;
     652             :   }
     653             : 
     654         529 :   if (bytesRead != length) {
     655           0 :     return NS_ERROR_FAILURE;
     656             :   }
     657             : 
     658         529 :   return NS_OK;
     659             : }
     660             : 
     661             : 
     662             : // sometimes, WriteSegmentToString will be handed an odd-number of
     663             : // bytes, which means we only have half of the last char16_t
     664             : struct WriteStringClosure
     665             : {
     666             :   char16_t* mWriteCursor;
     667             :   bool mHasCarryoverByte;
     668             :   char mCarryoverByte;
     669             : };
     670             : 
     671             : // there are a few cases we have to account for here:
     672             : // * even length buffer, no carryover - easy, just append
     673             : // * odd length buffer, no carryover - the last byte needs to be saved
     674             : //                                     for carryover
     675             : // * odd length buffer, with carryover - first byte needs to be used
     676             : //                              with the carryover byte, and
     677             : //                              the rest of the even length
     678             : //                              buffer is appended as normal
     679             : // * even length buffer, with carryover - the first byte needs to be
     680             : //                              used with the previous carryover byte.
     681             : //                              this gives you an odd length buffer,
     682             : //                              so you have to save the last byte for
     683             : //                              the next carryover
     684             : 
     685             : 
     686             : // same version of the above, but with correct casting and endian swapping
     687             : static nsresult
     688       11717 : WriteSegmentToString(nsIInputStream* aStream,
     689             :                      void* aClosure,
     690             :                      const char* aFromSegment,
     691             :                      uint32_t aToOffset,
     692             :                      uint32_t aCount,
     693             :                      uint32_t* aWriteCount)
     694             : {
     695       11717 :   NS_PRECONDITION(aCount > 0, "Why are we being told to write 0 bytes?");
     696             :   NS_PRECONDITION(sizeof(char16_t) == 2, "We can't handle other sizes!");
     697             : 
     698       11717 :   WriteStringClosure* closure = static_cast<WriteStringClosure*>(aClosure);
     699       11717 :   char16_t* cursor = closure->mWriteCursor;
     700             : 
     701             :   // we're always going to consume the whole buffer no matter what
     702             :   // happens, so take care of that right now.. that allows us to
     703             :   // tweak aCount later. Do NOT move this!
     704       11717 :   *aWriteCount = aCount;
     705             : 
     706             :   // if the last Write had an odd-number of bytes read, then
     707       11717 :   if (closure->mHasCarryoverByte) {
     708             :     // re-create the two-byte sequence we want to work with
     709           0 :     char bytes[2] = { closure->mCarryoverByte, *aFromSegment };
     710           0 :     *cursor = *(char16_t*)bytes;
     711             :     // Now the little endianness dance
     712           0 :     mozilla::NativeEndian::swapToBigEndianInPlace(cursor, 1);
     713           0 :     ++cursor;
     714             : 
     715             :     // now skip past the first byte of the buffer.. code from here
     716             :     // can assume normal operations, but should not assume aCount
     717             :     // is relative to the ORIGINAL buffer
     718           0 :     ++aFromSegment;
     719           0 :     --aCount;
     720             : 
     721           0 :     closure->mHasCarryoverByte = false;
     722             :   }
     723             : 
     724             :   // this array is possibly unaligned... be careful how we access it!
     725             :   const char16_t* unicodeSegment =
     726       11717 :     reinterpret_cast<const char16_t*>(aFromSegment);
     727             : 
     728             :   // calculate number of full characters in segment (aCount could be odd!)
     729       11717 :   uint32_t segmentLength = aCount / sizeof(char16_t);
     730             : 
     731             :   // copy all data into our aligned buffer.  byte swap if necessary.
     732             :   // cursor may be unaligned, so we cannot use copyAndSwapToBigEndian directly
     733       11717 :   memcpy(cursor, unicodeSegment, segmentLength * sizeof(char16_t));
     734       11717 :   char16_t* end = cursor + segmentLength;
     735       11717 :   mozilla::NativeEndian::swapToBigEndianInPlace(cursor, segmentLength);
     736       11717 :   closure->mWriteCursor = end;
     737             : 
     738             :   // remember this is the modifed aCount and aFromSegment,
     739             :   // so that will take into account the fact that we might have
     740             :   // skipped the first byte in the buffer
     741       11717 :   if (aCount % sizeof(char16_t) != 0) {
     742             :     // we must have had a carryover byte, that we'll need the next
     743             :     // time around
     744           0 :     closure->mCarryoverByte = aFromSegment[aCount - 1];
     745           0 :     closure->mHasCarryoverByte = true;
     746             :   }
     747             : 
     748       11717 :   return NS_OK;
     749             : }
     750             : 
     751             : 
     752             : NS_IMETHODIMP
     753       13315 : nsBinaryInputStream::ReadString(nsAString& aString)
     754             : {
     755             :   nsresult rv;
     756             :   uint32_t length, bytesRead;
     757             : 
     758       13315 :   rv = Read32(&length);
     759       13315 :   if (NS_FAILED(rv)) {
     760           0 :     return rv;
     761             :   }
     762             : 
     763       13315 :   if (length == 0) {
     764        1598 :     aString.Truncate();
     765        1598 :     return NS_OK;
     766             :   }
     767             : 
     768             :   // pre-allocate output buffer, and get direct access to buffer...
     769       11717 :   if (!aString.SetLength(length, mozilla::fallible)) {
     770           0 :     return NS_ERROR_OUT_OF_MEMORY;
     771             :   }
     772             : 
     773       11717 :   nsAString::iterator start;
     774       11717 :   aString.BeginWriting(start);
     775             : 
     776             :   WriteStringClosure closure;
     777       11717 :   closure.mWriteCursor = start.get();
     778       11717 :   closure.mHasCarryoverByte = false;
     779             : 
     780       11717 :   rv = ReadSegments(WriteSegmentToString, &closure,
     781       11717 :                     length * sizeof(char16_t), &bytesRead);
     782       11717 :   if (NS_FAILED(rv)) {
     783           0 :     return rv;
     784             :   }
     785             : 
     786       11717 :   NS_ASSERTION(!closure.mHasCarryoverByte, "some strange stream corruption!");
     787             : 
     788       11717 :   if (bytesRead != length * sizeof(char16_t)) {
     789           0 :     return NS_ERROR_FAILURE;
     790             :   }
     791             : 
     792       11717 :   return NS_OK;
     793             : }
     794             : 
     795             : NS_IMETHODIMP
     796        1129 : nsBinaryInputStream::ReadBytes(uint32_t aLength, char** aResult)
     797             : {
     798             :   nsresult rv;
     799             :   uint32_t bytesRead;
     800             :   char* s;
     801             : 
     802        1129 :   s = reinterpret_cast<char*>(malloc(aLength));
     803        1129 :   if (!s) {
     804           0 :     return NS_ERROR_OUT_OF_MEMORY;
     805             :   }
     806             : 
     807        1129 :   rv = Read(s, aLength, &bytesRead);
     808        1129 :   if (NS_FAILED(rv)) {
     809           0 :     free(s);
     810           0 :     return rv;
     811             :   }
     812        1129 :   if (bytesRead != aLength) {
     813           0 :     free(s);
     814           0 :     return NS_ERROR_FAILURE;
     815             :   }
     816             : 
     817        1129 :   *aResult = s;
     818        1129 :   return NS_OK;
     819             : }
     820             : 
     821             : NS_IMETHODIMP
     822           0 : nsBinaryInputStream::ReadByteArray(uint32_t aLength, uint8_t** aResult)
     823             : {
     824           0 :   return ReadBytes(aLength, reinterpret_cast<char**>(aResult));
     825             : }
     826             : 
     827             : NS_IMETHODIMP
     828           0 : nsBinaryInputStream::ReadArrayBuffer(uint32_t aLength,
     829             :                                      JS::Handle<JS::Value> aBuffer,
     830             :                                      JSContext* aCx, uint32_t* aReadLength)
     831             : {
     832           0 :   if (!aBuffer.isObject()) {
     833           0 :     return NS_ERROR_FAILURE;
     834             :   }
     835           0 :   JS::RootedObject buffer(aCx, &aBuffer.toObject());
     836           0 :   if (!JS_IsArrayBufferObject(buffer)) {
     837           0 :     return NS_ERROR_FAILURE;
     838             :   }
     839             : 
     840           0 :   uint32_t bufferLength = JS_GetArrayBufferByteLength(buffer);
     841           0 :   if (bufferLength < aLength) {
     842           0 :     return NS_ERROR_FAILURE;
     843             :   }
     844             : 
     845           0 :   uint32_t bufSize = std::min<uint32_t>(aLength, 4096);
     846           0 :   UniquePtr<char[]> buf = MakeUnique<char[]>(bufSize);
     847             : 
     848           0 :   uint32_t pos = 0;
     849           0 :   *aReadLength = 0;
     850           0 :   do {
     851             :     // Read data into temporary buffer.
     852             :     uint32_t bytesRead;
     853           0 :     uint32_t amount = std::min(aLength - pos, bufSize);
     854           0 :     nsresult rv = Read(buf.get(), amount, &bytesRead);
     855           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     856           0 :       return rv;
     857             :     }
     858           0 :     MOZ_ASSERT(bytesRead <= amount);
     859             : 
     860           0 :     if (bytesRead == 0) {
     861           0 :       break;
     862             :     }
     863             : 
     864             :     // Copy data into actual buffer.
     865             : 
     866           0 :     JS::AutoCheckCannotGC nogc;
     867             :     bool isShared;
     868           0 :     if (bufferLength != JS_GetArrayBufferByteLength(buffer)) {
     869           0 :       return NS_ERROR_FAILURE;
     870             :     }
     871             : 
     872           0 :     char* data = reinterpret_cast<char*>(JS_GetArrayBufferData(buffer, &isShared, nogc));
     873           0 :     MOZ_ASSERT(!isShared);      // Implied by JS_GetArrayBufferData()
     874           0 :     if (!data) {
     875           0 :       return NS_ERROR_FAILURE;
     876             :     }
     877             : 
     878           0 :     *aReadLength += bytesRead;
     879           0 :     PodCopy(data + pos, buf.get(), bytesRead);
     880             : 
     881           0 :     pos += bytesRead;
     882           0 :   } while (pos < aLength);
     883             : 
     884           0 :   return NS_OK;
     885             : }
     886             : 
     887             : NS_IMETHODIMP
     888          53 : nsBinaryInputStream::ReadObject(bool aIsStrongRef, nsISupports** aObject)
     889             : {
     890             :   nsCID cid;
     891             :   nsIID iid;
     892          53 :   nsresult rv = ReadID(&cid);
     893          53 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     894           0 :     return rv;
     895             :   }
     896             : 
     897          53 :   rv = ReadID(&iid);
     898          53 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     899           0 :     return rv;
     900             :   }
     901             : 
     902             :   // HACK: Intercept old (pre-gecko6) nsIURI IID, and replace with
     903             :   // the updated IID, so that we're QI'ing to an actual interface.
     904             :   // (As soon as we drop support for upgrading from pre-gecko6, we can
     905             :   // remove this chunk.)
     906             :   static const nsIID oldURIiid = {
     907             :     0x7a22cc0, 0xce5, 0x11d3,
     908             :     { 0x93, 0x31, 0x0, 0x10, 0x4b, 0xa0, 0xfd, 0x40 }
     909             :   };
     910             : 
     911             :   // hackaround for bug 670542
     912             :   static const nsIID oldURIiid2 = {
     913             :     0xd6d04c36, 0x0fa4, 0x4db3,
     914             :     { 0xbe, 0x05, 0x4a, 0x18, 0x39, 0x71, 0x03, 0xe2 }
     915             :   };
     916             : 
     917             :   // hackaround for bug 682031
     918             :   static const nsIID oldURIiid3 = {
     919             :     0x12120b20, 0x0929, 0x40e9,
     920             :     { 0x88, 0xcf, 0x6e, 0x08, 0x76, 0x6e, 0x8b, 0x23 }
     921             :   };
     922             : 
     923             :   // hackaround for bug 1195415
     924             :   static const nsIID oldURIiid4 = {
     925             :     0x395fe045, 0x7d18, 0x4adb,
     926             :     { 0xa3, 0xfd, 0xaf, 0x98, 0xc8, 0xa1, 0xaf, 0x11 }
     927             :   };
     928             : 
     929         159 :   if (iid.Equals(oldURIiid) ||
     930         106 :       iid.Equals(oldURIiid2) ||
     931         159 :       iid.Equals(oldURIiid3) ||
     932          53 :       iid.Equals(oldURIiid4)) {
     933           0 :     const nsIID newURIiid = NS_IURI_IID;
     934           0 :     iid = newURIiid;
     935             :   }
     936             :   // END HACK
     937             : 
     938             :   // HACK:  Service workers store resource security info on disk in the dom
     939             :   //        Cache API.  When the uuid of the nsIX509Cert interface changes
     940             :   //        these serialized objects cannot be loaded any more.  This hack
     941             :   //        works around this issue.
     942             : 
     943             :   // hackaround for bug 1247580 (FF45 to FF46 transition)
     944             :   static const nsIID oldCertIID = {
     945             :     0xf8ed8364, 0xced9, 0x4c6e,
     946             :     { 0x86, 0xba, 0x48, 0xaf, 0x53, 0xc3, 0x93, 0xe6 }
     947             :   };
     948             : 
     949          53 :   if (iid.Equals(oldCertIID)) {
     950           0 :     const nsIID newCertIID = NS_IX509CERT_IID;
     951           0 :     iid = newCertIID;
     952             :   }
     953             :   // END HACK
     954             : 
     955         106 :   nsCOMPtr<nsISupports> object = do_CreateInstance(cid, &rv);
     956          53 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     957           0 :     return rv;
     958             :   }
     959             : 
     960         106 :   nsCOMPtr<nsISerializable> serializable = do_QueryInterface(object);
     961          53 :   if (NS_WARN_IF(!serializable)) {
     962           0 :     return NS_ERROR_UNEXPECTED;
     963             :   }
     964             : 
     965          53 :   rv = serializable->Read(this);
     966          53 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     967           0 :     return rv;
     968             :   }
     969             : 
     970          53 :   return object->QueryInterface(iid, reinterpret_cast<void**>(aObject));
     971             : }
     972             : 
     973             : NS_IMETHODIMP
     974         167 : nsBinaryInputStream::ReadID(nsID* aResult)
     975             : {
     976         167 :   nsresult rv = Read32(&aResult->m0);
     977         167 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     978           0 :     return rv;
     979             :   }
     980             : 
     981         167 :   rv = Read16(&aResult->m1);
     982         167 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     983           0 :     return rv;
     984             :   }
     985             : 
     986         167 :   rv = Read16(&aResult->m2);
     987         167 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     988           0 :     return rv;
     989             :   }
     990             : 
     991        1503 :   for (int i = 0; i < 8; ++i) {
     992        1336 :     rv = Read8(&aResult->m3[i]);
     993        1336 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     994           0 :       return rv;
     995             :     }
     996             :   }
     997             : 
     998         167 :   return NS_OK;
     999             : }
    1000             : 
    1001             : NS_IMETHODIMP_(char*)
    1002           0 : nsBinaryInputStream::GetBuffer(uint32_t aLength, uint32_t aAlignMask)
    1003             : {
    1004           0 :   if (mBufferAccess) {
    1005           0 :     return mBufferAccess->GetBuffer(aLength, aAlignMask);
    1006             :   }
    1007           0 :   return nullptr;
    1008             : }
    1009             : 
    1010             : NS_IMETHODIMP_(void)
    1011           0 : nsBinaryInputStream::PutBuffer(char* aBuffer, uint32_t aLength)
    1012             : {
    1013           0 :   if (mBufferAccess) {
    1014           0 :     mBufferAccess->PutBuffer(aBuffer, aLength);
    1015             :   }
    1016           0 : }

Generated by: LCOV version 1.13