Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/modules/libjar/zipwriter/nsDeflateConverter.cpp
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
 */
5
6
#include "StreamFunctions.h"
7
#include "nsDeflateConverter.h"
8
#include "nsStringStream.h"
9
#include "nsIInputStreamPump.h"
10
#include "nsComponentManagerUtils.h"
11
#include "nsMemory.h"
12
#include "plstr.h"
13
#include "mozilla/UniquePtr.h"
14
15
0
#define ZLIB_TYPE "deflate"
16
0
#define GZIP_TYPE "gzip"
17
0
#define X_GZIP_TYPE "x-gzip"
18
19
using namespace mozilla;
20
21
/**
22
 * nsDeflateConverter is a stream converter applies the deflate compression
23
 * method to the data.
24
 */
25
NS_IMPL_ISUPPORTS(nsDeflateConverter, nsIStreamConverter,
26
                  nsIStreamListener,
27
                  nsIRequestObserver)
28
29
nsresult nsDeflateConverter::Init()
30
0
{
31
0
    int zerr;
32
0
33
0
    mOffset = 0;
34
0
35
0
    mZstream.zalloc = Z_NULL;
36
0
    mZstream.zfree = Z_NULL;
37
0
    mZstream.opaque = Z_NULL;
38
0
39
0
    int32_t window = MAX_WBITS;
40
0
    switch (mWrapMode) {
41
0
        case WRAP_NONE:
42
0
            window = -window;
43
0
            break;
44
0
        case WRAP_GZIP:
45
0
            window += 16;
46
0
            break;
47
0
        default:
48
0
            break;
49
0
    }
50
0
51
0
    zerr = deflateInit2(&mZstream, mLevel, Z_DEFLATED, window, 8,
52
0
                        Z_DEFAULT_STRATEGY);
53
0
    if (zerr != Z_OK) return NS_ERROR_OUT_OF_MEMORY;
54
0
55
0
    mZstream.next_out = mWriteBuffer;
56
0
    mZstream.avail_out = sizeof(mWriteBuffer);
57
0
58
0
    // mark the input buffer as empty.
59
0
    mZstream.avail_in = 0;
60
0
    mZstream.next_in = Z_NULL;
61
0
62
0
    return NS_OK;
63
0
}
64
65
NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream *aFromStream,
66
                                          const char *aFromType,
67
                                          const char *aToType,
68
                                          nsISupports *aCtxt,
69
                                          nsIInputStream **_retval)
70
0
{
71
0
    return NS_ERROR_NOT_IMPLEMENTED;
72
0
}
73
74
NS_IMETHODIMP nsDeflateConverter::AsyncConvertData(const char *aFromType,
75
                                                   const char *aToType,
76
                                                   nsIStreamListener *aListener,
77
                                                   nsISupports *aCtxt)
78
0
{
79
0
    if (mListener)
80
0
        return NS_ERROR_ALREADY_INITIALIZED;
81
0
82
0
    NS_ENSURE_ARG_POINTER(aListener);
83
0
84
0
    if (!PL_strncasecmp(aToType, ZLIB_TYPE, sizeof(ZLIB_TYPE)-1))
85
0
        mWrapMode = WRAP_ZLIB;
86
0
    else if (!PL_strcasecmp(aToType, GZIP_TYPE) ||
87
0
             !PL_strcasecmp(aToType, X_GZIP_TYPE))
88
0
        mWrapMode = WRAP_GZIP;
89
0
    else
90
0
        mWrapMode = WRAP_NONE;
91
0
92
0
    nsresult rv = Init();
93
0
    NS_ENSURE_SUCCESS(rv, rv);
94
0
95
0
    mListener = aListener;
96
0
    mContext = aCtxt;
97
0
    return rv;
98
0
}
99
100
NS_IMETHODIMP nsDeflateConverter::OnDataAvailable(nsIRequest *aRequest,
101
                                                  nsISupports *aContext,
102
                                                  nsIInputStream *aInputStream,
103
                                                  uint64_t aOffset,
104
                                                  uint32_t aCount)
105
0
{
106
0
    if (!mListener)
107
0
        return NS_ERROR_NOT_INITIALIZED;
108
0
109
0
    auto buffer = MakeUnique<char[]>(aCount);
110
0
    NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
111
0
112
0
    nsresult rv = ZW_ReadData(aInputStream, buffer.get(), aCount);
113
0
    NS_ENSURE_SUCCESS(rv, rv);
114
0
115
0
    // make sure we aren't reading too much
116
0
    mZstream.avail_in = aCount;
117
0
    mZstream.next_in = (unsigned char*)buffer.get();
118
0
119
0
    int zerr = Z_OK;
120
0
    // deflate loop
121
0
    while (mZstream.avail_in > 0 && zerr == Z_OK) {
122
0
        zerr = deflate(&mZstream, Z_NO_FLUSH);
123
0
124
0
        while (mZstream.avail_out == 0) {
125
0
            // buffer is full, push the data out to the listener
126
0
            rv = PushAvailableData(aRequest, aContext);
127
0
            NS_ENSURE_SUCCESS(rv, rv);
128
0
            zerr = deflate(&mZstream, Z_NO_FLUSH);
129
0
        }
130
0
    }
131
0
132
0
    return NS_OK;
133
0
}
134
135
NS_IMETHODIMP nsDeflateConverter::OnStartRequest(nsIRequest *aRequest,
136
                                                 nsISupports *aContext)
137
0
{
138
0
    if (!mListener)
139
0
        return NS_ERROR_NOT_INITIALIZED;
140
0
141
0
    return mListener->OnStartRequest(aRequest, mContext);
142
0
}
143
144
NS_IMETHODIMP nsDeflateConverter::OnStopRequest(nsIRequest *aRequest,
145
                                                nsISupports *aContext,
146
                                                nsresult aStatusCode)
147
0
{
148
0
    if (!mListener)
149
0
        return NS_ERROR_NOT_INITIALIZED;
150
0
151
0
    nsresult rv;
152
0
153
0
    int zerr;
154
0
    do {
155
0
        zerr = deflate(&mZstream, Z_FINISH);
156
0
        rv = PushAvailableData(aRequest, aContext);
157
0
        NS_ENSURE_SUCCESS(rv, rv);
158
0
    } while (zerr == Z_OK);
159
0
160
0
    deflateEnd(&mZstream);
161
0
162
0
    return mListener->OnStopRequest(aRequest, mContext, aStatusCode);
163
0
}
164
165
nsresult nsDeflateConverter::PushAvailableData(nsIRequest *aRequest,
166
                                               nsISupports *aContext)
167
0
{
168
0
    uint32_t bytesToWrite = sizeof(mWriteBuffer) - mZstream.avail_out;
169
0
    // We don't need to do anything if there isn't any data
170
0
    if (bytesToWrite == 0)
171
0
        return NS_OK;
172
0
173
0
    MOZ_ASSERT(bytesToWrite <= INT32_MAX);
174
0
    nsCOMPtr<nsIInputStream> stream;
175
0
    nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
176
0
          (char*)mWriteBuffer, bytesToWrite);
177
0
    NS_ENSURE_SUCCESS(rv, rv);
178
0
179
0
    rv = mListener->OnDataAvailable(aRequest, mContext, stream, mOffset,
180
0
                                    bytesToWrite);
181
0
182
0
    // now set the state for 'deflate'
183
0
    mZstream.next_out = mWriteBuffer;
184
0
    mZstream.avail_out = sizeof(mWriteBuffer);
185
0
186
0
    mOffset += bytesToWrite;
187
0
    return rv;
188
0
}