1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsGZFileWriter.h"
11 #include "mozilla/ScopeExit.h"
20 nsGZFileWriter::nsGZFileWriter()
21 : mInitialized(false), mFinished(false), mGZFile(nullptr) {
22 mZStream
.avail_out
= sizeof(mBuffer
);
23 mZStream
.next_out
= mBuffer
;
26 nsGZFileWriter::~nsGZFileWriter() {
27 if (mInitialized
&& !mFinished
) {
32 nsresult
nsGZFileWriter::Init(nsIFile
* aFile
) {
33 if (NS_WARN_IF(mInitialized
) || NS_WARN_IF(mFinished
)) {
34 return NS_ERROR_FAILURE
;
37 // Get a FILE out of our nsIFile. Convert that into a file descriptor which
38 // gzip can own. Then close our FILE, leaving only gzip's fd open.
41 nsresult rv
= aFile
->OpenANSIFileDesc("wb", &file
);
42 if (NS_WARN_IF(NS_FAILED(rv
))) {
45 return InitANSIFileDesc(file
);
48 nsresult
nsGZFileWriter::InitANSIFileDesc(FILE* aFile
) {
49 if (NS_WARN_IF(mInitialized
) || NS_WARN_IF(mFinished
)) {
50 return NS_ERROR_FAILURE
;
53 int err
= deflateInit2(&mZStream
, Z_DEFAULT_COMPRESSION
, Z_DEFLATED
,
54 MAX_WBITS
+ /* gzip encoding */ 16,
55 /* DEF_MEM_LEVEL */ 8, Z_DEFAULT_STRATEGY
);
57 return NS_ERROR_FAILURE
;
65 nsresult
nsGZFileWriter::Write(const nsACString
& aStr
) {
66 if (NS_WARN_IF(!mInitialized
) || NS_WARN_IF(mFinished
)) {
67 return NS_ERROR_FAILURE
;
70 // gzwrite uses a return value of 0 to indicate failure. Otherwise, it
71 // returns the number of uncompressed bytes written. To ensure we can
72 // distinguish between success and failure, don't call gzwrite when we have 0
78 mZStream
.avail_in
= aStr
.Length();
80 reinterpret_cast<Bytef
*>(const_cast<char*>(aStr
.BeginReading()));
82 auto cleanup
= mozilla::MakeScopeExit([&] {
83 mZStream
.avail_in
= 0;
84 mZStream
.next_in
= nullptr;
86 auto onerror
= mozilla::MakeScopeExit([&] {
92 if (mZStream
.avail_out
== 0) {
93 if (fwrite(mBuffer
, 1, sizeof(mBuffer
), mGZFile
) != sizeof(mBuffer
)) {
94 return NS_ERROR_FAILURE
;
96 mZStream
.avail_out
= sizeof(mBuffer
);
97 mZStream
.next_out
= mBuffer
;
99 int err
= deflate(&mZStream
, Z_NO_FLUSH
);
100 if (err
== Z_STREAM_ERROR
) {
101 return NS_ERROR_FAILURE
;
103 } while (mZStream
.avail_in
);
109 nsresult
nsGZFileWriter::Finish() {
110 if (NS_WARN_IF(!mInitialized
) || NS_WARN_IF(mFinished
)) {
111 return NS_ERROR_FAILURE
;
114 mZStream
.avail_in
= 0;
115 mZStream
.next_in
= nullptr;
117 auto cleanup
= mozilla::MakeScopeExit([&] {
124 err
= deflate(&mZStream
, Z_FINISH
);
125 if (err
== Z_STREAM_ERROR
) {
126 return NS_ERROR_FAILURE
;
128 size_t length
= sizeof(mBuffer
) - mZStream
.avail_out
;
129 if (fwrite(mBuffer
, 1, length
, mGZFile
) != length
) {
130 return NS_ERROR_FAILURE
;
132 mZStream
.avail_out
= sizeof(mBuffer
);
133 mZStream
.next_out
= mBuffer
;
134 } while (err
!= Z_STREAM_END
);
136 // Ignore errors from fclose; it's not like there's anything we can do about
137 // it, at this point!