| 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 Introduction
 
- libzipper offers a flexible C++ interface for reading compressed files
 
- in multiple formats.
 
- <a href="http://www.codesrc.com/src/libzipper">Homepage</a>
 
- libzipper aims to provide applications a transparent method of accessing
 
- compressed data. eg. libzipper is suited to reading XML config files that
 
- are compressed to save space.
 
- libzipper is not a general-purpose archive management library, as it
 
- does not provide access to the filesystem attributes of each file.
 
- (ie. libzipper does not support the concepts of file owner, group or
 
- permissions.
 
- \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
 
 
  |