DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
/* vim:set expandtab ts=4 sw=4 sts=4 cin: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nsCOMPtr.h"

#include "nsIOutputStream.h"
#include "nsString.h"

#include "nsConverterOutputStream.h"
#include "mozilla/Encoding.h"
#include "mozilla/Unused.h"

using namespace mozilla;

NS_IMPL_ISUPPORTS(nsConverterOutputStream, nsIUnicharOutputStream,
                  nsIConverterOutputStream)

nsConverterOutputStream::~nsConverterOutputStream() { Close(); }

NS_IMETHODIMP
nsConverterOutputStream::Init(nsIOutputStream* aOutStream,
                              const char* aCharset) {
  NS_PRECONDITION(aOutStream, "Null output stream!");

  const Encoding* encoding;
  if (!aCharset) {
    encoding = UTF_8_ENCODING;
  } else {
    encoding = Encoding::ForLabelNoReplacement(MakeStringSpan(aCharset));
    if (!encoding || encoding == UTF_16LE_ENCODING ||
        encoding == UTF_16BE_ENCODING) {
      return NS_ERROR_UCONV_NOCONV;
    }
  }

  mConverter = encoding->NewEncoder();

  mOutStream = aOutStream;

  return NS_OK;
}

NS_IMETHODIMP
nsConverterOutputStream::Write(uint32_t aCount, const char16_t* aChars,
                               bool* aSuccess) {
  if (!mOutStream) {
    NS_ASSERTION(!mConverter, "Closed streams shouldn't have converters");
    return NS_BASE_STREAM_CLOSED;
  }
  MOZ_ASSERT(mConverter, "Must have a converter when not closed");
  uint8_t buffer[4096];
  auto dst = MakeSpan(buffer);
  auto src = MakeSpan(aChars, aCount);
  for (;;) {
    uint32_t result;
    size_t read;
    size_t written;
    bool hadErrors;
    Tie(result, read, written, hadErrors) =
        mConverter->EncodeFromUTF16(src, dst, false);
    Unused << hadErrors;
    src = src.From(read);
    uint32_t streamWritten;
    nsresult rv = mOutStream->Write(reinterpret_cast<char*>(dst.Elements()),
                                    written, &streamWritten);
    *aSuccess = NS_SUCCEEDED(rv) && written == streamWritten;
    if (!(*aSuccess)) {
      return rv;
    }
    if (result == kInputEmpty) {
      return NS_OK;
    }
  }
}

NS_IMETHODIMP
nsConverterOutputStream::WriteString(const nsAString& aString, bool* aSuccess) {
  int32_t inLen = aString.Length();
  nsAString::const_iterator i;
  aString.BeginReading(i);
  return Write(inLen, i.get(), aSuccess);
}

NS_IMETHODIMP
nsConverterOutputStream::Flush() {
  if (!mOutStream) return NS_OK;  // Already closed.

  // If we are encoding to ISO-2022-JP, potentially
  // transition back to the ASCII state. The buffer
  // needs to be large enough for an additional NCR,
  // though.
  uint8_t buffer[12];
  auto dst = MakeSpan(buffer);
  Span<char16_t> src(nullptr);
  uint32_t result;
  size_t read;
  size_t written;
  bool hadErrors;
  Tie(result, read, written, hadErrors) =
      mConverter->EncodeFromUTF16(src, dst, true);
  Unused << hadErrors;
  MOZ_ASSERT(result == kInputEmpty);
  uint32_t streamWritten;
  if (!written) {
    return NS_OK;
  }
  return mOutStream->Write(reinterpret_cast<char*>(dst.Elements()), written,
                           &streamWritten);
}

NS_IMETHODIMP
nsConverterOutputStream::Close() {
  if (!mOutStream) return NS_OK;  // Already closed.

  nsresult rv1 = Flush();

  nsresult rv2 = mOutStream->Close();
  mOutStream = nullptr;
  mConverter = nullptr;
  return NS_FAILED(rv1) ? rv1 : rv2;
}