cgiolibzip

How do I open a zip within a zip with libzip


I am trying to open a zip inside a zip

#include "zip.h"
#include "gtk.h"

zip_t *mainzipfile = zip_open(g_file_get_path(file), ZIP_CHECKCONS, &error);
zip_file_t *childzip = zip_fopen(mainzipfile, "child.zip", ZIP_RDONLY);// this segfaults
zip_file_t *childofchild = zip_fopen_index((zip_t*)childzip, 1, ZIP_RDONLY);

From what I am seeing childzip is not being read as a zip so its seg faulting. I tried casting because I know childzip is a zip file but the program is failing to see it as so

How do I set the zip_file_t as zip_t so that I can also extract its children


Solution

  • There is no generic support for opening a ZIP file inside a zip. To some extent, this is because reading ZIP file require direct access to the data (the ability to seek by offset). However, compressed ZIP files do not support the ability to read by offset. The only way to read a specific offset is to rewind the zip_file_t object, and skip over bytes.

    The leaves two possible scenarios (assuming the goal is to avoid extracting the inside zip into a file).

    1. Reading from uncompressed zip.

    In most cases, when a ZIP archive is placed into another ZIP archive, the zip program will realize that compression will not be effective, and will use the 'store' method. In those situation, it is possible to use zip_source_zip method to create (seekable) zip_source, which then be opened

    See https://libzip.org/documentation/zip_source.html

      // Find index
    zip_int64_t child_idx= zip_name_locate(main_zip, "child.zip", flags);
    
      // Create zip_source from the complete child.zip
    zip_source_t *src = zip_source_zip(archive, main_zip, child_idx, flags, 0, 0);
    
      // Create zip_t
    zip_t child_zip = zip_open_from_source(src, flags, &error);
      // work with the child zip
    
    

    2. Unzipping into memory.

    As an alternative, and assuming that the ZIP can fit in memory, consider reading the whole child zip into memory, than using the same context of zip_source to create a zip_source, which can be opened. In theory, simpler to implement.

    zip_stat (...) ;
    N = size_of_child_zip(...) ;
    
    zip_file_t *child_file = zip_fopen(main_zip, "child.zip", flags);
    
    char *buffer = calloc(1, N);
    zip_fread(child_file, buffer, N) ;
    
    zip_source = zip_source_buffer_create(buffer, N, ...)
    
      // Create zip_t
    zip_t child_zip = zip_open_from_source(zip_source, flags, &error);
      // work with the child zip