2017-01-27 12:05:45 +00:00
|
|
|
// gzip.cpp - originally written and placed in the public domain by Wei Dai
|
2015-11-05 06:59:46 +00:00
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "gzip.h"
|
2017-05-12 23:52:42 +00:00
|
|
|
#include "argnames.h"
|
2015-11-05 06:59:46 +00:00
|
|
|
|
|
|
|
NAMESPACE_BEGIN(CryptoPP)
|
|
|
|
|
2017-05-12 19:09:21 +00:00
|
|
|
// Checks whether the character is valid for ISO/IEC 8859-1 as required by RFC 1952
|
|
|
|
static inline bool Is8859Character(char c) {
|
|
|
|
const unsigned char cc = static_cast<unsigned char>(c);
|
2017-05-20 05:27:23 +00:00
|
|
|
return (cc >= 32 && cc <= 126) || (cc >= 160);
|
2017-05-12 19:09:21 +00:00
|
|
|
}
|
|
|
|
|
2017-05-12 23:52:42 +00:00
|
|
|
void Gzip::IsolatedInitialize(const NameValuePairs ¶meters)
|
|
|
|
{
|
2018-07-11 21:10:32 +00:00
|
|
|
Deflator::IsolatedInitialize(parameters);
|
|
|
|
|
2017-05-12 23:52:42 +00:00
|
|
|
ConstByteArrayParameter v;
|
|
|
|
if (parameters.GetValue(Name::FileName(), v))
|
|
|
|
m_filename.assign(reinterpret_cast<const char*>(v.begin()), v.size());
|
|
|
|
if (parameters.GetValue(Name::Comment(), v))
|
|
|
|
m_comment.assign(reinterpret_cast<const char*>(v.begin()), v.size());
|
|
|
|
m_filetime = parameters.GetIntValueWithDefault(Name::FileTime(), 0);
|
|
|
|
}
|
|
|
|
|
2015-11-05 06:59:46 +00:00
|
|
|
void Gzip::WritePrestreamHeader()
|
|
|
|
{
|
|
|
|
m_totalLen = 0;
|
|
|
|
m_crc.Restart();
|
|
|
|
|
2017-05-12 19:09:21 +00:00
|
|
|
int flags = 0;
|
|
|
|
if(!m_filename.empty())
|
|
|
|
flags |= FILENAME;
|
|
|
|
if(!m_comment.empty())
|
|
|
|
flags |= COMMENTS;
|
|
|
|
|
2015-11-05 06:59:46 +00:00
|
|
|
AttachedTransformation()->Put(MAGIC1);
|
|
|
|
AttachedTransformation()->Put(MAGIC2);
|
|
|
|
AttachedTransformation()->Put(DEFLATED);
|
2017-05-12 19:09:21 +00:00
|
|
|
AttachedTransformation()->Put((byte)flags); // general flag
|
2017-05-12 20:51:03 +00:00
|
|
|
AttachedTransformation()->PutWord32(m_filetime, LITTLE_ENDIAN_ORDER); // time stamp
|
2018-08-20 18:01:05 +00:00
|
|
|
byte extra = static_cast<byte>((GetDeflateLevel() == 1) ?
|
|
|
|
FAST : ((GetDeflateLevel() == 9) ? SLOW : 0));
|
2015-11-05 06:59:46 +00:00
|
|
|
AttachedTransformation()->Put(extra);
|
|
|
|
AttachedTransformation()->Put(GZIP_OS_CODE);
|
2017-05-12 19:09:21 +00:00
|
|
|
|
|
|
|
// Filename is NULL terminated, hence the +1
|
|
|
|
if(!m_filename.empty())
|
|
|
|
AttachedTransformation()->Put((const unsigned char*)m_filename.data(), m_filename.size() +1);
|
|
|
|
|
|
|
|
// Comment is NULL terminated, hence the +1
|
|
|
|
if(!m_comment.empty())
|
|
|
|
AttachedTransformation()->Put((const unsigned char*)m_comment.data(), m_comment.size() +1);
|
2015-11-05 06:59:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2017-05-12 20:51:03 +00:00
|
|
|
AttachedTransformation()->PutWord32(m_totalLen, LITTLE_ENDIAN_ORDER);
|
2017-05-12 19:09:21 +00:00
|
|
|
|
|
|
|
m_filetime = 0;
|
|
|
|
m_filename.clear();
|
|
|
|
m_comment.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Gzip::SetComment(const std::string& comment, bool throwOnEncodingError)
|
|
|
|
{
|
|
|
|
if(throwOnEncodingError)
|
|
|
|
{
|
|
|
|
for(size_t i = 0; i < comment.length(); i++) {
|
|
|
|
const char c = comment[i];
|
|
|
|
if(!Is8859Character(c))
|
|
|
|
throw InvalidDataFormat("The comment is not ISO/IEC 8859-1 encoded");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_comment = comment;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Gzip::SetFilename(const std::string& filename, bool throwOnEncodingError)
|
|
|
|
{
|
|
|
|
if(throwOnEncodingError)
|
|
|
|
{
|
|
|
|
for(size_t i = 0; i < filename.length(); i++) {
|
|
|
|
const char c = filename[i];
|
|
|
|
if(!Is8859Character(c))
|
|
|
|
throw InvalidDataFormat("The filename is not ISO/IEC 8859-1 encoded");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_filename = filename;
|
2015-11-05 06:59:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// *************************************************************
|
|
|
|
|
|
|
|
Gunzip::Gunzip(BufferedTransformation *attachment, bool repeat, int propagation)
|
2017-05-12 19:09:21 +00:00
|
|
|
: Inflator(attachment, repeat, propagation), m_length(0), m_filetime(0)
|
2015-11-05 06:59:46 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Gunzip::ProcessPrestreamHeader()
|
|
|
|
{
|
|
|
|
m_length = 0;
|
|
|
|
m_crc.Restart();
|
|
|
|
|
2017-05-12 19:09:21 +00:00
|
|
|
m_filetime = 0;
|
|
|
|
m_filename.clear();
|
|
|
|
m_comment.clear();
|
|
|
|
|
2015-11-05 06:59:46 +00:00
|
|
|
byte buf[6];
|
|
|
|
byte b, flags;
|
|
|
|
|
|
|
|
if (m_inQueue.Get(buf, 2)!=2) throw HeaderErr();
|
|
|
|
if (buf[0] != MAGIC1 || buf[1] != MAGIC2) throw HeaderErr();
|
2017-05-12 19:09:21 +00:00
|
|
|
if (!m_inQueue.Get(b) || (b != DEFLATED)) throw HeaderErr(); // skip CM flag
|
2015-11-05 06:59:46 +00:00
|
|
|
if (!m_inQueue.Get(flags)) throw HeaderErr();
|
|
|
|
if (flags & (ENCRYPTED | CONTINUED)) throw HeaderErr();
|
2017-05-12 19:09:21 +00:00
|
|
|
if (m_inQueue.GetWord32(m_filetime, LITTLE_ENDIAN_ORDER) != 4) throw HeaderErr();
|
|
|
|
if (m_inQueue.Skip(2)!=2) throw HeaderErr(); // Skip extra flags and OS type
|
2015-11-05 06:59:46 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2017-05-12 19:09:21 +00:00
|
|
|
if (flags & FILENAME) // extract filename
|
|
|
|
{
|
2015-11-05 06:59:46 +00:00
|
|
|
do
|
2017-05-12 19:09:21 +00:00
|
|
|
{
|
2015-11-05 06:59:46 +00:00
|
|
|
if(!m_inQueue.Get(b)) throw HeaderErr();
|
2017-05-12 19:09:21 +00:00
|
|
|
if(b) m_filename.append( 1, (char)b );
|
|
|
|
}
|
2015-11-05 06:59:46 +00:00
|
|
|
while (b);
|
2017-05-12 19:09:21 +00:00
|
|
|
}
|
2015-11-05 06:59:46 +00:00
|
|
|
|
2017-05-12 19:09:21 +00:00
|
|
|
if (flags & COMMENTS) // extract comments
|
|
|
|
{
|
2015-11-05 06:59:46 +00:00
|
|
|
do
|
2017-05-12 19:09:21 +00:00
|
|
|
{
|
2015-11-05 06:59:46 +00:00
|
|
|
if(!m_inQueue.Get(b)) throw HeaderErr();
|
2017-05-12 19:09:21 +00:00
|
|
|
if(b) m_comment.append( 1, (char)b );
|
|
|
|
}
|
2015-11-05 06:59:46 +00:00
|
|
|
while (b);
|
2017-05-12 19:09:21 +00:00
|
|
|
}
|
2015-11-05 06:59:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2017-05-12 19:09:21 +00:00
|
|
|
const std::string& Gunzip::GetComment(bool throwOnEncodingError) const
|
|
|
|
{
|
|
|
|
if(throwOnEncodingError)
|
|
|
|
{
|
|
|
|
for(size_t i = 0; i < m_comment.length(); i++) {
|
|
|
|
const char c = m_comment[i];
|
|
|
|
if(!Is8859Character(c))
|
|
|
|
throw InvalidDataFormat("The comment is not ISO/IEC 8859-1 encoded");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_comment;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string& Gunzip::GetFilename(bool throwOnEncodingError) const
|
|
|
|
{
|
|
|
|
if(throwOnEncodingError)
|
|
|
|
{
|
|
|
|
for(size_t i = 0; i < m_filename.length(); i++) {
|
|
|
|
const char c = m_filename[i];
|
|
|
|
if(!Is8859Character(c))
|
|
|
|
throw InvalidDataFormat("The filename is not ISO/IEC 8859-1 encoded");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_filename;
|
|
|
|
}
|
|
|
|
|
2015-11-05 06:59:46 +00:00
|
|
|
NAMESPACE_END
|