2022-08-12 22:12:58 +02:00
|
|
|
|
|
|
|
#include "gzip.h"
|
|
|
|
|
|
|
|
#include "modules/exceptions.h"
|
|
|
|
|
|
|
|
#include <errno.h>
|
2022-09-01 00:47:19 +02:00
|
|
|
#if defined( Q_OS_WIN )
|
|
|
|
#include <QtZlib/zlib.h>
|
|
|
|
#else
|
|
|
|
#include <zlib.h>
|
|
|
|
#endif
|
2022-08-12 22:12:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
// avoid corruption of the data on Windows/MS-DOS systems
|
|
|
|
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <io.h>
|
|
|
|
#define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
|
|
|
|
#else
|
|
|
|
#define SET_BINARY_MODE(file)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// buffer size
|
|
|
|
#define CHUNK 16384
|
|
|
|
|
|
|
|
|
2024-01-07 19:14:56 +01:00
|
|
|
//! RAII class to handle s file resource
|
|
|
|
class FileHandler
|
|
|
|
{
|
|
|
|
FILE* file;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit FileHandler( const char* path, const char* mode )
|
|
|
|
: file{ nullptr }
|
|
|
|
{
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
fopen_s( &this->file, path, mode );
|
|
|
|
#else
|
|
|
|
this->file = fopen( path, mode );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
~FileHandler()
|
|
|
|
{
|
|
|
|
if ( this->valid() ) {
|
|
|
|
fclose( this->file );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-21 16:05:23 +01:00
|
|
|
Q_DISABLE_COPY_MOVE(FileHandler)
|
2024-01-07 19:14:56 +01:00
|
|
|
|
|
|
|
inline operator FILE*()
|
|
|
|
{
|
|
|
|
return this->file;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool valid() const noexcept
|
|
|
|
{
|
|
|
|
return this->file != NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool error() const noexcept
|
|
|
|
{
|
|
|
|
return ferror( this->file );
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void close()
|
|
|
|
{
|
|
|
|
if ( fclose( this->file ) ) {
|
|
|
|
throw GenericException( "Failed to close file pointer" );
|
|
|
|
}
|
|
|
|
this->file = nullptr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-04-11 23:12:06 +02:00
|
|
|
namespace GZutils
|
2022-08-12 22:12:58 +02:00
|
|
|
{
|
|
|
|
|
2023-04-11 23:12:06 +02:00
|
|
|
void readFile( const std::string& path, std::string& content )
|
2022-08-12 22:12:58 +02:00
|
|
|
{
|
2023-04-11 23:12:06 +02:00
|
|
|
bool successful{ true };
|
2022-08-12 22:12:58 +02:00
|
|
|
|
|
|
|
int ret;
|
|
|
|
unsigned have;
|
|
|
|
z_stream strm;
|
|
|
|
unsigned char in[CHUNK];
|
|
|
|
unsigned char out[CHUNK];
|
|
|
|
|
|
|
|
// allocate inflate state
|
|
|
|
strm.zalloc = Z_NULL;
|
|
|
|
strm.zfree = Z_NULL;
|
|
|
|
strm.opaque = Z_NULL;
|
|
|
|
strm.avail_in = 0;
|
|
|
|
strm.next_in = Z_NULL;
|
|
|
|
ret = inflateInit2( &strm, 15|32 );
|
|
|
|
if ( ret != Z_OK ) {
|
2023-04-11 23:12:06 +02:00
|
|
|
successful &= false;
|
2022-08-12 22:12:58 +02:00
|
|
|
}
|
|
|
|
|
2022-08-23 21:41:31 +02:00
|
|
|
if ( successful ) {
|
2024-01-07 19:14:56 +01:00
|
|
|
FileHandler file{ path.c_str(), "rb" };
|
|
|
|
if ( ! file.valid() ) {
|
2022-10-06 21:28:33 +02:00
|
|
|
// unable to open the file
|
|
|
|
return;
|
|
|
|
}
|
2024-01-07 19:14:56 +01:00
|
|
|
/*FILE *dest = fopen( out_path.c_str(), "wb" );*/
|
2022-08-12 22:12:58 +02:00
|
|
|
// decompress until deflate stream ends or end of file is reached
|
|
|
|
do {
|
2023-09-16 20:22:12 +02:00
|
|
|
strm.avail_in = static_cast<unsigned>(fread( in, 1, CHUNK, file ));
|
2024-01-07 19:14:56 +01:00
|
|
|
if ( file.error() ) {
|
2022-08-12 22:12:58 +02:00
|
|
|
// error reading
|
|
|
|
(void)inflateEnd( &strm );
|
2022-10-23 16:41:36 +02:00
|
|
|
/*successful = false;*/
|
2022-08-12 22:12:58 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( strm.avail_in == 0 ) {
|
|
|
|
// no more data to read
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
strm.next_in = in;
|
|
|
|
// run inflate() on input until output buffer is not full
|
|
|
|
do {
|
|
|
|
strm.avail_out = CHUNK;
|
|
|
|
strm.next_out = out;
|
|
|
|
ret = inflate( &strm, Z_NO_FLUSH );
|
|
|
|
switch (ret) {
|
|
|
|
case Z_NEED_DICT:
|
|
|
|
ret = Z_DATA_ERROR; // fall through
|
|
|
|
case Z_STREAM_ERROR: // <- state not clobbered
|
|
|
|
case Z_DATA_ERROR:
|
|
|
|
case Z_MEM_ERROR:
|
|
|
|
(void)inflateEnd( &strm );
|
2023-04-11 23:12:06 +02:00
|
|
|
successful &= false;
|
2022-08-12 22:12:58 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
have = CHUNK - strm.avail_out;
|
|
|
|
/*if ( fwrite(out, 1, have, dest) != have || ferror( dest ) ) {
|
|
|
|
(void)inflateEnd( &strm );
|
|
|
|
successful = false;
|
|
|
|
break;
|
|
|
|
}*/
|
2024-01-21 16:05:23 +01:00
|
|
|
for ( unsigned i{0u}; i<have; ++i ) {
|
2022-08-12 22:12:58 +02:00
|
|
|
content.push_back( out[i] );
|
|
|
|
}
|
|
|
|
|
|
|
|
} while ( strm.avail_out == 0 );
|
|
|
|
// done when inflate() says it's done
|
2022-08-23 21:41:31 +02:00
|
|
|
if ( ! successful ) {
|
2022-08-12 22:12:58 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while ( ret != Z_STREAM_END );
|
|
|
|
// clean up and return
|
|
|
|
(void)inflateEnd( &strm );
|
|
|
|
successful = (ret == Z_STREAM_END) ? true : false;
|
2024-01-07 19:14:56 +01:00
|
|
|
file.close(); // throws GenericException on failure
|
2022-08-12 22:12:58 +02:00
|
|
|
}
|
2023-04-11 23:12:06 +02:00
|
|
|
if ( content.empty() ) {
|
2022-08-12 22:12:58 +02:00
|
|
|
// probably not a gzip compressed file
|
2022-08-22 21:17:30 +02:00
|
|
|
throw(""); // do not implement
|
2022-08-12 22:12:58 +02:00
|
|
|
}
|
2022-08-23 21:41:31 +02:00
|
|
|
if ( ! successful ) {
|
2023-04-11 23:12:06 +02:00
|
|
|
content.clear();
|
2022-08-12 22:12:58 +02:00
|
|
|
}
|
|
|
|
}
|
2023-04-11 23:12:06 +02:00
|
|
|
|
|
|
|
} // namespace GZutils
|