Coverage Report

Created: 2018-09-25 14:53

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