Skip to content

Instantly share code, notes, and snippets.

@chenshuo
Created July 12, 2016 18:19
Show Gist options
  • Save chenshuo/23a3c94e2f4b14dd493aee16af7421e4 to your computer and use it in GitHub Desktop.
Save chenshuo/23a3c94e2f4b14dd493aee16af7421e4 to your computer and use it in GitHub Desktop.
inplace gunzip
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <zlib.h>
#include <boost/noncopyable.hpp>
#include <deque>
// FIXME: re-implement this with disk buffer.
class Buffer : boost::noncopyable
{
public:
Buffer() : total_(0) {}
void append(const char* data, int len)
{
total_ += len;
buffer_.insert(buffer_.end(), data, data+len);
}
int take(char* data, int len)
{
int x = std::min<int>(len, buffer_.size());
std::copy(buffer_.begin(), buffer_.begin() + x, data);
buffer_.erase(buffer_.begin(), buffer_.begin() + x);
return x;
}
private:
std::deque<char> buffer_;
int64_t total_;
};
class InPlaceGunzip : boost::noncopyable
{
public:
InPlaceGunzip(const char* filename)
: file_(::open(filename, O_RDWR)),
gzfile_(::gzdopen(file_, "rb"))
{
assert(file_ >= 0);
assert(gzfile_ != NULL);
}
~InPlaceGunzip()
{
gzclose(gzfile_);
}
void unzip()
{
Buffer queue;
char buf[64*1024];
int nr = 0;
int64_t last_off = 0;
while ( (nr = gzread(gzfile_, buf, sizeof buf)) > 0) {
queue.append(buf, nr);
// int64_t tell = gztell(gzfile_);
int64_t off = gzoffset(gzfile_);
int avail = std::min<int>(off - last_off, sizeof buf);
int x = queue.take(buf, avail);
int nw = pwrite(file_, buf, x, last_off);
assert(x == nw);
last_off += nw;
}
while ( (nr = queue.take(buf, sizeof buf)) > 0) {
int nw = pwrite(file_, buf, nr, last_off);
assert(nr == nw);
last_off += nw;
}
}
private:
int file_;
gzFile gzfile_;
};
int main(int argc, char* argv[])
{
if (argc > 1)
{
InPlaceGunzip unzip(argv[1]);
unzip.unzip();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment