4#include "Stroika/Foundation/StroikaPreComp.h"
7#include "Stroika/Foundation/DataExchange/Archive/Zip/Private_minizip_.h"
9#include "Stroika/Foundation/Streams/MemoryStream.h"
16using namespace Stroika::Foundation::DataExchange::Archive;
17using namespace Stroika::Foundation::DataExchange::Archive::Writer;
19using namespace Stroika::Foundation::Memory;
20using namespace Stroika::Foundation::Streams;
22#if qStroika_HasComponent_zlib
23using namespace Stroika::Foundation::DataExchange::Archive::Zip::PrivateMinizip_;
29 void ThrowIfMinizipErr_ (
int err,
const String& doing)
31 if (err != UNZ_OK) [[unlikely]] {
35 struct MyZipLibOutStream_ final : zlib_filefunc64_def {
37#if qStroika_Foundation_Debug_AssertionsChecked
43 this->zopen64_file = [] (voidpf opaqueStream,
const void* ,
int ) -> voidpf {
44 MyZipLibOutStream_* myThis =
reinterpret_cast<MyZipLibOutStream_*
> (opaqueStream);
45#if qStroika_Foundation_Debug_AssertionsChecked
46 Assert (not myThis->fOpened_);
47 myThis->fOpened_ =
true;
51 this->zread_file = [] ([[maybe_unused]] voidpf opaqueStream, [[maybe_unused]] voidpf stream, [[maybe_unused]]
void* buf,
52 [[maybe_unused]] uLong size) -> uLong {
54 return static_cast<uLong
> (UNZ_PARAMERROR);
56 this->zwrite_file = [] (voidpf opaqueStream, [[maybe_unused]] voidpf stream,
const void* buf, uLong size) -> uLong {
57 Require (opaqueStream == stream);
58 MyZipLibOutStream_* myThis =
reinterpret_cast<MyZipLibOutStream_*
> (opaqueStream);
59#if qStroika_Foundation_Debug_AssertionsChecked
60 Assert (myThis->fOpened_);
62 myThis->fOutSteram_.Write (span{
reinterpret_cast<const byte*
> (buf), size});
63 return static_cast<uLong
> (size);
65 this->ztell64_file = [] (voidpf opaqueStream, [[maybe_unused]] voidpf stream) -> ZPOS64_T {
66 Require (opaqueStream == stream);
67 MyZipLibOutStream_* myThis =
reinterpret_cast<MyZipLibOutStream_*
> (opaqueStream);
68#if qStroika_Foundation_Debug_AssertionsChecked
69 Assert (myThis->fOpened_);
71 return myThis->fOutSteram_.GetOffset ();
73 this->zseek64_file = [] (voidpf opaqueStream, [[maybe_unused]] voidpf stream, ZPOS64_T offset,
int origin) ->
long {
74 Require (opaqueStream == stream);
75 MyZipLibOutStream_* myThis =
reinterpret_cast<MyZipLibOutStream_*
> (opaqueStream);
76#if qStroika_Foundation_Debug_AssertionsChecked
77 Assert (myThis->fOpened_);
80 case ZLIB_FILEFUNC_SEEK_SET:
81 myThis->fOutSteram_.Seek (offset);
83 case ZLIB_FILEFUNC_SEEK_CUR:
84 myThis->fOutSteram_.Seek (Streams::eFromCurrent, offset);
86 case ZLIB_FILEFUNC_SEEK_END:
87 myThis->fOutSteram_.Seek (Streams::eFromEnd, offset);
91 return UNZ_PARAMERROR;
95 this->zclose_file = [] ([[maybe_unused]] voidpf opaqueStream, [[maybe_unused]] voidpf stream) ->
int {
96#if qStroika_Foundation_Debug_AssertionsChecked
97 Require (opaqueStream == stream);
98 MyZipLibOutStream_* myThis =
reinterpret_cast<MyZipLibOutStream_*
> (opaqueStream);
99 Assert (myThis->fOpened_);
100 myThis->fOutSteram_.Flush ();
101 myThis->fOpened_ =
false;
105 this->zerror_file = [] (voidpf opaqueStream, [[maybe_unused]] voidpf stream) ->
int {
106 Require (opaqueStream == stream);
107 [[maybe_unused]] MyZipLibOutStream_* myThis =
reinterpret_cast<MyZipLibOutStream_*
> (opaqueStream);
108#if qStroika_Foundation_Debug_AssertionsChecked
109 Assert (myThis->fOpened_);
115 ~MyZipLibOutStream_ ()
117#if qStroika_Foundation_Debug_AssertionsChecked
118 Assert (not fOpened_);
125 struct MyRep_ final : Archive::Writer::IRep {
126 MyZipLibOutStream_ fOutZipStream_;
129 : fOutZipStream_{out}
130 , fZipFile_{zipOpen2_64 (
"", APPEND_STATUS_CREATE, nullptr, &fOutZipStream_)}
132 if (fZipFile_ ==
nullptr) [[unlikely]] {
140 zipClose (fZipFile_,
nullptr);
142 virtual void Add (
const String& fileName,
const span<const byte>& data)
override
145 const char* password =
nullptr;
146 uint32_t crcFile = password ==
nullptr ? 0 : crc32_z (0,
reinterpret_cast<const Bytef*
> (data.data ()), data.size ());
148 bool zip64 = data.size () > numeric_limits<uint16_t>::max ();
151 uInt opt_compress_level = 0;
152 constexpr int VERSIONMADEBY = (0x0);
154 constexpr uLong flagBase = 1 << 11;
155 ThrowIfMinizipErr_ (zipOpenNewFileInZip4_64 (fZipFile_, fileName.
AsUTF8<
string> ().c_str (), &zi, NULL, 0, NULL, 0,
156 NULL , (opt_compress_level != 0) ? Z_DEFLATED : 0, opt_compress_level, 0,
158 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, password, crcFile, VERSIONMADEBY, flagBase, zip64),
159 "zipOpenNewFileInZip4_64"sv);
161 [[maybe_unused]]
auto&& cleanup =
Finally ([
this] ()
noexcept { zipCloseFileInZip (fZipFile_); });
163 ThrowIfMinizipErr_ (zipWriteInFileInZip (fZipFile_,
reinterpret_cast<const Bytef*
> (data.data ()),
static_cast<unsigned int> (data.size ())),
164 "zipWriteInFileInZip"sv);
177 return Archive::Writer::Ptr{make_shared<MyRep_> (writeTo)};
#define RequireNotReached()
#define AssertNotReached()
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual T AsUTF8() const
OutputStream<>::Ptr is Smart pointer to a stream-based sink of data.
nonvirtual bool IsSeekable() const
Returns true iff this object was constructed with a seekable input stream rep.
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
auto Finally(FUNCTION &&f) -> Private_::FinallySentry< FUNCTION >