#include "stdafx.h" #include "unzip.h" #include std::vector unzip(const void* src, usz size) { if (!src || !size) [[unlikely]] { return {}; } std::vector out(size * 6); z_stream zs{}; #ifndef _MSC_VER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif int res = inflateInit2(&zs, 16 + 15); if (res != Z_OK) { return {}; } #ifndef _MSC_VER #pragma GCC diagnostic pop #endif zs.avail_in = static_cast(size); zs.next_in = reinterpret_cast(src); zs.avail_out = static_cast(out.size()); zs.next_out = out.data(); while (zs.avail_in) { switch (inflate(&zs, Z_FINISH)) { case Z_OK: case Z_STREAM_END: break; case Z_BUF_ERROR: if (zs.avail_in) break; [[fallthrough]]; default: inflateEnd(&zs); return out; } if (zs.avail_in) { const auto cur_size = zs.next_out - out.data(); out.resize(out.size() + 65536); zs.avail_out = static_cast(out.size() - cur_size); zs.next_out = &out[cur_size]; } } out.resize(zs.next_out - out.data()); res = inflateEnd(&zs); return out; } bool unzip(const void* src, usz size, fs::file& out) { if (!src || !size || !out) { return false; } bool is_valid = true; constexpr usz BUFSIZE = 32ULL * 1024ULL; std::vector tempbuf(BUFSIZE); z_stream strm{}; strm.avail_in = ::narrow(size); strm.avail_out = static_cast(tempbuf.size()); strm.next_in = reinterpret_cast(src); strm.next_out = tempbuf.data(); #ifndef _MSC_VER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif int res = inflateInit(&strm); if (res != Z_OK) { return false; } #ifndef _MSC_VER #pragma GCC diagnostic pop #endif while (strm.avail_in) { res = inflate(&strm, Z_NO_FLUSH); if (res == Z_STREAM_END) break; if (res != Z_OK) is_valid = false; if (strm.avail_out) break; if (out.write(tempbuf.data(), tempbuf.size()) != tempbuf.size()) { is_valid = false; } strm.next_out = tempbuf.data(); strm.avail_out = static_cast(tempbuf.size()); } res = inflate(&strm, Z_FINISH); if (res != Z_STREAM_END) is_valid = false; if (strm.avail_out < tempbuf.size()) { const usz bytes_to_write = tempbuf.size() - strm.avail_out; if (out.write(tempbuf.data(), bytes_to_write) != bytes_to_write) { is_valid = false; } } res = inflateEnd(&strm); return is_valid; } std::vector zip(const void* src, usz size) { if (!src || !size) { return {}; } const uLong zsz = compressBound(::narrow(size)) + 256; std::vector out(zsz); z_stream zs{}; #ifndef _MSC_VER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif int res = deflateInit2(&zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY); if (res != Z_OK) { return {}; } #ifndef _MSC_VER #pragma GCC diagnostic pop #endif zs.avail_in = static_cast(size); zs.next_in = reinterpret_cast(src); zs.avail_out = static_cast(out.size()); zs.next_out = out.data(); res = deflate(&zs, Z_FINISH); switch (res) { case Z_OK: case Z_STREAM_END: if (zs.avail_out) { out.resize(zsz - zs.avail_out); } break; default: out.clear(); break; } deflateEnd(&zs); return out; } bool zip(const void* src, usz size, fs::file& out) { if (!src || !size || !out) { return false; } const std::vector zipped = zip(src, size); if (zipped.empty() || out.write(zipped.data(), zipped.size()) != zipped.size()) { return false; } return true; }