| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591 | //	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/>.#ifndef zipper_hh#define zipper_hh#include <stdexcept>#include <memory>#include <string>#include <vector>#include <cstdint>#include <sys/stat.h> // For mode_t#include <sys/time.h> // For timeval/**\mainpage libzipper C++ (de)compression library\section intro Introductionlibzipper offers a flexible C++ interface for reading compressed filesin multiple formats.<a href="http://www.codesrc.com/src/libzipper">Homepage</a>libzipper aims to provide applications a transparent method of accessingcompressed data. eg. libzipper is suited to reading XML config files thatare compressed to save space.libzipper is not a general-purpose archive management library, as itdoes not provide access to the filesystem attributes of each file.(ie. libzipper does not support the concepts of file owner, group orpermissions.\section formats Supported Formats<ul>	<li>gzip</li>	<li>zip</li></ul>\section example_read Reading a compressed file into memory\code#include <zipper.hh>#include <algorithm>#include <vector>class MemWriter : public zipper::Writer{public:	std::vector<uint8_t> data;	virtual void writeData(		zsize_t offset, zsize_t bytes, const uint8_t* inData)	{		data.resize(std::max(offset + bytes, data.size()));		std::copy(inData, inData + bytes, &data[offset]);	}	virtual zsize_t getSize() const { return data.size(); }};std::vector<uint8_t> readSavedGame(const std::string& filename){	// open the compressed input file. FileReader will throw an	// exception if an IO error occurs.	zipper::FileReader reader(filename);	MemWriter writer;	zipper::Decompressor decomp(reader);	std::vector<zipper::CompressedFilePtr> entries(decomp.getEntries());	if (!entries.empty())	{		// Uncompress the first file. Will pass-though data as-is if the		// file is not compressed.		entries.front()->decompress(writer);	}	return writer.data;}\endcode\section example_write Writing compressed files.\code#include <zipper.hh>#include <algorithm>#include <vector>class MemReader : public zipper::Reader{public:	MemReader(const vector<uint8_t>& data) : m_data(data) {}	virtual const std::string& getSourceName() const	{		static std::string Name("savedGame.dat");		return Name;	}	virtual const timeval& getModTime() const	{		return zipper::s_now;	}	virtual zsize_t getSize() const { return m_data.size(); }	virtual void readData(zsize_t offset, zsize_t bytes, uint8_t* dest) const	{		std::copy(&m_data[offset], &m_data[offset + bytes], dest);	}private:	std::vector<uint8_t> m_data;};void writeSavedGame(	const std::string& filename, const std::vector<uint8_t>& gameData){	zipper::FileWriter writer(filename);	zipper::Compressor comp(zipper::Container_zip, writer);	comp.addFile(MemReader(gameData));}\endcode*//// \namespace zipper/// \brief The zipper namespace contains the libzipper public API.namespace zipper{	/// \typedef zsize_t	/// zsize_t should be used exclusively when dealing with file offsets	/// and sizes to support large files (>4Gb).	///	/// Unlike size_t on some systems, zsize_t will be 64bit when compiling for	/// a 32bit target.	typedef uint64_t zsize_t;	/// \enum ContainerFormat	/// ContainerFormat enumerates the compressed archive formats supported	/// by libzipper.	///	/// An application can determine the supported formats by iterating	/// over the Container_begin to Container_end range. eg.	/// \code	/// for (int i = Container_begin; i < Container_end; ++i)	/// {	///     const Container& container(getContainer(ContainerFormat(i)));	/// }	/// \endcode	enum ContainerFormat	{		/// Iteration marker		Container_begin = 0,		/// No container (eg. plain text)		Container_none = 0,		/// ZIP		Container_zip,		/// gzip.		Container_gzip,		/// Iteration marker		Container_end	};	/// \struct Container	/// Provides libzipper capability details for a compressed archive	/// format.	/// \see getContainer	struct Container	{		/// \enum CapabilityBits allows a bitmask to be specified with a		/// combination of boolean flags.		enum CapabilityBits		{			/// Compression bit is set if the format is usable with Compressor			Compression = 1,			/// Decompression bit is set if the format is usable with			/// Decompressor			Decompression = 2,			/// EmbeddedFilenames bit is set if CompressedFile::getPath() is			/// supported			EmbeddedFilenames = 4,			/// Archive bit is set if multiple compressed files may exist in			/// a single container.			Archive = 8,			/// FileSize bit is set if the uncompressed size for each			/// compressed file is recorded in the container.			FileSize = 16		};		/// %Container Type		ContainerFormat format;		/// %Container Internet Media Type (aka MIME type).		/// eg. "application/zip"		std::string mediaType;		/// Bitmask comprised of CapabilityBits enum values.		uint32_t capabilities;	};	/// \brief When passed as a method parameter, it requests that the	/// current time be used instead.	extern const timeval s_now;	/// \brief Returns the capability details of the given format.	const Container& getContainer(ContainerFormat format);	/// \brief Base class for all exceptions thrown by libzipper	class Exception : public std::runtime_error	{	public:		/// Exception ctor		/// \param what A description of the error encountered.		Exception(const std::string& what);	};	/// \brief Exception thrown when the input data does not match	/// the expected Container format.	class FormatException : public Exception	{	public:		/// FormatException ctor		/// \param what A description of the error encountered.		FormatException(const std::string& what);	};	/// \brief Exception thrown when a Reader or Writer instance is unable	/// to satisfy an IO request due to an external error.	class IOException : public Exception	{	public:		/// IOException ctor		/// \param what A description of the error encountered.		IOException(const std::string& what);	};	/// \brief Exception thrown when an operation is requested on a compressed	/// archive that libzipper does not implement.	///	/// This exception may be thrown even if libzipper advertises general	/// support for the Container format.  eg. libzipper supports most	/// ZIP files, but an UnsupportedException will be thrown if given an	/// encrypted ZIP file.	class UnsupportedException : public Exception	{	public:		/// UnsupportedException ctor		/// \param what A description of the error encountered.		UnsupportedException(const std::string& what);	};	/// \brief Reader supplies input data to the compression/decompression	/// functions.	///	/// Normally, an application using libzipper provides the Reader	/// implementation. The implementation could supply data from files,	/// in-memory buffers, or it could be generated on-the-fly.	///	/// The Reader implementation must support random access, and must	/// determine at creation time the number of bytes available. The	/// Reader interface is not suitable for use with streaming data.	class Reader	{	public:		/// Reader dtor		virtual ~Reader();		/// Returns a name for this source of the data.		///		/// For file-based Reader implementations, this would normally be		/// the input filename.		virtual const std::string& getSourceName() const = 0;		/// Return the last-modified timestamp of the data.		/// If the special s_now value is returned, the current time should be		/// used instead.		virtual const timeval& getModTime() const = 0;		/// Returns the number of bytes available via readData()		///		/// \invariant getSize() is stable throughout the lifetime		/// of the Reader instance.		virtual zsize_t getSize() const = 0;		/// Copies data into the dest buffer		///		/// An exception must be thrown if it is not possible to copy the		/// requested data into the supplied buffer (eg. file IO error).		///		/// \pre offset + bytes <= getSize()		///		/// \param offset Number of bytes to skip at the front of the data		/// source.		/// \param bytes Number of bytes to copy		/// \param dest Destination buffer.		///		virtual void readData(			zsize_t offset, zsize_t bytes, uint8_t* dest			) const = 0;	};	/// \brief FileReader is a file-based implementation of the Reader	/// interface.	class FileReader : public Reader	{	public:		/// Read data from the supplied file.		FileReader(const std::string& filename);		/// Read data from the supplied file.		///		/// \param filename The value used by getSourceName(). This name		/// is arbitary, and does not need to be related to fd.		///		/// \param fd The descriptor to source data from.  The descriptor		/// must be open for reading, blocking, and seekable (ie. lseek(2)).		///		/// \param closeFd If true, fd will be closed by this object		/// when it is no longer needed.		FileReader(const std::string& filename, int fd, bool closeFd);		/// FileReader dtor		virtual ~FileReader();		/// Inherited from Reader		virtual const std::string& getSourceName() const;		/// Inherited from Reader		virtual const timeval& getModTime() const;		/// Inherited from Reader		virtual zsize_t getSize() const;		/// Inherited from Reader		virtual void readData(			zsize_t offset, zsize_t bytes, uint8_t* dest			) const;	private:		FileReader(const FileReader&);		FileReader& operator=(const FileReader&);		class FileReaderImpl;		FileReaderImpl* m_impl;	};	/// \typedef ReaderPtr	/// A shared pointer to a Reader	typedef std::shared_ptr<Reader> ReaderPtr;	/// \brief Writer accepts output data from the compression/decompression	/// functions.	///	/// Normally, an application using libzipper provides the Writer	/// implementation. The implementation could write data to files,	/// in-memory buffers, or it could be simply discarded.	///	/// The Writer implementation needs only to support sequential access.	class Writer	{	public:		/// Writer dtor		virtual ~Writer();		/// Returns the size of the written data.		virtual zsize_t getSize() const = 0;		/// Accepts output from libzipper		///		/// An exception must be thrown if it is not possible to accept		/// given data. (eg. file IO error).		///		/// \param offset Number of bytes to skip at the front of the data		/// source.  Skipped bytes will contain null characters if not already		/// assigned a value.		/// \param bytes Number of bytes in data		/// \param data Output from libzipper.		///		virtual void writeData(			zsize_t offset, zsize_t bytes, const uint8_t* data			) = 0;	};	/// \typedef WriterPtr	/// A shared pointer to a Writer	typedef std::shared_ptr<Writer> WriterPtr;	/// \brief FileWrter is a file-based implementation of the Writer	/// interface.	class FileWriter : public Writer	{	public:		/// Write data to the supplied file.		/// If the file already exists, it will be truncated.		/// If the file does not exist, it will be created with the		/// given permissions.		///		/// \param filename The file to open for writing.		///		/// \param createPermissions The permissions set on the file if it is to		/// be created.		///		/// \param modTime Set a specific modification time on the created file.		/// If the special s_now value is provided, the current time will be		/// used.		///		FileWriter(			const std::string& filename,			mode_t createPermissions = 0664,			const timeval& modTime = s_now);		/// Write data to the supplied file.		///		/// \param filename The filename reported in any exception error		/// messages. This name  is arbitary, and does not need to be		/// related to fd.		///		/// \param fd The descriptor to write data to.  The descriptor		/// must be open for writing in blocking mode.		///		/// \param closeFd If true, fd will be closed by this object		/// when it is no longer needed.		FileWriter(const std::string& filename, int fd, bool closeFd);		/// FileWriter dtor		virtual ~FileWriter();		/// Inherited from Writer		virtual zsize_t getSize() const;		/// Inherited from Writer		virtual void writeData(			zsize_t offset, zsize_t bytes, const uint8_t* data			);	private:		FileWriter(const FileWriter&);		FileWriter& operator=(const FileWriter&);		class FileWriterImpl;		FileWriterImpl* m_impl;	};	/// \brief CompressedFile represents an entry within a compressed archive.	///	/// CompressedFile instances are created by Decompressor, and allow	/// selectively extracting the contents of an archive.	class CompressedFile	{	public:		/// CompressedFile dtor		virtual ~CompressedFile();		/// Return true if decompress is likely to succeed.		///		/// isDecompressSupported may return false if libzipper doesn't know		/// how to deal with the compressed data. eg. encrypted files,		/// or ZIP files compressed with non-standard schemes.		virtual bool isDecompressSupported() const = 0;		/// Decompress the file, and store the results via the given		/// writer object.		virtual void decompress(Writer& writer) = 0;		/// Return the file path of the compressed file.		///		/// Unix-style path separaters ('/') are returned, even if the		/// archive was created under an alternative OS.		virtual const std::string& getPath() const = 0;		/// Return the compressed size of the file		///		/// getCompressedSize() will return -1 of the FileSize capability		/// bit of the container is false.		virtual zsize_t getCompressedSize() const = 0;		/// Return the uncompressed size of the file		///		/// The decompress method will pass exactly this number of bytes		/// to the Writer.		///		/// getUncompressedSize() will return -1 of the FileSize capability		/// bit of the container is false.		virtual zsize_t getUncompressedSize() const = 0;		/// Return the modification time of the original file		virtual const timeval& getModificationTime() const = 0;	};	/// \typedef CompressedFilePtr	/// A shared pointer to a CompressedFile	typedef std::shared_ptr<CompressedFile> CompressedFilePtr;	/// \brief Decompressor detects the compressed archive type of the data,	/// and creates suitable CompressedFile instances to access the compressed	/// data.	class Decompressor	{	public:		/// Create a decompressor from the data made available by reader.		Decompressor(const ReaderPtr& reader);		/// Create a decompressor from the data made available by reader.		///		/// \param reader must remain in scope for the lifetime of the		/// Decompressor, and lifetime of any CompressedFile objects returned		/// from getEntries()		Decompressor(Reader& reader);		/// Decompressor dtor		~Decompressor();		/// Return the detected Container type of the compressed archive.		ContainerFormat getContainerFormat() const;		/// Return CompressedFile entries to represent the file entries within		/// a compressed archive.		std::vector<CompressedFilePtr> getEntries() const;	private:		Decompressor(const Decompressor&);		Decompressor& operator=(const Decompressor&);		class DecompressorImpl;		DecompressorImpl* m_decompressor;	};	/// \brief Compressor creates a compressed archive from the supplied	/// Reader objects.	/// data.	class Compressor	{	public:		/// Create a Compressor to output the given compressed archived format		/// to writer.		/// \param writer destination of the compressed data		/// \param format determines the output archive file type to		/// create.		Compressor(ContainerFormat format, const WriterPtr& writer);		/// Create a Compressor to output the given compressed archived format		/// to writer.		///		/// \param writer is the destination of the compressed data.  writer		/// must remain in scope for the lifetime of the Compressor.		/// \param format determines the output archive file type to		/// create.		Compressor(ContainerFormat format, Writer& writer);		/// \brief Compressor dtor		///		/// Additional data may be passed to writer (given in ctor) to close		/// the compressed archive.		~Compressor();		/// Compress the data given by reader, and add it to the compressed		/// archive.		void addFile(const Reader& reader);		class CompressorImpl;	private:		Compressor(const Compressor&);		Compressor& operator=(const Compressor&);		CompressorImpl* m_compressor;	};}#endif
 |