summaryrefslogtreecommitdiff
path: root/gzip.cpp
blob: 09e420a78d70408f385d8fc64284965145edfa3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// gzip.cpp - written and placed in the public domain by Wei Dai

#include "pch.h"
#include "gzip.h"

NAMESPACE_BEGIN(CryptoPP)

void Gzip::WritePrestreamHeader()
{
	m_totalLen = 0;
	m_crc.Restart();

	AttachedTransformation()->Put(MAGIC1);
	AttachedTransformation()->Put(MAGIC2);
	AttachedTransformation()->Put(DEFLATED);
	AttachedTransformation()->Put(0);		// general flag
	AttachedTransformation()->PutWord32(0);	// time stamp
	byte extra = (GetDeflateLevel() == 1) ? FAST : ((GetDeflateLevel() == 9) ? SLOW : 0);
	AttachedTransformation()->Put(extra);
	AttachedTransformation()->Put(GZIP_OS_CODE);
}

void Gzip::ProcessUncompressedData(const byte *inString, size_t length)
{
	m_crc.Update(inString, length);
	m_totalLen += (word32)length;
}

void Gzip::WritePoststreamTail()
{
	SecByteBlock crc(4);
	m_crc.Final(crc);
	AttachedTransformation()->Put(crc, 4);
	AttachedTransformation()->PutWord32(m_totalLen, LITTLE_ENDIAN_ORDER);
}

// *************************************************************

Gunzip::Gunzip(BufferedTransformation *attachment, bool repeat, int propagation)
	: Inflator(attachment, repeat, propagation)
{
}

void Gunzip::ProcessPrestreamHeader()
{
	m_length = 0;
	m_crc.Restart();

	byte buf[6];
	byte b, flags;

	if (m_inQueue.Get(buf, 2)!=2) throw HeaderErr();
	if (buf[0] != MAGIC1 || buf[1] != MAGIC2) throw HeaderErr();
	if (!m_inQueue.Skip(1)) throw HeaderErr();	 // skip extra flags
	if (!m_inQueue.Get(flags)) throw HeaderErr();
	if (flags & (ENCRYPTED | CONTINUED)) throw HeaderErr();
	if (m_inQueue.Skip(6)!=6) throw HeaderErr();    // Skip file time, extra flags and OS type

	if (flags & EXTRA_FIELDS)	// skip extra fields
	{
		word16 length;
		if (m_inQueue.GetWord16(length, LITTLE_ENDIAN_ORDER) != 2) throw HeaderErr();
		if (m_inQueue.Skip(length)!=length) throw HeaderErr();
	}

	if (flags & FILENAME)	// skip filename
		do
			if(!m_inQueue.Get(b)) throw HeaderErr();
		while (b);

	if (flags & COMMENTS)	// skip comments
		do
			if(!m_inQueue.Get(b)) throw HeaderErr();
		while (b);
}

void Gunzip::ProcessDecompressedData(const byte *inString, size_t length)
{
	AttachedTransformation()->Put(inString, length);
	m_crc.Update(inString, length);
	m_length += (word32)length;
}

void Gunzip::ProcessPoststreamTail()
{
	SecByteBlock crc(4);
	if (m_inQueue.Get(crc, 4) != 4)
		throw TailErr();
	if (!m_crc.Verify(crc))
		throw CrcErr();

	word32 lengthCheck;
	if (m_inQueue.GetWord32(lengthCheck, LITTLE_ENDIAN_ORDER) != 4)
		throw TailErr();
	if (lengthCheck != m_length)
		throw LengthErr();
}

NAMESPACE_END