Created
July 3, 2020 18:38
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// 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