LCOV - code coverage report
Current view: top level - intl/uconv - nsConverterInputStream.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 55 114 48.2 %
Date: 2017-07-14 16:53:18 Functions: 7 10 70.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       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/. */
       5             : 
       6             : #include "nsConverterInputStream.h"
       7             : #include "nsIInputStream.h"
       8             : #include "nsReadLine.h"
       9             : #include "nsStreamUtils.h"
      10             : #include <algorithm>
      11             : #include "mozilla/Unused.h"
      12             : 
      13             : using namespace mozilla;
      14             : 
      15             : #define CONVERTER_BUFFER_SIZE 8192
      16             : 
      17          51 : NS_IMPL_ISUPPORTS(nsConverterInputStream, nsIConverterInputStream,
      18             :                   nsIUnicharInputStream, nsIUnicharLineInputStream)
      19             : 
      20             : 
      21             : NS_IMETHODIMP
      22           3 : nsConverterInputStream::Init(nsIInputStream* aStream,
      23             :                              const char *aCharset,
      24             :                              int32_t aBufferSize,
      25             :                              char16_t aReplacementChar)
      26             : {
      27           6 :     nsAutoCString label;
      28           3 :     if (!aCharset) {
      29           0 :         label.AssignLiteral("UTF-8");
      30             :     } else {
      31           3 :         label = aCharset;
      32             :     }
      33             : 
      34           3 :     auto encoding = Encoding::ForLabelNoReplacement(label);
      35           3 :     if (!encoding) {
      36           0 :       return NS_ERROR_UCONV_NOCONV;
      37             :     }
      38             :     // Previously, the implementation auto-switched only
      39             :     // between the two UTF-16 variants and only when
      40             :     // initialized with an endianness-unspecific label.
      41           3 :     mConverter = encoding->NewDecoder();
      42             : 
      43             :     size_t outputBufferSize;
      44           3 :     if (aBufferSize <= 0) {
      45           0 :       aBufferSize = CONVERTER_BUFFER_SIZE;
      46           0 :       outputBufferSize = CONVERTER_BUFFER_SIZE;
      47             :     } else {
      48             :       // NetUtil.jsm assumes that if buffer size equals
      49             :       // the input size, the whole stream will be processed
      50             :       // as one readString. This is not true with encoding_rs,
      51             :       // because encoding_rs might want to see space for a
      52             :       // surrogate pair, so let's compute a larger output
      53             :       // buffer length.
      54           3 :       CheckedInt<size_t> needed = mConverter->MaxUTF16BufferLength(aBufferSize);
      55           3 :       if (!needed.isValid()) {
      56           0 :         return NS_ERROR_OUT_OF_MEMORY;
      57             :       }
      58           3 :       outputBufferSize = needed.value();
      59             :     }
      60             : 
      61             :     // set up our buffers.
      62           6 :     if (!mByteData.SetCapacity(aBufferSize, mozilla::fallible) ||
      63           3 :         !mUnicharData.SetLength(outputBufferSize, mozilla::fallible)) {
      64           0 :       return NS_ERROR_OUT_OF_MEMORY;
      65             :     }
      66             : 
      67           3 :     mInput = aStream;
      68           3 :     mErrorsAreFatal = !aReplacementChar;
      69           3 :     return NS_OK;
      70             : }
      71             : 
      72             : NS_IMETHODIMP
      73           3 : nsConverterInputStream::Close()
      74             : {
      75           3 :     nsresult rv = mInput ? mInput->Close() : NS_OK;
      76           3 :     mLineBuffer = nullptr;
      77           3 :     mInput = nullptr;
      78           3 :     mConverter = nullptr;
      79           3 :     mByteData.Clear();
      80           3 :     mUnicharData.Clear();
      81           3 :     return rv;
      82             : }
      83             : 
      84             : NS_IMETHODIMP
      85           0 : nsConverterInputStream::Read(char16_t* aBuf,
      86             :                              uint32_t aCount,
      87             :                              uint32_t *aReadCount)
      88             : {
      89           0 :   NS_ASSERTION(mUnicharDataLength >= mUnicharDataOffset, "unsigned madness");
      90           0 :   uint32_t readCount = mUnicharDataLength - mUnicharDataOffset;
      91           0 :   if (0 == readCount) {
      92             :     // Fill the unichar buffer
      93           0 :     readCount = Fill(&mLastErrorCode);
      94           0 :     if (readCount == 0) {
      95           0 :       *aReadCount = 0;
      96           0 :       return mLastErrorCode;
      97             :     }
      98             :   }
      99           0 :   if (readCount > aCount) {
     100           0 :     readCount = aCount;
     101             :   }
     102           0 :   memcpy(aBuf, mUnicharData.Elements() + mUnicharDataOffset,
     103           0 :          readCount * sizeof(char16_t));
     104           0 :   mUnicharDataOffset += readCount;
     105           0 :   *aReadCount = readCount;
     106           0 :   return NS_OK;
     107             : }
     108             : 
     109             : NS_IMETHODIMP
     110           0 : nsConverterInputStream::ReadSegments(nsWriteUnicharSegmentFun aWriter,
     111             :                                      void* aClosure,
     112             :                                      uint32_t aCount, uint32_t *aReadCount)
     113             : {
     114           0 :   NS_ASSERTION(mUnicharDataLength >= mUnicharDataOffset, "unsigned madness");
     115           0 :   uint32_t bytesToWrite = mUnicharDataLength - mUnicharDataOffset;
     116             :   nsresult rv;
     117           0 :   if (0 == bytesToWrite) {
     118             :     // Fill the unichar buffer
     119           0 :     bytesToWrite = Fill(&rv);
     120           0 :     if (bytesToWrite <= 0) {
     121           0 :       *aReadCount = 0;
     122           0 :       return rv;
     123             :     }
     124             :   }
     125             : 
     126           0 :   if (bytesToWrite > aCount)
     127           0 :     bytesToWrite = aCount;
     128             : 
     129             :   uint32_t bytesWritten;
     130           0 :   uint32_t totalBytesWritten = 0;
     131             : 
     132           0 :   while (bytesToWrite) {
     133           0 :     rv = aWriter(this, aClosure,
     134           0 :                  mUnicharData.Elements() + mUnicharDataOffset,
     135             :                  totalBytesWritten, bytesToWrite, &bytesWritten);
     136           0 :     if (NS_FAILED(rv)) {
     137             :       // don't propagate errors to the caller
     138           0 :       break;
     139             :     }
     140             : 
     141           0 :     bytesToWrite -= bytesWritten;
     142           0 :     totalBytesWritten += bytesWritten;
     143           0 :     mUnicharDataOffset += bytesWritten;
     144             :   }
     145             : 
     146           0 :   *aReadCount = totalBytesWritten;
     147             : 
     148           0 :   return NS_OK;
     149             : }
     150             : 
     151             : NS_IMETHODIMP
     152           3 : nsConverterInputStream::ReadString(uint32_t aCount, nsAString& aString,
     153             :                                    uint32_t* aReadCount)
     154             : {
     155           3 :   NS_ASSERTION(mUnicharDataLength >= mUnicharDataOffset, "unsigned madness");
     156           3 :   uint32_t readCount = mUnicharDataLength - mUnicharDataOffset;
     157           3 :   if (0 == readCount) {
     158             :     // Fill the unichar buffer
     159           3 :     readCount = Fill(&mLastErrorCode);
     160           3 :     if (readCount == 0) {
     161           0 :       *aReadCount = 0;
     162           0 :       return mLastErrorCode;
     163             :     }
     164             :   }
     165           3 :   if (readCount > aCount) {
     166           0 :     readCount = aCount;
     167             :   }
     168           3 :   const char16_t* buf = mUnicharData.Elements() + mUnicharDataOffset;
     169           3 :   aString.Assign(buf, readCount);
     170           3 :   mUnicharDataOffset += readCount;
     171           3 :   *aReadCount = readCount;
     172           3 :   return NS_OK;
     173             : }
     174             : 
     175             : uint32_t
     176           3 : nsConverterInputStream::Fill(nsresult * aErrorCode)
     177             : {
     178           3 :   if (nullptr == mInput) {
     179             :     // We already closed the stream!
     180           0 :     *aErrorCode = NS_BASE_STREAM_CLOSED;
     181           0 :     return 0;
     182             :   }
     183             : 
     184           3 :   if (NS_FAILED(mLastErrorCode)) {
     185             :     // We failed to completely convert last time, and error-recovery
     186             :     // is disabled.  We will fare no better this time, so...
     187           0 :     *aErrorCode = mLastErrorCode;
     188           0 :     return 0;
     189             :   }
     190             : 
     191             :   // We assume a many to one conversion and are using equal sizes for
     192             :   // the two buffers.  However if an error happens at the very start
     193             :   // of a byte buffer we may end up in a situation where n bytes lead
     194             :   // to n+1 unicode chars.  Thus we need to keep track of the leftover
     195             :   // bytes as we convert.
     196             : 
     197             :   uint32_t nb;
     198           3 :   *aErrorCode = NS_FillArray(mByteData, mInput, mLeftOverBytes, &nb);
     199           3 :   if (nb == 0 && mLeftOverBytes == 0) {
     200             :     // No more data
     201           0 :     *aErrorCode = NS_OK;
     202           0 :     return 0;
     203             :   }
     204             : 
     205           3 :   NS_ASSERTION(uint32_t(nb) + mLeftOverBytes == mByteData.Length(),
     206             :                "mByteData is lying to us somewhere");
     207             : 
     208             :   // Now convert as much of the byte buffer to unicode as possible
     209           3 :   auto src = AsBytes(MakeSpan(mByteData));
     210           3 :   auto dst = MakeSpan(mUnicharData);
     211             :   // mUnicharData.Length() is the buffer length, not the fill status.
     212             :   // mUnicharDataLength reflects the current fill status.
     213           3 :   mUnicharDataLength = 0;
     214             :   // Whenever we convert, mUnicharData is logically empty.
     215           3 :   mUnicharDataOffset = 0;
     216             :   // Truncation from size_t to uint32_t below is OK, because the sizes
     217             :   // are bounded by the lengths of mByteData and mUnicharData.
     218             :   uint32_t result;
     219             :   size_t read;
     220             :   size_t written;
     221             :   bool hadErrors;
     222             :   // The design of this class is fundamentally bogus in that trailing
     223             :   // errors are ignored. Always passing false as the last argument to
     224             :   // Decode* calls below.
     225           3 :   if (mErrorsAreFatal) {
     226           6 :     Tie(result, read, written) =
     227           9 :       mConverter->DecodeToUTF16WithoutReplacement(src, dst, false);
     228             :   } else {
     229           0 :     Tie(result, read, written, hadErrors) =
     230           0 :       mConverter->DecodeToUTF16(src, dst, false);
     231             :   }
     232             :   Unused << hadErrors;
     233           3 :   mLeftOverBytes = mByteData.Length() - read;
     234           3 :   mUnicharDataLength = written;
     235           3 :   if (result == kInputEmpty || result == kOutputFull) {
     236           3 :     *aErrorCode = NS_OK;
     237             :   } else {
     238           0 :     MOZ_ASSERT(mErrorsAreFatal, "How come DecodeToUTF16() reported error?");
     239           0 :     *aErrorCode = NS_ERROR_UDEC_ILLEGALINPUT;
     240             :   }
     241           3 :   return mUnicharDataLength;
     242             : }
     243             : 
     244             : NS_IMETHODIMP
     245           0 : nsConverterInputStream::ReadLine(nsAString& aLine, bool* aResult)
     246             : {
     247           0 :   if (!mLineBuffer) {
     248           0 :     mLineBuffer = new nsLineBuffer<char16_t>;
     249             :   }
     250           0 :   return NS_ReadLine(this, mLineBuffer.get(), aLine, aResult);
     251             : }

Generated by: LCOV version 1.13