PageRenderTime 21ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/mordor/zip.h

http://github.com/mozy/mordor
C Header | 175 lines | 88 code | 22 blank | 65 comment | 0 complexity | 5ba9ee648fabd818dd85bc2fb6a59b41 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #ifndef __MORDOR_ZIP_H__
  2. #define __MORDOR_ZIP_H__
  3. // Copyright (c) 2010 - Mozy, Inc.
  4. #include <boost/noncopyable.hpp>
  5. #include <boost/shared_ptr.hpp>
  6. #include "exception.h"
  7. namespace Mordor {
  8. class CRC32Stream;
  9. class DeflateStream;
  10. class LimitedStream;
  11. class NotifyStream;
  12. class Stream;
  13. class Zip;
  14. struct CorruptZipException : virtual Exception {};
  15. struct UnsupportedCompressionMethodException : virtual Exception {};
  16. struct SpannedZipNotSupportedException : virtual Exception {};
  17. /// A single file within a Zip archive
  18. class ZipEntry
  19. {
  20. friend class Zip;
  21. private:
  22. ZipEntry(Zip &outer)
  23. : m_size(-1ll),
  24. m_compressedSize(-1ll),
  25. m_startOffset(0ll),
  26. m_outer(&outer),
  27. m_crc(0),
  28. m_flags(0x0800),
  29. m_extraFieldsLength(0),
  30. m_compressionMethod(8) // DEFLATED
  31. {}
  32. public:
  33. const std::string &filename() const { return m_filename; }
  34. void filename(const std::string &filename);
  35. const std::string &comment() const { return m_comment; }
  36. void comment(const std::string &comment);
  37. long long size() const { return m_size; }
  38. /// Providing size is optional; if it is not provided, Zip64 extensions are
  39. /// assumed
  40. void size(long long size);
  41. /// Supported method:
  42. /// 0 - no compression
  43. /// 8 - deflate
  44. unsigned short compressionMethod() const { return m_compressionMethod; }
  45. void compressionMethod(unsigned short method);
  46. long long compressedSize() const { return m_compressedSize; }
  47. /// @note Only one ZipEntry stream can be accessed at any one time from a
  48. /// single Zip; accessing the stream() of another ZipEntry will implicitly
  49. /// close the previously accessed one
  50. boost::shared_ptr<Stream> stream();
  51. boost::shared_ptr<Stream> stream() const;
  52. private:
  53. /// Writes the local file header (and extra field, if any)
  54. void commit();
  55. /// Flushes the deflate stream, and stores the CRC and actual sizes
  56. void close();
  57. /// Resets all fields
  58. void clear();
  59. private:
  60. std::string m_filename, m_comment;
  61. long long m_size, m_compressedSize;
  62. long long m_startOffset;
  63. mutable Zip *m_outer;
  64. unsigned int m_crc;
  65. unsigned short m_flags;
  66. unsigned short m_extraFieldsLength;
  67. unsigned short m_compressionMethod;
  68. };
  69. class ZipEntries : public std::multimap<std::string, ZipEntry>, boost::noncopyable
  70. {};
  71. /// @brief Zip Archive Format access
  72. ///
  73. /// Supports reading or writing a Zip, but not both at the same time. It fully
  74. /// supports non-seekable streams for both reading and writing, though many
  75. /// utilities (i.e. Windows) do not support Zips that weren't seekable when
  76. /// written. When writing a zip, it will automatically use Zip64 extensions
  77. /// if necessary, which means if you want to avoid Zip64 extensions, you need
  78. /// to provide the filesize (under 4GB) to ZipEntry prior to writing to
  79. /// ZipEntry::stream().
  80. ///
  81. /// Example of randomly accessing a zip file:
  82. /// @code
  83. /// Zip zip(stream);
  84. /// const ZipEntries &entries = zip.getAllEntries();
  85. /// ZipEntries::const_iterator it = entries.find("somefile.txt");
  86. /// transferStream(it->second.stream(), NullStream::get());
  87. /// @endcode
  88. /// Example of sequentially accessing a (possibly non-seekable) zip file:
  89. /// @code
  90. /// Zip zip(stream);
  91. /// ZipEntry const *entry = zip.getNextEntry();
  92. /// while (entry) {
  93. /// FileStream outputStream(entry->filename(), FileStream::WRITE,
  94. /// FileStream::OVERWRITE_OR_CREATE);
  95. /// transferStream(entry->stream, outputStream);
  96. /// entry = zip.getNextEntry();
  97. /// }
  98. /// @endcode
  99. /// Example of writing a (possibly non-seekable) zip file:
  100. /// @code
  101. /// Zip zip(stream);
  102. /// for (std::vector<std::string>::const_iterator it = files.begin();
  103. /// it != files.end();
  104. /// ++it) {
  105. /// ZipEntry &entry = zip.addEntry();
  106. /// entry.filename(*it);
  107. /// FileStream inputStream(*it, FileStream::READ);
  108. /// entry.size(inputStream.size());
  109. /// transferStream(inputStream, entry.stream());
  110. /// }
  111. /// zip.close();
  112. /// @endcode
  113. class Zip : boost::noncopyable
  114. {
  115. friend class ZipEntry;
  116. public:
  117. enum OpenMode
  118. {
  119. /// Opens the zip file for reading
  120. READ,
  121. /// Opens the zip file for writing (truncating existing files)
  122. WRITE,
  123. /// Infer the OpenMode. If the stream supportsWrite(), it will open in
  124. /// WRITE mode, otherwise READ
  125. INFER
  126. };
  127. public:
  128. Zip(boost::shared_ptr<Stream> stream, OpenMode mode = INFER);
  129. /// @pre stream->supportsWrite()
  130. ZipEntry &addFile();
  131. /// Writes the central directory
  132. /// @pre stream->supportsWrite()
  133. void close();
  134. /// @pre stream->supportsRead()
  135. ZipEntry const *getNextEntry();
  136. /// @pre stream->supportsRead()
  137. /// @pre stream->supportsSeek() && stream->supportsSize()
  138. const ZipEntries &getAllEntries();
  139. private:
  140. void onFileEOF();
  141. private:
  142. boost::shared_ptr<Stream> m_stream, m_fileStream;
  143. boost::shared_ptr<LimitedStream> m_uncompressedStream, m_compressedStream;
  144. boost::shared_ptr<DeflateStream> m_deflateStream;
  145. boost::shared_ptr<CRC32Stream> m_crcStream;
  146. boost::shared_ptr<NotifyStream> m_notifyStream;
  147. ZipEntry *m_currentFile;
  148. ZipEntry m_scratchFile;
  149. OpenMode m_mode;
  150. ZipEntries m_centralDirectory;
  151. };
  152. }
  153. #endif