// gzip.cpp - originally written and placed in the public domain by Wei Dai #include "pch.h" #include "gzip.h" #include "argnames.h" NAMESPACE_BEGIN(CryptoPP) // 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(c); return (cc >= 32 && cc <= 126) || (cc >= 160); } void Gzip::IsolatedInitialize(const NameValuePairs ¶meters) { Deflator::IsolatedInitialize(parameters); ConstByteArrayParameter v; if (parameters.GetValue(Name::FileName(), v)) m_filename.assign(reinterpret_cast(v.begin()), v.size()); if (parameters.GetValue(Name::Comment(), v)) m_comment.assign(reinterpret_cast(v.begin()), v.size()); m_filetime = parameters.GetIntValueWithDefault(Name::FileTime(), 0); } void Gzip::WritePrestreamHeader() { m_totalLen = 0; m_crc.Restart(); int flags = 0; if(!m_filename.empty()) flags |= FILENAME; if(!m_comment.empty()) flags |= COMMENTS; AttachedTransformation()->Put(MAGIC1); AttachedTransformation()->Put(MAGIC2); AttachedTransformation()->Put(DEFLATED); AttachedTransformation()->Put((byte)flags); // general flag AttachedTransformation()->PutWord32(m_filetime, LITTLE_ENDIAN_ORDER); // time stamp byte extra = static_cast((GetDeflateLevel() == 1) ? FAST : ((GetDeflateLevel() == 9) ? SLOW : 0)); AttachedTransformation()->Put(extra); AttachedTransformation()->Put(GZIP_OS_CODE); // 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); } 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); 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; } // ************************************************************* Gunzip::Gunzip(BufferedTransformation *attachment, bool repeat, int propagation) : Inflator(attachment, repeat, propagation), m_length(0), m_filetime(0) { } void Gunzip::ProcessPrestreamHeader() { m_length = 0; m_crc.Restart(); m_filetime = 0; m_filename.clear(); m_comment.clear(); 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.Get(b) || (b != DEFLATED)) throw HeaderErr(); // skip CM flag if (!m_inQueue.Get(flags)) throw HeaderErr(); if (flags & (ENCRYPTED | CONTINUED)) throw HeaderErr(); 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 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) // extract filename { do { if(!m_inQueue.Get(b)) throw HeaderErr(); if(b) m_filename.append( 1, (char)b ); } while (b); } if (flags & COMMENTS) // extract comments { do { if(!m_inQueue.Get(b)) throw HeaderErr(); if(b) m_comment.append( 1, (char)b ); } 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(); } 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; } NAMESPACE_END