Program Listing for File inflate.hpp

Return to documentation for file (include/uitsl/utility/inflate.hpp)

#pragma once
#ifndef UITSL_UTILITY_INFLATE_HPP_INCLUDE
#define UITSL_UTILITY_INFLATE_HPP_INCLUDE

#include <cstdio>
#include <cstdlib>
#include <string>

#include "zlib.h"

#include "../debug/err_audit.hpp"
#include "../nonce/ScopeGuard.hpp"
#include "../polyfill/filesystem.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
 */
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, UITSL_INFLATE_CHUNK, dest_handle);

}

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;

}

std::filesystem::path inflate( const std::filesystem::path& source_path ) {
  // adapted from https://en.wikipedia.org/wiki/Mkstemp
  char dest_path[] = "/tmp/uitsl_inflate_dataXXXXXX";
  uitsl::err_audit(! mkstemp(dest_path) );
  return inflate( source_path, dest_path );
}

} // namespace uitsl

#endif // #ifndef UITSL_UTILITY_INFLATE_HPP_INCLUDE