Skip to content

Instantly share code, notes, and snippets.

@gregoryfmartin
Created July 3, 2020 18:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gregoryfmartin/21c156d7be36ece1545c855d5d1dedc2 to your computer and use it in GitHub Desktop.
Save gregoryfmartin/21c156d7be36ece1545c855d5d1dedc2 to your computer and use it in GitHub Desktop.
Demonstration of libzip and SFML to decompress and use a file in SFML
///////////////////////////////////////////////////////////////////////////////
//
// libzip-decompress-file.cpp
//
// Written by Gregory F Martin
//
//
// This source code is public domain. It references a Zip Archive which is
// not included in this Gist.
//
//
// This program leverages two libraries: libzip and SFML.
//
//
// This program demonstrates how to leverage libzip to decompress a Zip archive
// at runtime, enumerate and iterate through the files within the specified
// archive, and during said iteration extrapolate the bits from a given entry
// into a SFML construct that could be used by it.
//
///////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <zip.h>
#include <SFML/Graphics.hpp>
int main() {
///////////////////////////////////////////////////////////////////////////
//
// SFML Setup
//
///////////////////////////////////////////////////////////////////////////
sf::RenderWindow window(sf::VideoMode(800, 600), "");
sf::Texture img;
sf::Sprite s;
///////////////////////////////////////////////////////////////////////////
//
// Attempt to open the Zip Archive from the disk
//
///////////////////////////////////////////////////////////////////////////
int zfile_err = 0;
zip_t* zfile = zip_open("./sample.zip", ZIP_RDONLY, &zfile_err);
if (nullptr == zfile) {
std::cerr << zfile_err << std::endl;
exit (zfile_err);
}
///////////////////////////////////////////////////////////////////////////
//
// Enumerate the entries in the Zip Archive
//
///////////////////////////////////////////////////////////////////////////
zip_int64_t num_entries = zip_get_num_entries(zfile, ZIP_FL_UNCHANGED);
if (-1 == num_entries) {
std::cerr << -1 << std::endl;
exit (-1);
} else {
std::cout << "Number of entries in the zip file are " << num_entries << std::endl;
}
///////////////////////////////////////////////////////////////////////////
//
// Iterate through the Zip Archive entries using good old probe
//
///////////////////////////////////////////////////////////////////////////
for (zip_int64_t i = 0; i < num_entries; i++) {
///////////////////////////////////////////////////////////////////////
//
// Obtain relevant metadata about the file at the specified index
// within the Zip Archive
//
///////////////////////////////////////////////////////////////////////
zip_stat_t sb;
if (0 == zip_stat_index(zfile, i, ZIP_FL_UNCHANGED, &sb)) {
///////////////////////////////////////////////////////////////////
//
// Create a data buffer equal to the decompressed size of the file
// at the specified index.
//
// Information on this can be found at the following page:
// https://libzip.org/documentation/zip_stat.html
//
// https://libzip.org/documentation/zip_fread.html
//
///////////////////////////////////////////////////////////////////
char* buf = new char[sb.size];
zip_int64_t r = zip_fread(zip_fopen_index(zfile, i, ZIP_FL_UNCHANGED), buf, sb.size);
///////////////////////////////////////////////////////////////////
//
// zip_fread returns the number of bytes read. Because
// zip_stat_t.size represents the decompressed size of the file,
// we want to confirm that the number of bytes read from the read
// op matches what we're expected based off the metadata. If we've
// read a disparate number of bytes, it's likely that there's some
// corruption in either the archive or the actual file itself.
// Either way, it's unsafe to use this file if the bytes read don't
// match the expected size.
//
///////////////////////////////////////////////////////////////////
if (sb.size != r) {
std::cerr << "Failed to read the appropriate amount of memory for this file." << std::endl;
exit (-99);
}
///////////////////////////////////////////////////////////////////
//
// Create a SFML Texture using the data buffer that we created
// earlier with the raw data from the decompressed file.
//
///////////////////////////////////////////////////////////////////
img.loadFromMemory(buf, (std::size_t)sb.size);
img.setSmooth(true);
}
}
///////////////////////////////////////////////////////////////////////////
//
// Modify the SFML Sprite to use the Texture from before and apply some
// transforms. Note that the call to setScale is because the test image
// used is quite large and, when drawn, extends way beyond the 800x600
// viewport.
//
///////////////////////////////////////////////////////////////////////////
s.setTexture(img);
s.setScale(0.15f, 0.15f);
s.setPosition(25.0f, 25.0f);
///////////////////////////////////////////////////////////////////////////
//
// Attempt to close the Zip Archive. This could be performed earlier, but
// it's here now.
//
///////////////////////////////////////////////////////////////////////////
int closeres = zip_close(zfile);
if (0 > closeres) {
zip_error_t* close_err = zip_get_error(zfile);
std::cerr << close_err->zip_err << " " << close_err->sys_err << std::endl;
exit (close_err->zip_err);
}
///////////////////////////////////////////////////////////////////////////
//
// Very basic SFML event loop. The program will end when the user clicks
// the Close button on the window.
//
///////////////////////////////////////////////////////////////////////////
while(window.isOpen()) {
sf::Event ev;
while(window.pollEvent(ev)) {
if(sf::Event::Closed == ev.type) {
window.close();
}
}
window.clear();
window.draw(s);
window.display();
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment