| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 | 
							- //	Copyright (C) 2011 Michael McMaster <michael@codesrc.com>
 
- //
 
- //	This file is part of libzipper.
 
- //
 
- //	libzipper is free software: you can redistribute it and/or modify
 
- //	it under the terms of the GNU General Public License as published by
 
- //	the Free Software Foundation, either version 3 of the License, or
 
- //	(at your option) any later version.
 
- //
 
- //	libzipper is distributed in the hope that it will be useful,
 
- //	but WITHOUT ANY WARRANTY; without even the implied warranty of
 
- //	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
- //	GNU General Public License for more details.
 
- //
 
- //	You should have received a copy of the GNU General Public License
 
- //	along with libzipper.  If not, see <http://www.gnu.org/licenses/>.
 
- #include "zipper.hh"
 
- #include "gzip.hh"
 
- #include "util.hh"
 
- #include "deflate.hh"
 
- #include <algorithm>
 
- #include <cassert>
 
- #include <iostream>
 
- #include <vector>
 
- #include <string.h>
 
- using namespace zipper;
 
- namespace
 
- {
 
- 	size_t
 
- 	findNull(const std::vector<uint8_t>& zipData, size_t start)
 
- 	{
 
- 		if (start >= zipData.size())
 
- 		{
 
- 			throw FormatException("Unexpected end-of-file");
 
- 		}
 
- 		while (zipData[start] != 0)
 
- 		{
 
- 			++start;
 
- 			if (start >= zipData.size())
 
- 			{
 
- 				throw FormatException("Unexpected end-of-file");
 
- 			}
 
- 		}
 
- 		return start;
 
- 	}
 
- 	class FileEntry : public CompressedFile
 
- 	{
 
- 	public:
 
- 		FileEntry(
 
- 			const ReaderPtr& reader,
 
- 			zsize_t dataOffset,
 
- 			const std::string& filename,
 
- 			time_t modTime
 
- 			) :
 
- 			m_reader(reader),
 
- 			m_dataOffset(dataOffset),
 
- 			m_fileName(filename)
 
- 		{
 
- 			m_modTime.tv_sec = modTime;
 
- 			m_modTime.tv_usec = 0;
 
- 		}
 
- 		virtual bool isDecompressSupported() const
 
- 		{
 
- 			return true;
 
- 		}
 
- 		virtual const std::string& getPath() const
 
- 		{
 
- 			return m_fileName;
 
- 		}
 
- 		virtual zsize_t getCompressedSize() const { return -1; }
 
- 		virtual zsize_t getUncompressedSize() const { return -1; }
 
- 		virtual const timeval& getModificationTime() const { return m_modTime; }
 
- 		virtual void decompress(Writer& writer)
 
- 		{
 
- 			zsize_t endCompressedBytes = m_reader->getSize() - 8; // CRC+ISIZE
 
- 			zsize_t inPos(m_dataOffset);
 
- 			zsize_t outPos(0);
 
- 			uint32_t crc(0);
 
- 			inflate(
 
- 				m_reader,
 
- 				writer,
 
- 				inPos,
 
- 				endCompressedBytes,
 
- 				outPos,
 
- 				crc);
 
- 			uint8_t crcBuffer[4];
 
- 			m_reader->readData(inPos, sizeof(crcBuffer), &crcBuffer[0]);
 
- 			uint32_t savedCRC = read32_le(&crcBuffer[0]);
 
- 			if (savedCRC != crc)
 
- 			{
 
- 				throw FormatException("Corrupt Data (CRC Failure)");
 
- 			}
 
- 		}
 
- 	private:
 
- 		ReaderPtr m_reader;
 
- 		zsize_t m_dataOffset;
 
- 		std::string m_fileName;
 
- 		timeval m_modTime;
 
- 	};
 
- }
 
- std::vector<zipper::CompressedFilePtr>
 
- zipper::ungzip(const ReaderPtr& reader)
 
- {
 
- 	enum
 
- 	{
 
- 		MaxHeader = 64*1024  // Artifical limit to simplify code
 
- 	};
 
- 	if (!isGzip(reader))
 
- 	{
 
- 		throw FormatException("Invalid gzip file");
 
- 	}
 
- 	std::vector<uint8_t> header(
 
- 		std::min(reader->getSize(), zsize_t(MaxHeader)));
 
- 	reader->readData(0, header.size(), &header[0]);
 
- 	if (header[2] != 8) // "deflate" method
 
- 	{
 
- 		throw UnsupportedException("Unknown gzip compression method");
 
- 	}
 
- 	bool fextra = (header[3] & 4) != 0;
 
- 	bool fname = (header[3] & 8) != 0;
 
- 	bool fcomment = (header[3] & 0x10) != 0;
 
- 	bool fhcrc = (header[3] & 2) != 0;
 
- 	time_t modTime = read32_le(&header[4]);
 
- 	size_t offset(10);
 
- 	if (fextra)
 
- 	{
 
- 		if (offset + 2 > header.size())
 
- 		{
 
- 			throw FormatException("Unexpected end-of-file");
 
- 		}
 
- 		uint16_t fextraBytes(read16_le(header, offset));
 
- 		offset += 2;
 
- 		offset += fextraBytes;
 
- 	}
 
- 	std::string embeddedName(reader->getSourceName());
 
- 	if (fname)
 
- 	{
 
- 		size_t nullOffset(findNull(header, offset));
 
- 		embeddedName =
 
- 			std::string(
 
- 				reinterpret_cast<char*>(&header[offset]), nullOffset - offset);
 
- 		offset = nullOffset + 1;
 
- 	}
 
- 	if (fcomment)
 
- 	{
 
- 		size_t nullOffset(findNull(header, offset));
 
- 		offset = nullOffset + 1;
 
- 	}
 
- 	if (fhcrc)
 
- 	{
 
- 		offset += 2;
 
- 	}
 
- 	if (offset >= header.size())
 
- 	{
 
- 		throw FormatException("Unexpected end-of-file");
 
- 	}
 
- 	std::vector<CompressedFilePtr> result;
 
- 	result.push_back(
 
- 		CompressedFilePtr(
 
- 			new FileEntry(reader, offset, embeddedName, modTime)));
 
- 	return result;
 
- }
 
- bool
 
- zipper::isGzip(const ReaderPtr& reader)
 
- {
 
- 	enum Constants
 
- 	{
 
- 		MinFileBytes = 18, // Header + CRC + size
 
- 		ID1 = 0x1f,
 
- 		ID2 = 0x8b
 
- 	};
 
- 	bool isGzip(false);
 
- 	if (reader->getSize() >= MinFileBytes)
 
- 	{
 
- 		uint8_t magic[2];
 
- 		reader->readData(0, sizeof(magic), &magic[0]);
 
- 		isGzip = (magic[0] == ID1) && (magic[1] == ID2);
 
- 	}
 
- 	return isGzip;
 
- }
 
- void
 
- zipper::gzip(
 
- 	const std::string& filename,
 
- 	const Reader& reader,
 
- 	const WriterPtr& writer)
 
- {
 
- 	enum Constants
 
- 	{
 
- 		ChunkSize = 64*1024,
 
- 		WindowBits = 15
 
- 	};
 
- 	static uint8_t Header[] =
 
- 	{
 
- 		0x1f, 0x8b, // ID
 
- 		0x08, // deflate
 
- 		0x8, // Flags (filename set)
 
- 		0x0, 0x0, 0x0, 0x0, // mtime
 
- 		0x0, // Extra flags
 
- 		0xff  // OS
 
- 	};
 
- 	zsize_t outPos(writer->getSize());
 
- 	// Write header
 
- 	{
 
- 		uint8_t buffer[ChunkSize];
 
- 		memcpy(buffer, Header, sizeof(Header));
 
- 		write32_le(reader.getModTime().tv_sec, &buffer[4]); // modtime
 
- 		zsize_t pos(sizeof(Header));
 
- 		zsize_t filenameSize(filename.size());
 
- 		if (filenameSize > (ChunkSize - pos - 1))
 
- 		{
 
- 			filenameSize = ChunkSize - pos - 1;
 
- 		}
 
- 		std::copy(&filename[0], &filename[filenameSize], &buffer[pos]);
 
- 		pos += filenameSize;
 
- 		buffer[pos++] = '\0';
 
- 		writer->writeData(outPos, pos, &buffer[0]);
 
- 		outPos += pos;
 
- 	}
 
- 	// Compress data
 
- 	zsize_t uncompressedSize(0);
 
- 	zsize_t compressedSize(0);
 
- 	uint32_t crc(0);
 
- 	deflate(reader, writer, outPos, uncompressedSize, compressedSize, crc);
 
- 	// Write trailer.
 
- 	uint8_t trailer[8];
 
- 	write32_le(crc, &trailer[0]);
 
- 	write32_le(reader.getSize(), &trailer[4]);
 
- 	writer->writeData(outPos, sizeof(trailer), &trailer[0]);
 
- }
 
 
  |