]> localhost Git - libzipper.git/commitdiff
zip and gzip complete. Debian packaging in progress.
authorMichael McMaster <email@michaelmcmaster.name>
Fri, 20 May 2011 14:24:27 +0000 (00:24 +1000)
committerMichael McMaster <email@michaelmcmaster.name>
Fri, 20 May 2011 14:24:27 +0000 (00:24 +1000)
18 files changed:
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/docs [new file with mode: 0644]
debian/libzipper-dev.dirs [new file with mode: 0644]
debian/libzipper-dev.install [new file with mode: 0644]
debian/libzipper1.dirs [new file with mode: 0644]
debian/libzipper1.install [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debian/source/format [new file with mode: 0644]
deflate.cc [moved from Unzip.cc with 55% similarity]
deflate.hh [moved from Unzip.hh with 80% similarity]
gzip.cc [moved from Ungzip.cc with 100% similarity]
gzip.hh [moved from Ungzip.hh with 100% similarity]
libzipper-1.0.pc.in [new file with mode: 0644]
zip.cc [moved from Zip.cc with 100% similarity]
zip.hh [moved from Zip.hh with 100% similarity]

diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..be1dcb7
--- /dev/null
@@ -0,0 +1,5 @@
+libzipper (1.0.0-1) unstable; urgency=low
+
+  * Initial release (Closes: #nnnn)  <nnnn is the bug number of your ITP>
+
+ -- Michael McMaster <michael@codesrc.com>  Sat, 21 May 2011 00:01:11 +1000
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..d57a16e
--- /dev/null
@@ -0,0 +1,27 @@
+Source: libzipper
+Priority: extra
+Maintainer: Michael McMaster <michael@codesrc.com>
+Build-Depends: debhelper (>= 7.0.50~), autotools-dev, cdbs, zlib1g-dev
+Standards-Version: 3.9.1
+Section: libs
+Homepage: http://www.codesrc.com/src/libzipper
+#Vcs-Git: git://git.debian.org/collab-maint/libzipper.git
+#Vcs-Browser: http://git.debian.org/?p=collab-maint/libzipper.git;a=summary
+
+Package: libzipper-dev
+Section: libdevel
+Architecture: any
+Depends: libzipper (= ${binary:Version})
+Homepage: http://www.codesrc.com/src/libzipper
+Description: A C++ interface for reading compressed.
+ libzipper offers a flexible C++ interface for reading compressed files in
+ multiple formats.
+
+Package: libzipper
+Section: libs
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Homepage: http://www.codesrc.com/src/libzipper
+Description: A C++ interface for reading compressed.
+ libzipper offers a flexible C++ interface for reading compressed files in
+ multiple formats.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..5ae1531
--- /dev/null
@@ -0,0 +1,40 @@
+Format: http://dep.debian.net/deps/dep5
+Upstream-Name: libzipper
+Source: <url://example.com>
+
+Files: *
+Copyright: <years> <put author's name and email here>
+           <years> <likewise for another author>
+License: GPL-3.0+
+
+Files: debian/*
+Copyright: 2011 Michael McMaster <michael@codesrc.com>
+License: GPL-3.0+
+
+License: GPL-3.0+
+ This program 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.
+ .
+ This package 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
+
+# Please choose a license for your packaging work. If the program you package
+# uses a mainstream license, using the same license is the safest choice.
+# Please avoid to pick license terms that are more restrictive than the
+# packaged work, as it may make Debian's contributions unacceptable upstream.
+# If you just want it to be GPL version 3, leave the following line in.
+
+and is licensed under the GPL version 3, see above.
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
diff --git a/debian/docs b/debian/docs
new file mode 100644 (file)
index 0000000..50bd824
--- /dev/null
@@ -0,0 +1,2 @@
+NEWS
+README
diff --git a/debian/libzipper-dev.dirs b/debian/libzipper-dev.dirs
new file mode 100644 (file)
index 0000000..4418816
--- /dev/null
@@ -0,0 +1,2 @@
+usr/lib
+usr/include
diff --git a/debian/libzipper-dev.install b/debian/libzipper-dev.install
new file mode 100644 (file)
index 0000000..3c996c8
--- /dev/null
@@ -0,0 +1,6 @@
+usr/include/*
+usr/lib/lib*.a
+usr/lib/lib*.so
+usr/lib/pkgconfig/*
+usr/lib/*.la
+usr/share/pkgconfig/*
diff --git a/debian/libzipper1.dirs b/debian/libzipper1.dirs
new file mode 100644 (file)
index 0000000..6845771
--- /dev/null
@@ -0,0 +1 @@
+usr/lib
diff --git a/debian/libzipper1.install b/debian/libzipper1.install
new file mode 100644 (file)
index 0000000..d0dbfd1
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/lib*.so.*
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..114ab44
--- /dev/null
@@ -0,0 +1,4 @@
+#!/usr/bin/make -f
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/autotools.mk
+
diff --git a/debian/source/format b/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
similarity index 55%
rename from Unzip.cc
rename to deflate.cc
index 7845d9195111c53ea0c883ccebdb4b1c949d2170..0819b80c7f8e06daaaa98d464c9c5cddca70e2c4 100644 (file)
--- a/Unzip.cc
@@ -16,7 +16,8 @@
 //     along with libzipper.  If not, see <http://www.gnu.org/licenses/>.
 
 #include "zipper.hh"
-#include "Unzip.hh"
+#include "zip.hh"
+#include "util.hh"
 
 #include <zlib.h>
 
@@ -30,31 +31,6 @@ using namespace zipper;
 
 namespace
 {
-       template<typename T>
-       uint32_t
-       read32(const T& zipData, size_t pos)
-       {
-               // Read 4 bytes in little-endian order.
-               // Return results in host-endian.
-               return uint32_t(
-                       zipData[pos] |
-                       (uint32_t(zipData[pos+1]) << 8) |
-                       (uint32_t(zipData[pos+2]) << 16) |
-                       (uint32_t(zipData[pos+3]) << 24)
-                       );
-       }
-
-       uint16_t
-       read16(const std::vector<uint8_t>& zipData, size_t pos)
-       {
-               // Read 2 bytes in little-endian order.
-               // Return results in host-endian.
-               return uint16_t(
-                       zipData[pos] |
-                       (uint16_t(zipData[pos+1]) << 8)
-                       );
-       }
-
        struct InflateDeleter
        {
        public:
@@ -68,6 +44,19 @@ namespace
                z_stream* m_stream;
        };
 
+       struct DeflateDeleter
+       {
+       public:
+               DeflateDeleter(z_stream* stream) : m_stream(stream) {}
+               ~DeflateDeleter()
+               {
+                       deflateEnd(m_stream);
+
+               }
+       private:
+               z_stream* m_stream;
+       };
+
        class FileEntry : public CompressedFile
        {
        public:
@@ -126,7 +115,7 @@ namespace
                        m_reader->readData(
                                m_localHeaderOffset, MinRecordBytes, &localRecord[0]
                                );
-                       if (read32(localRecord, 0) != Signature)
+                       if (read32_le(localRecord, 0) != Signature)
                        {
                                throw FormatException("Invalid local ZIP record");
                        }
@@ -134,8 +123,8 @@ namespace
                        // Don't trust the lengths for filename and extra content read from
                        // the central records.  At least for extra, these DO differ for
                        // unknown reasons
-                       zsize_t filenameLength(read16(localRecord, 26));
-                       zsize_t extraLength(read16(localRecord, 28));
+                       zsize_t filenameLength(read16_le(localRecord, 26));
+                       zsize_t extraLength(read16_le(localRecord, 28));
 
                        zsize_t startCompressedBytes(
                                m_localHeaderOffset +
@@ -254,9 +243,9 @@ namespace
                                                        12 - stream.avail_in,
                                                        &dataDescriptor[stream.avail_in]);
                                        }
-                                       m_crc = read32(dataDescriptor, 0);
-                                       m_compressedSize = read32(dataDescriptor, 4);
-                                       m_uncompressedSize = read32(dataDescriptor, 8);
+                                       m_crc = read32_le(dataDescriptor, 0);
+                                       m_compressedSize = read32_le(dataDescriptor, 4);
+                                       m_uncompressedSize = read32_le(dataDescriptor, 8);
                                }
 
                                if (crc != m_crc)
@@ -323,20 +312,20 @@ namespace
                ssize_t pos(bufSize - MinRecordBytes);
                for (; pos >= 0; --pos)
                {
-                       recordFound = (read32(buffer, pos) == Signature);
+                       recordFound = (read32_le(buffer, pos) == Signature);
                        break;
                }
 
                if (recordFound)
                {
-                       if (read16(buffer, pos + 4) != 0)
+                       if (read16_le(buffer, pos + 4) != 0)
                        {
                                throw UnsupportedException("Spanned disks not supported");
                        }
 
-                       centralDirectoryBytes = read32(buffer, pos + 12);
-                       centralDirectoryOffset = read32(buffer, pos + 16);
-                       centralDirectoryEntries = read16(buffer, pos + 10);
+                       centralDirectoryBytes = read32_le(buffer, pos + 12);
+                       centralDirectoryOffset = read32_le(buffer, pos + 16);
+                       centralDirectoryEntries = read16_le(buffer, pos + 10);
                }
                return recordFound;
        }
@@ -374,23 +363,23 @@ namespace
                std::vector<CompressedFilePtr> entries;
                while ((pos + MinRecordBytes) < buffer.size())
                {
-                       if (read32(buffer, pos) != Signature)
+                       if (read32_le(buffer, pos) != Signature)
                        {
                                // Unknown record type.
                                pos += 1;
                                continue;
                        }
 
-                       uint16_t versionNeeded(read16(buffer, pos + 6));
-                       uint16_t gpFlag(read16(buffer, pos + 8));
-                       uint16_t compressionMethod(read16(buffer, pos + 10));
-                       uint32_t crc(read32(buffer, pos + 16));
-                       uint32_t compressedSize(read32(buffer, pos + 20));
-                       uint32_t uncompressedSize(read32(buffer, pos + 24));
-                       size_t fileNameLen(read16(buffer, pos + 28));
-                       size_t extraLen(read16(buffer, pos + 30));
-                       size_t commentLen(read16(buffer, pos + 32));
-                       uint32_t localHeaderOffset(read32(buffer, pos + 42));
+                       uint16_t versionNeeded(read16_le(buffer, pos + 6));
+                       uint16_t gpFlag(read16_le(buffer, pos + 8));
+                       uint16_t compressionMethod(read16_le(buffer, pos + 10));
+                       uint32_t crc(read32_le(buffer, pos + 16));
+                       uint32_t compressedSize(read32_le(buffer, pos + 20));
+                       uint32_t uncompressedSize(read32_le(buffer, pos + 24));
+                       size_t fileNameLen(read16_le(buffer, pos + 28));
+                       size_t extraLen(read16_le(buffer, pos + 30));
+                       size_t commentLen(read16_le(buffer, pos + 32));
+                       uint32_t localHeaderOffset(read32_le(buffer, pos + 42));
 
                        if ((fileNameLen + extraLen + commentLen + MinRecordBytes + pos) >
                                buffer.size()
@@ -424,6 +413,248 @@ namespace
                }
                return entries;
        }
+
+}
+
+
+void
+zipper::zip(
+       const std::string& filename,
+       const Reader& reader,
+       const WriterPtr& writer,
+       ZipFileRecord& outRecord)
+{
+       enum Constants
+       {
+               ChunkSize = 64*1024,
+               WindowBits = 15,
+               CRC32Pos = 14
+       };
+
+       static uint8_t Header[] =
+       {
+               0x50, 0x4b, 0x03, 0x04,  // Header
+               20, // Version (2.0)
+               0, // File attributes
+               0,0, // gp flag.
+               8,0, // deflate method
+               0,0, // file time
+               0,0, // file date
+               0,0,0,0, // CRC32
+               0,0,0,0, // Compressed size
+               0,0,0,0 // Uncompressed size
+       };
+
+       zsize_t outPos(writer->getSize());
+       outRecord.localHeaderOffset = outPos;
+       outRecord.filename = filename;
+
+       // Write header
+       {
+               uint8_t buffer[ChunkSize];
+               memcpy(buffer, Header, sizeof(Header));
+               zsize_t pos(sizeof(Header));
+
+               std::string::size_type filenameSize(filename.size());
+               if (filenameSize > (ChunkSize - pos))
+               {
+                       filenameSize = ChunkSize - pos;
+               }
+               buffer[pos++] = filenameSize & 0xff;
+               buffer[pos++] = (filenameSize >> 8);
+               buffer[pos++] = 0; // extra field len
+               buffer[pos++] = 0; // extra field len
+               memcpy(buffer + pos, filename.data(), filenameSize);
+               pos += filenameSize;
+               writer->writeData(outPos, pos, &buffer[0]);
+               outPos += pos;
+       }
+
+       // Write compressed data
+
+       uint8_t inChunk[ChunkSize];
+       uint8_t outChunk[ChunkSize];
+
+       outRecord.uncompressedSize = 0;
+       outRecord.compressedSize = 0;
+
+       z_stream stream;
+       stream.zalloc = NULL;
+       stream.zfree = NULL;
+       stream.opaque = NULL;
+       int zlibErr(
+               deflateInit2(
+                       &stream,
+                       Z_DEFAULT_COMPRESSION,
+                       Z_DEFLATED,
+                       -WindowBits,
+                       MAX_MEM_LEVEL,
+                       Z_DEFAULT_STRATEGY)
+                       );
+
+       assert(zlibErr == Z_OK);
+       DeflateDeleter deleter(&stream);
+       stream.next_in = NULL;
+       stream.avail_in = 0;
+
+       zsize_t pos(0);
+       zsize_t end(reader.getSize());
+       outRecord.crc32 = crc32(0, NULL, 0);
+
+       while (pos < end)
+       {
+               if (stream.avail_in == 0)
+               {
+                       stream.avail_in =
+                               std::min(zsize_t(ChunkSize), end - pos);
+                       reader.readData(
+                               pos, stream.avail_in, &inChunk[0]);
+                       stream.next_in = reinterpret_cast<Bytef*>(&inChunk);
+                       pos += stream.avail_in;
+                       outRecord.uncompressedSize += stream.avail_in;
+                       outRecord.crc32 =
+                               crc32(outRecord.crc32, stream.next_in, stream.avail_in);
+               }
+
+               stream.next_out = reinterpret_cast<Bytef*>(&outChunk);
+               stream.avail_out = sizeof(outChunk);
+
+               zlibErr = deflate(&stream, (pos < end) ? Z_NO_FLUSH : Z_FINISH);
+
+               if (zlibErr == Z_STREAM_END)
+               {
+                       if (pos < end)
+                       {
+                               assert(!"zlib buffer unexpectedly empty");
+                               std::terminate();
+                       }
+               }
+               else if (zlibErr != Z_OK)
+               {
+                       throw FormatException("Corrupt Data");
+               }
+
+               zsize_t bytesToWrite(sizeof(outChunk) - stream.avail_out);
+               writer->writeData(
+                               outPos,
+                               bytesToWrite,
+                               &outChunk[0]);
+               outPos += bytesToWrite;
+               outRecord.compressedSize += bytesToWrite;
+       }
+
+       // Go back and complete the header.
+       uint8_t trailer[12];
+       write32_le(outRecord.crc32, &trailer[0]);
+       write32_le(outRecord.compressedSize, &trailer[4]);
+       write32_le(outRecord.uncompressedSize, &trailer[8]);
+       writer->writeData(
+               outRecord.localHeaderOffset + CRC32Pos, sizeof(trailer), &trailer[0]);
+}
+
+void
+zipper::zipFinalise(
+       const std::vector<ZipFileRecord>& records,
+       const WriterPtr& writer)
+{
+       enum Constants
+       {
+               ChunkSize = 64*1024
+       };
+
+       static uint8_t FileHeader[] =
+       {
+               0x50, 0x4b, 0x01, 0x02,  // Header
+               20, 0x00, // Version (2.0)
+               20, 0x00, // Version Needed to extract (2.0)
+               0,0, // gp flag.
+               8,0, // deflate method
+               0,0, // file time
+               0,0 // file date
+       };
+
+       zsize_t outPos(writer->getSize());
+       uint32_t centralDirOffset(outPos);
+
+       for (size_t i = 0; i < records.size(); ++i)
+       {
+               uint8_t buffer[ChunkSize];
+               memcpy(buffer, FileHeader, sizeof(FileHeader));
+               zsize_t pos(sizeof(FileHeader));
+
+               write32_le(records[i].crc32, &buffer[pos]);
+               pos += 4;
+
+               write32_le(records[i].compressedSize, &buffer[pos]);
+               pos += 4;
+
+               write32_le(records[i].uncompressedSize, &buffer[pos]);
+               pos += 4;
+
+               std::string::size_type filenameSize(records[i].filename.size());
+               if (filenameSize > (ChunkSize - pos))
+               {
+                       filenameSize = ChunkSize - pos;
+               }
+               buffer[pos++] = filenameSize & 0xff;
+               buffer[pos++] = (filenameSize >> 8);
+               buffer[pos++] = 0; // extra field len
+               buffer[pos++] = 0; // extra field len
+
+               buffer[pos++] = 0; // file comment len
+               buffer[pos++] = 0; // file comment len
+
+               buffer[pos++] = 0; // disk number
+               buffer[pos++] = 0; // disk number
+
+               buffer[pos++] = 0; // internal file attributes
+               buffer[pos++] = 0; // internal file attributes
+
+               buffer[pos++] = 0; // external file attributes
+               buffer[pos++] = 0; // external file attributes
+               buffer[pos++] = 0; // external file attributes
+               buffer[pos++] = 0; // external file attributes
+
+               write32_le(records[i].localHeaderOffset, &buffer[pos]);
+               pos += 4;
+
+               memcpy(buffer + pos, records[i].filename.data(), filenameSize);
+               pos += filenameSize;
+
+               writer->writeData(outPos, pos, &buffer[0]);
+               outPos += pos;
+       }
+
+       uint32_t centralDirSize(writer->getSize() - centralDirOffset);
+
+       {
+               // End-of-directory record.
+               static uint8_t EndDirectory[] =
+               {
+                       0x50, 0x4b, 0x05, 0x06,  // Header
+                       0x00, 0x00, // Disk num
+                       0x00, 0x00 // Disk with central dir
+               };
+               uint8_t buffer[ChunkSize];
+               memcpy(buffer, EndDirectory, sizeof(EndDirectory));
+               zsize_t pos(sizeof(EndDirectory));
+
+               buffer[pos++] = records.size() & 0xff; // Entries on this disk
+               buffer[pos++] = records.size() >> 8;
+               buffer[pos++] = records.size() & 0xff; // Total entries
+               buffer[pos++] = records.size() >> 8;
+
+               write32_le(centralDirSize, &buffer[pos]);
+               pos += 4;
+               write32_le(centralDirOffset, &buffer[pos]);
+               pos += 4;
+
+               buffer[pos++] = 0; // Zip comment length
+               buffer[pos++] = 0; // Zip comment length
+
+               writer->writeData(outPos, pos, &buffer[0]);
+               outPos += pos;
+       }
 }
 
 std::vector<CompressedFilePtr>
similarity index 80%
rename from Unzip.hh
rename to deflate.hh
index ab78f9fbc25ebbb3f97eecf331df75ea3164a31f..9acf552963891f9fde4ab31aee4b85f12ab0dc13 100644 (file)
--- a/Unzip.hh
 
 namespace zipper
 {
-       bool isZip(const ReaderPtr& reader);
+       bool isGzip(const ReaderPtr& reader);
 
-       std::vector<CompressedFilePtr> unzip(const ReaderPtr& reader);
+       void gzip(
+               const std::string& filename,
+               const Reader& reader,
+               const WriterPtr& writer);
+
+       std::vector<CompressedFilePtr> ungzip(const ReaderPtr& reader);
 }
 
similarity index 100%
rename from Ungzip.cc
rename to gzip.cc
similarity index 100%
rename from Ungzip.hh
rename to gzip.hh
diff --git a/libzipper-1.0.pc.in b/libzipper-1.0.pc.in
new file mode 100644 (file)
index 0000000..6e192d7
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libzipper
+Description: libzipper offers a flexible C++ interface for reading compressed files in multiple formats.
+Requires: zlib
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lzipper-1.0
+Cflags: -I${includedir}
diff --git a/Zip.cc b/zip.cc
similarity index 100%
rename from Zip.cc
rename to zip.cc
diff --git a/Zip.hh b/zip.hh
similarity index 100%
rename from Zip.hh
rename to zip.hh