Giulio
Giulio

Reputation: 11

Add multiple files from buffers to ZIP archive using libzip

I'm trying to use libzip in a program that needs to archive several data chunks in different files. At the moment I have a code similar to the following snippet, edited from in-memory.c example in libzip examples.

The zip file is correctly saved with the files inside, but each file contains garbage. Any help is appreciated.

bool push_files(zip_t* za) {
  for (int i = 0; i < 10; i++) {
    // Generate data
    std::stringstream ss;
    ss << "Test file #" << i;
    std::string a = ss.str();

    zip_source_t* source = zip_source_buffer(za, a.c_str(), a.size(), 0);

    if (source == NULL) {
      std::cerr << "error creating source: " << zip_strerror(za) << std::endl;
      return false;
    }

    // Add buffer with filename
    std::stringstream fname;
    fname << "TEST-" << i;
    a = fname.str();

    if (zip_file_add(za, a.c_str(), source, ZIP_FL_ENC_UTF_8) < 0) {
      std::cerr << "error adding source: " << zip_strerror(za) << std::endl;
      return false;
    }
  }
  return true;
}

int main() {
  zip_source_t* src;
  zip_error_t error;
  zip_t* za;

  zip_error_init(&error);

  if ((src = zip_source_buffer_create(NULL, 0, 1, &error)) == NULL) {
    std::cerr << "can't create source: " << zip_error_strerror(&error) << std::endl;
    zip_error_fini(&error);
    return 1;
  }

  if ((za = zip_open_from_source(src, ZIP_TRUNCATE, &error)) == NULL) {
    std::cerr << "can't open zip from source: " << zip_error_strerror(&error) << std::endl;
    zip_source_free(src);
    zip_error_fini(&error);
    return 1;
  }

  zip_error_fini(&error);

  zip_source_keep(src);

  if (!push_files(za))
    return -1;

  if (zip_close(za) < 0) {
    std::cerr << "can't close zip archive" << zip_strerror(za) << std::endl;
    return 1;
  }

  // ... omissis, save archive to file as in in-memory.c
}

Upvotes: 1

Views: 773

Answers (1)

zip_source_buffer does not copy the data out of the buffer - it just creates a zip_source_t which points to the same buffer. So you must keep the buffer alive until you're done adding the file.

Your code does not keep the buffer alive. The buffer you use is a.c_str() which is the data buffer of the string a. Fair enough, so far. But then before adding the file, you reassign the variable a = fname.str(); which (probably) frees that buffer and allocates a new one.

Solution: use a separate variable for the filename. Don't overwrite a until the file has been added.

Upvotes: 2

Related Questions