Program Listing for File inflate.hpp¶
↰ Return to documentation for file (include/uitsl/fetch/inflate.hpp)
#pragma once
#ifndef UITSL_FETCH_INFLATE_HPP_INCLUDE
#define UITSL_FETCH_INFLATE_HPP_INCLUDE
#include <cstdio>
#include <string>
#include "zlib.h"
#include "../debug/err_audit.hpp"
#include "../nonce/ScopeGuard.hpp"
#include "../polyfill/filesystem.hpp"
#include "detect_gz.hpp"
#include "make_temp_filepath.hpp"
#define UITSL_INFLATE_CHUNK 16384
namespace uitsl {
/*
* Decompress from file source to file dest until stream ends or EOF.
*
* Adapted from
* - https://zlib.net/zlib_how.html
* - https://windrealm.org/tutorials/decompress-gzip-stream.php
* - https://stackoverflow.com/questions/10195343/copy-a-file-in-a-sane-safe-and-efficient-way
*/
inline void inflate(gzFile_s* source_handle, FILE* dest_handle) {
unsigned char buf[UITSL_INFLATE_CHUNK];
for (
int size = gzread(source_handle, buf, UITSL_INFLATE_CHUNK);
size > 0;
size = gzread(source_handle, buf, UITSL_INFLATE_CHUNK)
) std::fwrite(buf, 1, size, dest_handle);
}
/*
* Inflate from source path to destination path.
* @return destination path
*/
inline std::filesystem::path inflate(
const std::filesystem::path& source_path,
const std::filesystem::path& dest_path
) {
auto source_handle{ gzopen(source_path.c_str(), "rb") };
const uitsl::ScopeGuard source_guard{
[](){}, [&source_handle](){ gzclose( source_handle ); }
};
auto dest_handle{ std::fopen( dest_path.c_str(), "wb+" ) };
const uitsl::ScopeGuard dest_guard{
[](){}, [&dest_handle](){ std::fclose( dest_handle ); }
};
inflate( source_handle, dest_handle );
return dest_path;
}
/*
* Inflate from source path. Choose a destination path by stripping the gz
* extension. If the source path doesn't have gz extension or the path with
* the gz extension stripped exists, write to a temporary file.
* @return destination path
*/
inline std::filesystem::path inflate( const std::filesystem::path& source_path ) {
const auto with_extension_dropped
= std::filesystem::path(source_path).replace_extension("");
if (
source_path.extension() == ".gz"
&& !std::filesystem::exists( with_extension_dropped )
) return uitsl::inflate( source_path, with_extension_dropped );
else return uitsl::inflate( source_path, uitsl::make_temp_filepath() );
}
inline std::filesystem::path inflate_if_gzip(const std::filesystem::path& source) {
if ( uitsl::detect_gz( source ) ) {
return uitsl::inflate( source );
}
else return source;
}
} // namespace uitsl
#endif // #ifndef UITSL_FETCH_INFLATE_HPP_INCLUDE