Skip to content

Commit d9fb8a4

Browse files
authored
PR 351: Add support for Filename field in GZip
1 parent 8ab21b0 commit d9fb8a4

File tree

5 files changed

+171
-105
lines changed

5 files changed

+171
-105
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using System;
2+
using System.Text;
3+
14
namespace ICSharpCode.SharpZipLib.GZip
25
{
36
/// <summary>
@@ -7,53 +10,69 @@ namespace ICSharpCode.SharpZipLib.GZip
710
sealed public class GZipConstants
811
{
912
/// <summary>
10-
/// Magic number found at start of GZIP header
13+
/// First GZip identification byte
1114
/// </summary>
12-
public const int GZIP_MAGIC = 0x1F8B;
15+
public const byte ID1 = 0x1F;
1316

14-
/* The flag byte is divided into individual bits as follows:
17+
/// <summary>
18+
/// Second GZip identification byte
19+
/// </summary>
20+
public const byte ID2 = 0x8B;
1521

16-
bit 0 FTEXT
17-
bit 1 FHCRC
18-
bit 2 FEXTRA
19-
bit 3 FNAME
20-
bit 4 FCOMMENT
21-
bit 5 reserved
22-
bit 6 reserved
23-
bit 7 reserved
24-
*/
22+
/// <summary>
23+
/// Deflate compression method
24+
/// </summary>
25+
public const byte CompressionMethodDeflate = 0x8;
2526

2627
/// <summary>
27-
/// Flag bit mask for text
28+
/// Get the GZip specified encoding (CP-1252 if supported, otherwise ASCII)
2829
/// </summary>
29-
public const int FTEXT = 0x1;
30+
public static Encoding Encoding
31+
{
32+
get
33+
{
34+
try
35+
{
36+
return Encoding.GetEncoding(1252);
37+
}
38+
catch
39+
{
40+
return Encoding.ASCII;
41+
}
42+
}
43+
}
3044

45+
}
46+
47+
/// <summary>
48+
/// GZip header flags
49+
/// </summary>
50+
[Flags]
51+
public enum GZipFlags: byte
52+
{
3153
/// <summary>
32-
/// Flag bitmask for Crc
54+
/// Text flag hinting that the file is in ASCII
3355
/// </summary>
34-
public const int FHCRC = 0x2;
56+
FTEXT = 0x1 << 0,
3557

3658
/// <summary>
37-
/// Flag bit mask for extra
59+
/// CRC flag indicating that a CRC16 preceeds the data
3860
/// </summary>
39-
public const int FEXTRA = 0x4;
61+
FHCRC = 0x1 << 1,
4062

4163
/// <summary>
42-
/// flag bitmask for name
64+
/// Extra flag indicating that extra fields are present
4365
/// </summary>
44-
public const int FNAME = 0x8;
66+
FEXTRA = 0x1 << 2,
4567

4668
/// <summary>
47-
/// flag bit mask indicating comment is present
69+
/// Filename flag indicating that the original filename is present
4870
/// </summary>
49-
public const int FCOMMENT = 0x10;
71+
FNAME = 0x1 << 3,
5072

5173
/// <summary>
52-
/// Initialise default instance.
74+
/// Flag bit mask indicating that a comment is present
5375
/// </summary>
54-
/// <remarks>Constructor is private to prevent instances being created.</remarks>
55-
private GZipConstants()
56-
{
57-
}
76+
FCOMMENT = 0x1 << 4,
5877
}
5978
}

src/ICSharpCode.SharpZipLib/GZip/GzipInputStream.cs

+44-73
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
44
using System;
55
using System.IO;
6+
using System.Text;
67

78
namespace ICSharpCode.SharpZipLib.GZip
89
{
@@ -54,6 +55,8 @@ public class GZipInputStream : InflaterInputStream
5455
/// </summary>
5556
private bool completedLastBlock;
5657

58+
private string fileName;
59+
5760
#endregion Instance Fields
5861

5962
#region Constructors
@@ -149,6 +152,15 @@ public override int Read(byte[] buffer, int offset, int count)
149152
}
150153
}
151154

155+
/// <summary>
156+
/// Retrieves the filename header field for the block last read
157+
/// </summary>
158+
/// <returns></returns>
159+
public string GetFilename()
160+
{
161+
return fileName;
162+
}
163+
152164
#endregion Stream overrides
153165

154166
#region Support routines
@@ -170,149 +182,108 @@ private bool ReadHeader()
170182
}
171183
}
172184

173-
// 1. Check the two magic bytes
174185
var headCRC = new Crc32();
175-
int magic = inputBuffer.ReadLeByte();
176186

177-
if (magic < 0)
178-
{
179-
throw new EndOfStreamException("EOS reading GZIP header");
180-
}
187+
// 1. Check the two magic bytes
181188

189+
var magic = inputBuffer.ReadLeByte();
182190
headCRC.Update(magic);
183-
if (magic != (GZipConstants.GZIP_MAGIC >> 8))
191+
if (magic != GZipConstants.ID1)
184192
{
185193
throw new GZipException("Error GZIP header, first magic byte doesn't match");
186194
}
187195

188-
//magic = baseInputStream.ReadByte();
189196
magic = inputBuffer.ReadLeByte();
190-
191-
if (magic < 0)
192-
{
193-
throw new EndOfStreamException("EOS reading GZIP header");
194-
}
195-
196-
if (magic != (GZipConstants.GZIP_MAGIC & 0xFF))
197+
if (magic != GZipConstants.ID2)
197198
{
198199
throw new GZipException("Error GZIP header, second magic byte doesn't match");
199200
}
200-
201201
headCRC.Update(magic);
202202

203203
// 2. Check the compression type (must be 8)
204-
int compressionType = inputBuffer.ReadLeByte();
205-
206-
if (compressionType < 0)
207-
{
208-
throw new EndOfStreamException("EOS reading GZIP header");
209-
}
204+
var compressionType = inputBuffer.ReadLeByte();
210205

211-
if (compressionType != 8)
206+
if (compressionType != GZipConstants.CompressionMethodDeflate)
212207
{
213208
throw new GZipException("Error GZIP header, data not in deflate format");
214209
}
215210
headCRC.Update(compressionType);
216211

217212
// 3. Check the flags
218-
int flags = inputBuffer.ReadLeByte();
219-
if (flags < 0)
220-
{
221-
throw new EndOfStreamException("EOS reading GZIP header");
222-
}
223-
headCRC.Update(flags);
224-
225-
/* This flag byte is divided into individual bits as follows:
213+
var flagsByte = inputBuffer.ReadLeByte();
226214

227-
bit 0 FTEXT
228-
bit 1 FHCRC
229-
bit 2 FEXTRA
230-
bit 3 FNAME
231-
bit 4 FCOMMENT
232-
bit 5 reserved
233-
bit 6 reserved
234-
bit 7 reserved
235-
*/
215+
headCRC.Update(flagsByte);
236216

237217
// 3.1 Check the reserved bits are zero
238218

239-
if ((flags & 0xE0) != 0)
219+
if ((flagsByte & 0xE0) != 0)
240220
{
241221
throw new GZipException("Reserved flag bits in GZIP header != 0");
242222
}
243223

224+
var flags = (GZipFlags)flagsByte;
225+
244226
// 4.-6. Skip the modification time, extra flags, and OS type
245227
for (int i = 0; i < 6; i++)
246228
{
247-
int readByte = inputBuffer.ReadLeByte();
248-
if (readByte < 0)
249-
{
250-
throw new EndOfStreamException("EOS reading GZIP header");
251-
}
252-
headCRC.Update(readByte);
229+
headCRC.Update(inputBuffer.ReadLeByte());
253230
}
254231

255232
// 7. Read extra field
256-
if ((flags & GZipConstants.FEXTRA) != 0)
233+
if (flags.HasFlag(GZipFlags.FEXTRA))
257234
{
258235
// XLEN is total length of extra subfields, we will skip them all
259-
int len1, len2;
260-
len1 = inputBuffer.ReadLeByte();
261-
len2 = inputBuffer.ReadLeByte();
262-
if ((len1 < 0) || (len2 < 0))
263-
{
264-
throw new EndOfStreamException("EOS reading GZIP header");
265-
}
236+
var len1 = inputBuffer.ReadLeByte();
237+
var len2 = inputBuffer.ReadLeByte();
238+
266239
headCRC.Update(len1);
267240
headCRC.Update(len2);
268241

269242
int extraLen = (len2 << 8) | len1; // gzip is LSB first
270243
for (int i = 0; i < extraLen; i++)
271244
{
272-
int readByte = inputBuffer.ReadLeByte();
273-
if (readByte < 0)
274-
{
275-
throw new EndOfStreamException("EOS reading GZIP header");
276-
}
277-
headCRC.Update(readByte);
245+
headCRC.Update(inputBuffer.ReadLeByte());
278246
}
279247
}
280248

281249
// 8. Read file name
282-
if ((flags & GZipConstants.FNAME) != 0)
250+
if (flags.HasFlag(GZipFlags.FNAME))
283251
{
252+
var fname = new byte[1024];
253+
var fnamePos = 0;
284254
int readByte;
285255
while ((readByte = inputBuffer.ReadLeByte()) > 0)
286256
{
257+
if (fnamePos < 1024)
258+
{
259+
fname[fnamePos++] = (byte)readByte;
260+
}
287261
headCRC.Update(readByte);
288262
}
289263

290-
if (readByte < 0)
291-
{
292-
throw new EndOfStreamException("EOS reading GZIP header");
293-
}
294264
headCRC.Update(readByte);
265+
266+
fileName = GZipConstants.Encoding.GetString(fname, 0, fnamePos);
267+
}
268+
else
269+
{
270+
fileName = null;
295271
}
296272

297273
// 9. Read comment
298-
if ((flags & GZipConstants.FCOMMENT) != 0)
274+
if (flags.HasFlag(GZipFlags.FCOMMENT))
299275
{
300276
int readByte;
301277
while ((readByte = inputBuffer.ReadLeByte()) > 0)
302278
{
303279
headCRC.Update(readByte);
304280
}
305281

306-
if (readByte < 0)
307-
{
308-
throw new EndOfStreamException("EOS reading GZIP header");
309-
}
310-
311282
headCRC.Update(readByte);
312283
}
313284

314285
// 10. Read header CRC
315-
if ((flags & GZipConstants.FHCRC) != 0)
286+
if (flags.HasFlag(GZipFlags.FHCRC))
316287
{
317288
int tempByte;
318289
int crcval = inputBuffer.ReadLeByte();

0 commit comments

Comments
 (0)