Bug 847479 - Allow to specify a chunk size on szip command line. r=nfroyd
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 06 Mar 2013 07:29:51 +0100
changeset 123915 88226153a994b19a9942b360fd93ea7f3bc83efd
parent 123914 9a66a2a47f2bb492b68b1a41e712d5f8e87fdc5c
child 123916 eeba894662b8ad803b1670bdef3b121a59e0edc7
push id1401
push userpastithas@mozilla.com
push dateThu, 07 Mar 2013 07:26:45 +0000
treeherderfx-team@ee4879719f78 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnfroyd
bugs847479
milestone22.0a1
Bug 847479 - Allow to specify a chunk size on szip command line. r=nfroyd
mozglue/linker/SeekableZStream.h
mozglue/linker/szip.cpp
--- a/mozglue/linker/SeekableZStream.h
+++ b/mozglue/linker/SeekableZStream.h
@@ -40,16 +40,22 @@ struct SeekableZStreamHeader: public Zip
   /* Size of last chunk (> 0, <= Chunk size) */
   le_uint16 lastChunkSize;
 
   /* windowBits value used when deflating */
   signed char windowBits;
 
   /* Padding */
   unsigned char unused;
+
+  /* Maximum supported size for chunkSize */
+  /* Can't use std::min here because it's not constexpr */
+  static const size_t maxChunkSize =
+    1 << ((sizeof(chunkSize) < sizeof(lastChunkSize) ?
+           sizeof(chunkSize) : sizeof(lastChunkSize)) - 1);
 };
 #pragma pack()
 
 MOZ_STATIC_ASSERT(sizeof(SeekableZStreamHeader) == 5 * 4,
                   "SeekableZStreamHeader should be 5 32-bits words");
 
 /**
  * Helper class used to decompress Seekable ZStreams.
--- a/mozglue/linker/szip.cpp
+++ b/mozglue/linker/szip.cpp
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <algorithm>
 #include <sys/stat.h>
 #include <cstring>
+#include <cstdlib>
 #include <zlib.h>
 #include <fcntl.h>
 #include <errno.h>
 #include "mozilla/Assertions.h"
 #include "mozilla/Scoped.h"
 #include "SeekableZStream.h"
 #include "Utils.h"
 #include "Logging.h"
@@ -58,21 +59,49 @@ public:
     return fd;
   }
 
 private:
   AutoCloseFD fd;
   bool writable;
 };
 
-static const size_t CHUNK = 16384;
+class SzipAction
+{
+public:
+  virtual int run(const char *name, Buffer &origBuf,
+                  const char *outName, Buffer &outBuf) = 0;
+
+  virtual ~SzipAction() {}
+};
+
+class SzipDecompress: public SzipAction
+{
+public:
+  int run(const char *name, Buffer &origBuf,
+          const char *outName, Buffer &outBuf);
+};
+
+class SzipCompress: public SzipAction
+{
+public:
+  int run(const char *name, Buffer &origBuf,
+          const char *outName, Buffer &outBuf);
+
+  SzipCompress(size_t aChunkSize)
+  : chunkSize(aChunkSize ? aChunkSize : 16384)
+  {}
+
+private:
+  size_t chunkSize;
+};
 
 /* Decompress a seekable compressed stream */
-int do_decompress(const char *name, Buffer &origBuf,
-                  const char *outName, Buffer &outBuf)
+int SzipDecompress::run(const char *name, Buffer &origBuf,
+                        const char *outName, Buffer &outBuf)
 {
   size_t origSize = origBuf.GetLength();
   if (origSize < sizeof(SeekableZStreamHeader)) {
     log("%s is not a seekable zstream", name);
     return 1;
   }
 
   SeekableZStream zstream;
@@ -89,58 +118,58 @@ int do_decompress(const char *name, Buff
 
   if (!zstream.Decompress(outBuf, 0, size))
     return 1;
 
   return 0;
 }
 
 /* Generate a seekable compressed stream. */
-int do_compress(const char *name, Buffer &origBuf,
-                const char *outName, Buffer &outBuf)
+int SzipCompress::run(const char *name, Buffer &origBuf,
+                      const char *outName, Buffer &outBuf)
 {
   size_t origSize = origBuf.GetLength();
   if (origSize == 0) {
     log("Won't compress %s: it's empty", name);
     return 1;
   }
   log("Size = %" PRIuSize, origSize);
 
   /* Expected total number of chunks */
-  size_t nChunks = ((origSize + CHUNK - 1) / CHUNK);
+  size_t nChunks = ((origSize + chunkSize - 1) / chunkSize);
 
   /* The first chunk is going to be stored after the header and the offset
    * table */
   size_t offset = sizeof(SeekableZStreamHeader) + nChunks * sizeof(uint32_t);
 
   /* Give enough room for the header and the offset table, and map them */
   if (!outBuf.Resize(origSize)) {
     log("Couldn't mmap %s: %s", outName, strerror(errno));
     return 1;
   }
 
   SeekableZStreamHeader *header = new (outBuf) SeekableZStreamHeader;
   le_uint32 *entry = reinterpret_cast<le_uint32 *>(&header[1]);
 
   /* Initialize header */
-  header->chunkSize = CHUNK;
+  header->chunkSize = chunkSize;
   header->totalSize = offset;
   header->windowBits = -15; // Raw stream, window size of 32k.
 
   /* Initialize zlib structure */
   z_stream zStream;
   memset(&zStream, 0, sizeof(zStream));
   zStream.avail_out = origSize - offset;
   zStream.next_out = static_cast<Bytef*>(outBuf) + offset;
 
   Bytef *origData = static_cast<Bytef*>(origBuf);
   size_t avail = 0;
   size_t size = origSize;
   while (size) {
-    avail = std::min(size, CHUNK);
+    avail = std::min(size, chunkSize);
 
     /* Compress chunk */
     int ret = deflateInit2(&zStream, 9, Z_DEFLATED, header->windowBits,
                            MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
     MOZ_ASSERT(ret == Z_OK);
     zStream.avail_in = avail;
     zStream.next_in = origData;
     ret = deflate(&zStream, Z_FINISH);
@@ -167,49 +196,84 @@ int do_compress(const char *name, Buffer
     return 1;
   }
 
   MOZ_ASSERT(header->nChunks == nChunks);
   log("Compressed size is %" PRIuSize, offset);
 
   /* Sanity check */
   Buffer tmpBuf;
-  if (do_decompress("buffer", outBuf, "buffer", tmpBuf))
+  SzipDecompress decompress;
+  if (decompress.run("buffer", outBuf, "buffer", tmpBuf))
     return 1;
 
   size = tmpBuf.GetLength();
   if (size != origSize) {
     log("Compression error: %" PRIuSize " != %" PRIuSize, size, origSize);
     return 1;
   }
   if (memcmp(static_cast<void *>(origBuf), static_cast<void *>(tmpBuf), size)) {
     log("Compression error: content mismatch");
     return 1;
   }
 
   return 0;
 }
 
+bool GetSize(const char *str, size_t *out)
+{
+  char *end;
+  MOZ_ASSERT(out);
+  errno = 0;
+  *out = strtol(str, &end, 10);
+  return (!errno && !*end);
+}
+
 int main(int argc, char* argv[])
 {
-  int (*func)(const char *, Buffer &, const char *, Buffer &) = do_compress;
-  char **firstArg = &argv[1];
+  mozilla::ScopedDeletePtr<SzipAction> action;
+  char **firstArg;
+  bool compress = true;
+  size_t chunkSize = 0;
 
-  if ((argc > 1) && strcmp(argv[1], "-d") == 0) {
-    func = do_decompress;
-    firstArg++;
-    argc--;
+  for (firstArg = &argv[1]; argc > 3; argc--, firstArg++) {
+    if (!firstArg[0] || firstArg[0][0] != '-')
+      break;
+    if (strcmp(firstArg[0], "-d") == 0) {
+      compress = false;
+    } else if (strcmp(firstArg[0], "-c") == 0) {
+      firstArg++;
+      argc--;
+      if (!firstArg[0])
+        break;
+      if (!GetSize(firstArg[0], &chunkSize) || !chunkSize ||
+          (chunkSize % 4096) ||
+          (chunkSize > SeekableZStreamHeader::maxChunkSize)) {
+        log("Invalid chunk size");
+        return 1;
+      }
+    }
   }
 
   if (argc != 3 || !firstArg[0] || !firstArg[1] ||
       (strcmp(firstArg[0], firstArg[1]) == 0)) {
-    log("usage: %s [-d] in_file out_file", argv[0]);
+    log("usage: %s [-d] [-c CHUNKSIZE] in_file out_file", argv[0]);
     return 1;
   }
 
+  if (compress) {
+    action = new SzipCompress(chunkSize);
+  } else {
+    if (chunkSize) {
+      log("-c is incompatible with -d");
+      return 1;
+    }
+    action = new SzipDecompress();
+  }
+
   FileBuffer origBuf;
   if (!origBuf.Init(firstArg[0])) {
     log("Couldn't open %s: %s", firstArg[0], strerror(errno));
     return 1;
   }
 
   struct stat st;
   int ret = fstat(origBuf.getFd(), &st);
@@ -228,10 +292,11 @@ int main(int argc, char* argv[])
 
   /* Create the compressed file */
   FileBuffer outBuf;
   if (!outBuf.Init(firstArg[1], true)) {
     log("Couldn't open %s: %s", firstArg[1], strerror(errno));
     return 1;
   }
 
-  return func(firstArg[0], origBuf, firstArg[1], outBuf);
+  ret = action->run(firstArg[0], origBuf, firstArg[1], outBuf);
+  return ret;
 }