|
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/. */ |
|
6 |
|
7 #include "nsGZFileWriter.h" |
|
8 #include "nsIFile.h" |
|
9 #include "nsString.h" |
|
10 #include "zlib.h" |
|
11 |
|
12 #ifdef XP_WIN |
|
13 #include <io.h> |
|
14 #define _dup dup |
|
15 #else |
|
16 #include <unistd.h> |
|
17 #endif |
|
18 |
|
19 NS_IMPL_ISUPPORTS(nsGZFileWriter, nsIGZFileWriter) |
|
20 |
|
21 nsGZFileWriter::nsGZFileWriter() |
|
22 : mInitialized(false) |
|
23 , mFinished(false) |
|
24 {} |
|
25 |
|
26 nsGZFileWriter::~nsGZFileWriter() |
|
27 { |
|
28 if (mInitialized && !mFinished) { |
|
29 Finish(); |
|
30 } |
|
31 } |
|
32 |
|
33 NS_IMETHODIMP |
|
34 nsGZFileWriter::Init(nsIFile* aFile) |
|
35 { |
|
36 if (NS_WARN_IF(mInitialized) || |
|
37 NS_WARN_IF(mFinished)) |
|
38 return NS_ERROR_FAILURE; |
|
39 |
|
40 // Get a FILE out of our nsIFile. Convert that into a file descriptor which |
|
41 // gzip can own. Then close our FILE, leaving only gzip's fd open. |
|
42 |
|
43 FILE* file; |
|
44 nsresult rv = aFile->OpenANSIFileDesc("wb", &file); |
|
45 if (NS_WARN_IF(NS_FAILED(rv))) |
|
46 return rv; |
|
47 |
|
48 mGZFile = gzdopen(dup(fileno(file)), "wb"); |
|
49 fclose(file); |
|
50 |
|
51 // gzdopen returns nullptr on error. |
|
52 if (NS_WARN_IF(!mGZFile)) |
|
53 return NS_ERROR_FAILURE; |
|
54 |
|
55 mInitialized = true; |
|
56 |
|
57 return NS_OK; |
|
58 } |
|
59 |
|
60 NS_IMETHODIMP |
|
61 nsGZFileWriter::Write(const nsACString& aStr) |
|
62 { |
|
63 if (NS_WARN_IF(!mInitialized) || |
|
64 NS_WARN_IF(mFinished)) |
|
65 return NS_ERROR_FAILURE; |
|
66 |
|
67 // gzwrite uses a return value of 0 to indicate failure. Otherwise, it |
|
68 // returns the number of uncompressed bytes written. To ensure we can |
|
69 // distinguish between success and failure, don't call gzwrite when we have 0 |
|
70 // bytes to write. |
|
71 if (aStr.IsEmpty()) { |
|
72 return NS_OK; |
|
73 } |
|
74 |
|
75 // gzwrite never does a short write -- that is, the return value should |
|
76 // always be either 0 or aStr.Length(), and we shouldn't have to call it |
|
77 // multiple times in order to get it to read the whole buffer. |
|
78 int rv = gzwrite(mGZFile, aStr.BeginReading(), aStr.Length()); |
|
79 if (NS_WARN_IF(rv != static_cast<int>(aStr.Length()))) |
|
80 return NS_ERROR_FAILURE; |
|
81 |
|
82 return NS_OK; |
|
83 } |
|
84 |
|
85 NS_IMETHODIMP |
|
86 nsGZFileWriter::Finish() |
|
87 { |
|
88 if (NS_WARN_IF(!mInitialized) || |
|
89 NS_WARN_IF(mFinished)) |
|
90 return NS_ERROR_FAILURE; |
|
91 |
|
92 mFinished = true; |
|
93 gzclose(mGZFile); |
|
94 |
|
95 // Ignore errors from gzclose; it's not like there's anything we can do about |
|
96 // it, at this point! |
|
97 return NS_OK; |
|
98 } |