]>
git.saurik.com Git - wxWidgets.git/blob - src/common/gzstream.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Streams for Gzip files
4 // Author: Mike Wetherell
6 // Copyright: (c) 2003 Mike Wetherell
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11 #pragma implementation "gzstream.h"
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
21 #if wxUSE_STREAMS && wxUSE_GZSTREAM && wxUSE_ZLIB
25 #include "wx/datstrm.h"
26 #include "wx/txtstrm.h"
27 #include "wx/filename.h"
28 #include "wx/zstream.h"
29 #include "wx/gzstream.h"
31 #if defined(__WXMSW__) && !defined(__WX_SETUP_H__) && !defined(wxUSE_ZLIB_H_IN_PATH)
32 #include "../zlib/zlib.h"
38 /////////////////////////////////////////////////////////////////////////////
41 // See RFC-1952 and the Gzip/Zlib sources for the details of the Gzip format
43 // Errors are displayed with wxLogError, but not errors from the compressor
44 // or underlying stream, since they will display their own errors.
46 // Gzip doesn't use flag 2 to indicate a header crc, so I think it's
47 // probably better not to use it for the moment.
54 GZ_EXTRA_FIELD
= 0x04,
66 const wxUint16 GZ_MAGIC
= 0x8b1f;
69 /////////////////////////////////////////////////////////////////////////////
72 wxGzipInputStream::wxGzipInputStream(wxInputStream
& stream
,
73 wxMBConv
& conv
/*=wxConvFile*/)
74 : wxFilterInputStream(stream
)
77 m_crc
= crc32(0, Z_NULL
, 0);
79 // Try to read the Gzip magic numbers 0x1f, 0x8b. If not found then the
80 // underlying stream isn't gzipped after all, so unread the bytes taken
81 // so that the underlying stream can be read directly instead.
83 size_t n
= m_parent_i_stream
->Read(magic
, sizeof(magic
)).LastRead();
85 if (n
< sizeof(magic
) || ((magic
[1] << 8) | magic
[0]) != GZ_MAGIC
) {
87 m_parent_i_stream
->Ungetch(magic
, n
);
88 // Set EOF rather than error to indicate no gzip data
89 m_lasterror
= wxSTREAM_EOF
;
93 wxDataInputStream
ds(*m_parent_i_stream
);
95 // read method, flags, timestamp, extra flags and OS-code
96 int method
= ds
.Read8();
97 int flags
= ds
.Read8();
99 wxUint32 datetime
= ds
.Read32();
100 if (datetime
) // zero means not set (not -1 as usual for time_t)
101 m_datetime
= wxLongLong(0, datetime
) * 1000L;
108 if (flags
& GZ_HEAD_CRC
)
111 if (flags
& GZ_EXTRA_FIELD
)
112 for (int i
= ds
.Read16(); i
> 0 && m_parent_i_stream
->IsOk(); i
--)
113 m_parent_i_stream
->GetC();
115 // RFC-1952 specifies ISO-8859-1 for these fields
116 if (flags
& GZ_ORIG_NAME
) {
118 wxTextInputStream
tis(*m_parent_i_stream
, wxT(" \t"), conv
);
120 wxTextInputStream
tis(*m_parent_i_stream
);
124 while ((c
= tis
.GetChar()) != 0 && m_parent_i_stream
->IsOk())
128 if (flags
& GZ_COMMENT
)
129 while (m_parent_i_stream
->GetC() != 0 && m_parent_i_stream
->IsOk())
132 m_lasterror
= wxSTREAM_READ_ERROR
;
133 if (!*m_parent_i_stream
) {
134 wxLogDebug(wxT("Error reading Gzip header"));
138 if (flags
& GZ_RESERVED
)
139 wxLogWarning(_("Unsupported flag in Gzip header"));
143 m_decomp
= new wxZlibInputStream(*m_parent_i_stream
, wxZLIB_NO_HEADER
);
147 wxLogError(_("unsupported compression method in Gzip stream"));
152 m_lasterror
= m_decomp
->GetLastError();
156 wxGzipInputStream::~wxGzipInputStream()
162 size_t wxGzipInputStream::OnSysRead(void *buffer
, size_t size
)
164 wxASSERT_MSG(m_decomp
, wxT("Gzip not open"));
167 m_lasterror
= wxSTREAM_READ_ERROR
;
168 if (!IsOk() || !size
)
171 m_decomp
->Read(buffer
, size
);
172 m_crc
= crc32(m_crc
, (Byte
*)buffer
, m_decomp
->LastRead());
174 if (m_decomp
->Eof()) {
175 wxDataInputStream
ds(*m_parent_i_stream
);
176 m_lasterror
= wxSTREAM_READ_ERROR
;
178 if (m_parent_i_stream
->IsOk() && ds
.Read32() != m_crc
)
179 wxLogError(_("reading Gzip stream: bad crc"));
180 else if (m_parent_i_stream
->IsOk() && ds
.Read32() != (wxUint32
)TellI())
181 wxLogError(_("reading Gzip stream: incorrect length"));
182 else if (m_parent_i_stream
->IsOk())
183 m_lasterror
= wxSTREAM_EOF
;
185 else if (!*m_decomp
) {
186 m_lasterror
= wxSTREAM_READ_ERROR
;
189 return m_decomp
->LastRead();
193 /////////////////////////////////////////////////////////////////////////////
196 wxGzipOutputStream::wxGzipOutputStream(
197 wxOutputStream
& stream
,
198 const wxString
& originalName
/*=wxEmptyString*/,
200 wxMBConv
& conv
/*=wxConvFile*/)
201 : wxFilterOutputStream(stream
)
204 m_crc
= crc32(0, Z_NULL
, 0);
206 wxFileName
filename(originalName
);
211 if (filename
.FileExists())
212 datetime
= filename
.GetModificationTime();
214 datetime
= wxDateTime::Now();
216 wxUint32 timestamp
= (datetime
.GetValue() / 1000L).GetLo();
218 wxUint32 timestamp
= 0;
221 // RFC-1952 specifies ISO-8859-1 for the name. Also it should be just the
222 // name part, no directory, folded to lowercase if case insensitive
223 wxString name
= filename
.GetFullName();
224 const wxWX2MBbuf mbName
= conv
.cWX2MB(name
);
226 wxDataOutputStream
ds(*m_parent_o_stream
);
228 // write signature, method, flags, timestamp, extra flags and OS-code
229 ds
.Write16(GZ_MAGIC
);
230 ds
.Write8(Z_DEFLATED
);
231 ds
.Write8(mbName
&& *mbName
? GZ_ORIG_NAME
: 0);
232 ds
.Write32(timestamp
);
233 ds
.Write8(level
== 1 ? GZ_FASTEST
: level
== 9 ? GZ_SLOWEST
: 0);
236 if (mbName
&& *mbName
)
237 m_parent_o_stream
->Write(mbName
, strlen(mbName
) + 1);
239 m_lasterror
= wxSTREAM_WRITE_ERROR
;
240 if (!*m_parent_o_stream
) {
241 wxLogDebug(wxT("Error writing Gzip header"));
245 m_comp
= new wxZlibOutputStream(*m_parent_o_stream
, level
, wxZLIB_NO_HEADER
);
248 m_lasterror
= m_comp
->GetLastError();
252 wxGzipOutputStream::~wxGzipOutputStream()
254 if (m_comp
&& m_comp
->IsOk()) {
255 wxUint32 len
= (wxUint32
)m_comp
->TellO();
257 if (m_parent_o_stream
->IsOk()) {
258 wxDataOutputStream
ds(*m_parent_o_stream
);
260 ds
.Write32(len
); // underlying stream will report errors
268 void wxGzipOutputStream::Sync()
270 wxASSERT_MSG(m_comp
, wxT("Gzip not open"));
273 m_lasterror
= wxSTREAM_WRITE_ERROR
;
279 size_t wxGzipOutputStream::OnSysWrite(const void *buffer
, size_t size
)
281 wxASSERT_MSG(m_comp
, wxT("Gzip not open"));
284 m_lasterror
= wxSTREAM_WRITE_ERROR
;
285 if (!IsOk() || !size
)
288 if (m_comp
->Write(buffer
, size
).LastWrite() != size
)
289 m_lasterror
= wxSTREAM_WRITE_ERROR
;
290 m_crc
= crc32(m_crc
, (Byte
*)buffer
, size
);
292 return m_comp
->LastWrite();
296 #endif // wxUSE_STREAMS && wxUSE_GZSTREAM && wxUSE_ZLIB