tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsConverterOutputStream.cpp (3344B)


      1 /* vim:set expandtab ts=4 sw=2 sts=2 cin: */
      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 "nsCOMPtr.h"
      7 #include "nsIOutputStream.h"
      8 #include "nsString.h"
      9 #include "nsConverterOutputStream.h"
     10 #include "mozilla/Encoding.h"
     11 
     12 using namespace mozilla;
     13 
     14 NS_IMPL_ISUPPORTS(nsConverterOutputStream, nsIUnicharOutputStream,
     15                  nsIConverterOutputStream)
     16 
     17 nsConverterOutputStream::~nsConverterOutputStream() { Close(); }
     18 
     19 NS_IMETHODIMP
     20 nsConverterOutputStream::Init(nsIOutputStream* aOutStream,
     21                              const char* aCharset) {
     22  MOZ_ASSERT(aOutStream, "Null output stream!");
     23 
     24  const Encoding* encoding;
     25  if (!aCharset) {
     26    encoding = UTF_8_ENCODING;
     27  } else {
     28    encoding = Encoding::ForLabelNoReplacement(MakeStringSpan(aCharset));
     29    if (!encoding || encoding == UTF_16LE_ENCODING ||
     30        encoding == UTF_16BE_ENCODING) {
     31      return NS_ERROR_UCONV_NOCONV;
     32    }
     33  }
     34 
     35  mConverter = encoding->NewEncoder();
     36 
     37  mOutStream = aOutStream;
     38 
     39  return NS_OK;
     40 }
     41 
     42 NS_IMETHODIMP
     43 nsConverterOutputStream::Write(uint32_t aCount, const char16_t* aChars,
     44                               bool* aSuccess) {
     45  if (!mOutStream) {
     46    NS_ASSERTION(!mConverter, "Closed streams shouldn't have converters");
     47    return NS_BASE_STREAM_CLOSED;
     48  }
     49  MOZ_ASSERT(mConverter, "Must have a converter when not closed");
     50  uint8_t buffer[4096];
     51  auto dst = Span(buffer);
     52  auto src = Span(aChars, aCount);
     53  for (;;) {
     54    uint32_t result;
     55    size_t read;
     56    size_t written;
     57    std::tie(result, read, written, std::ignore) =
     58        mConverter->EncodeFromUTF16(src, dst, false);
     59    src = src.From(read);
     60    uint32_t streamWritten;
     61    nsresult rv = mOutStream->Write(reinterpret_cast<char*>(dst.Elements()),
     62                                    written, &streamWritten);
     63    *aSuccess = NS_SUCCEEDED(rv) && written == streamWritten;
     64    if (!(*aSuccess)) {
     65      return rv;
     66    }
     67    if (result == kInputEmpty) {
     68      return NS_OK;
     69    }
     70  }
     71 }
     72 
     73 NS_IMETHODIMP
     74 nsConverterOutputStream::WriteString(const nsAString& aString, bool* aSuccess) {
     75  int32_t inLen = aString.Length();
     76  nsAString::const_iterator i;
     77  aString.BeginReading(i);
     78  return Write(inLen, i.get(), aSuccess);
     79 }
     80 
     81 NS_IMETHODIMP
     82 nsConverterOutputStream::Flush() {
     83  if (!mOutStream) return NS_OK;  // Already closed.
     84 
     85  // If we are encoding to ISO-2022-JP, potentially
     86  // transition back to the ASCII state. The buffer
     87  // needs to be large enough for an additional NCR,
     88  // though.
     89  uint8_t buffer[12];
     90  auto dst = Span(buffer);
     91  Span<char16_t> src(nullptr);
     92  uint32_t result;
     93  size_t written;
     94  std::tie(result, std::ignore, written, std::ignore) =
     95      mConverter->EncodeFromUTF16(src, dst, true);
     96  MOZ_ASSERT(result == kInputEmpty);
     97  uint32_t streamWritten;
     98  if (!written) {
     99    return NS_OK;
    100  }
    101  return mOutStream->Write(reinterpret_cast<char*>(dst.Elements()), written,
    102                           &streamWritten);
    103 }
    104 
    105 NS_IMETHODIMP
    106 nsConverterOutputStream::Close() {
    107  if (!mOutStream) return NS_OK;  // Already closed.
    108 
    109  nsresult rv1 = Flush();
    110 
    111  nsresult rv2 = mOutStream->Close();
    112  mOutStream = nullptr;
    113  mConverter = nullptr;
    114  return NS_FAILED(rv1) ? rv1 : rv2;
    115 }