Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Libzip - read file contents from zip

Tags:

c++

c

zip

I using libzip to work with zip files and everything goes fine, until i need to read file from zip I need to read just a whole text files, so it will be great to achieve something like PHP "file_get_contents" function.
To read file from zip there is a function
"int zip_fread(struct zip_file *file, void *buf, zip_uint64_t nbytes)".
Main problem what i don't know what size of buf must be and how many nbytes i must read (well i need to read whole file, but files have different size). I can just do a big buffer to fit them all and read all it's size, or do a while loop until fread return -1 but i don't think it's rational option.

like image 492
Aristarhys Avatar asked Feb 04 '12 10:02

Aristarhys


2 Answers

You can try using zip_stat to get file size. http://linux.die.net/man/3/zip_stat

like image 83
zch Avatar answered Oct 23 '22 20:10

zch


I haven't used the libzip interface but from what you write it seems to look very similar to a file interface: once you got a handle to the stream you keep calling zip_fread() until this function return an error (ir, possibly, less than requested bytes). The buffer you pass in us just a reasonably size temporary buffer where the data is communicated.

Personally I would probably create a stream buffer for this so once the file in the zip archive is set up it can be read using the conventional I/O stream methods. This would look something like this:

struct zipbuf: std::streambuf {
    zipbuf(???): file_(???) {}
private:
    zip_file* file_;
    enum { s_size = 8196 };
    char buffer_[s_size];
    int underflow() {
        int rc(zip_fread(this->file_, this->buffer_, s_size));
        this->setg(this->buffer_, this->buffer_,
                        this->buffer_ + std::max(0, rc));
        return this->gptr() == this->egptr()
            ? traits_type::eof()
            : traits_type::to_int_type(*this->gptr());
    }
};

With this stream buffer you should be able to create an std::istream and read the file into whatever structure you need:

zipbuf buf(???);
std::istream in(&buf);
...

Obviously, this code isn't tested or compiled. However, when you replace the ??? with whatever is needed to open the zip file, I'd think this should pretty much work.

like image 3
Dietmar Kühl Avatar answered Oct 23 '22 19:10

Dietmar Kühl