Stroika Library 3.0d20
 
Loading...
Searching...
No Matches
Archive/7z/Reader.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
8
9#include "Reader.h"
10
11#if qStroika_HasComponent_LZMA
12extern "C" {
13#include <lzma/7z.h>
14#include <lzma/7zCrc.h>
15}
16#endif
17
18#if qStroika_HasComponent_LZMA && defined(_MSC_VER)
19// Use #pragma comment lib instead of explicit entry in the lib entry of the project file
20#pragma comment(lib, "lzma.lib")
21#endif
22
23using namespace Stroika::Foundation;
27using namespace Stroika::Foundation::DataExchange::Archive;
28using namespace Stroika::Foundation::Streams;
29
31using std::byte;
32
33#if qStroika_HasComponent_LZMA
34namespace {
35 struct InitOnce_ {
36 InitOnce_ ()
37 {
38 ::CrcGenerateTable ();
39 }
40 } sInitOnce_;
41}
42
43namespace {
44
45 struct Rep_ : Reader::IRep {
46 private:
47 // could do smarter/block allocation or arena allocation, but KISS for now
48 static void* Alloc_ (void* /*p*/, size_t size)
49 {
50 Require (size > 0);
51 return new byte[size];
52 }
53 static void Free_ (void* /*p*/, void* address)
54 {
55 delete[] reinterpret_cast<byte*> (address);
56 }
57
58 private:
59 mutable ISzAlloc fAllocImp_{};
60 mutable ISzAlloc fAllocTempImp_{};
61 CSzArEx fDB_{};
62 struct MyISeekInStream : ISeekInStream {
64 MyISeekInStream (const Streams::InputStream::Ptr<byte>& in)
65 : fInStream_{in}
66 {
67 Read = Stream_Read_;
68 Seek = Stream_Seek_;
69 }
70 static SRes Stream_Read_ (void* pp, void* buf, size_t* size)
71 {
72 MyISeekInStream* pThis = (MyISeekInStream*)pp;
73 size_t sz = pThis->fInStream_.ReadBlocking (span{reinterpret_cast<byte*> (buf), *size}).size ();
74 Assert (sz <= *size);
75 *size = sz;
76 return SZ_OK; // not sure on EOF/underflow?SZ_ERROR_READ
77 }
78 static SRes Stream_Seek_ (void* pp, Int64* pos, ESzSeek origin)
79 {
80 MyISeekInStream* pThis = (MyISeekInStream*)pp;
81 switch (origin) {
82 case SZ_SEEK_SET:
83 *pos = pThis->fInStream_.Seek (*pos);
84 break;
85 case SZ_SEEK_CUR:
86 *pos = pThis->fInStream_.Seek (eFromCurrent, *pos);
87 break;
88 case SZ_SEEK_END:
89 *pos = pThis->fInStream_.Seek (eFromEnd, *pos);
90 break;
91 default:
93 return SZ_ERROR_UNSUPPORTED;
94 }
95 return SZ_OK;
96 }
97 };
98 MyISeekInStream fInSeekStream_;
99 mutable CLookToRead fLookStream_{};
100
101 public:
102 Rep_ (const Streams::InputStream::Ptr<byte>& in)
103 : fInSeekStream_{in}
104 {
105 fAllocImp_ = ISzAlloc{Alloc_, Free_};
106 fAllocTempImp_ = ISzAlloc{Alloc_, Free_};
107
108 ::SzArEx_Init (&fDB_);
109
110 ::LookToRead_CreateVTable (&fLookStream_, false);
111 fLookStream_.realStream = &fInSeekStream_;
112
113 SRes ret{};
114 if ((ret = ::SzArEx_Open (&fDB_, &fLookStream_.s, &fAllocImp_, &fAllocTempImp_)) != SZ_OK) {
115 // throw
116 throw "bad";
117 }
118 }
119 ~Rep_ ()
120 {
121 ::SzArEx_Free (&fDB_, &fAllocImp_);
122 }
123 virtual Set<String> GetContainedFiles () const override
124 {
125 Set<String> result;
126 for (unsigned int i = 0; i < fDB_.NumFiles; ++i) {
127 if (not SzArEx_IsDir (&fDB_, i)) {
128 size_t nameLen = ::SzArEx_GetFileNameUtf16 (&fDB_, i, nullptr);
129 if (nameLen < 1) {
130 break;
131 }
132 StackBuffer<char16_t> fileName{Memory::eUninitialized, nameLen};
133 [[maybe_unused]] size_t z = ::SzArEx_GetFileNameUtf16 (&fDB_, i, reinterpret_cast<UInt16*> (&fileName[0]));
134 result.Add (String{&fileName[0]});
135 }
136 }
137 return result;
138 }
139 virtual Memory::BLOB GetData (const String& fileName) const override
140 {
141 UInt32 idx = GetIdx_ (fileName);
142 if (idx == -1) {
143 throw "bad"; //filenotfound
144 }
145
146 byte* outBuffer = 0; // it must be 0 before first call for each new archive
147 UInt32 blockIndex = 0xFFFFFFFF; // can have any value if outBuffer = 0
148 size_t outBufferSize = 0; // can have any value if outBuffer = 0
149
150 size_t offset{};
151 size_t outSizeProcessed{};
152
153 [[maybe_unused]] auto&& cleanup = Execution::Finally ([&outBuffer, this] () noexcept { IAlloc_Free (&fAllocImp_, outBuffer); });
154
155 SRes ret;
156 if ((ret = ::SzArEx_Extract (&fDB_, &fLookStream_.s, idx, &blockIndex, reinterpret_cast<uint8_t**> (&outBuffer), &outBufferSize,
157 &offset, &outSizeProcessed, &fAllocImp_, &fAllocTempImp_)) != SZ_OK) {
158 throw "bad";
159 }
160 return Memory::BLOB (outBuffer + offset, outBuffer + offset + outSizeProcessed);
161 }
162 UInt32 GetIdx_ (const String& fn) const
163 {
164 // could create map to lookup once and maintain
165 for (UInt32 i = 0; i < fDB_.NumFiles; ++i) {
166 if (not SzArEx_IsDir (&fDB_, i)) {
167 size_t nameLen = SzArEx_GetFileNameUtf16 (&fDB_, i, nullptr);
168 if (nameLen < 1) {
169 break;
170 }
171 StackBuffer<char16_t> fileName{Memory::eUninitialized, nameLen};
172 [[maybe_unused]] size_t z = ::SzArEx_GetFileNameUtf16 (&fDB_, i, reinterpret_cast<UInt16*> (&fileName[0]));
173 if (String{&fileName[0]} == fn) {
174 return i;
175 }
176 }
177 }
178 return static_cast<UInt32> (-1);
179 }
180 };
181}
182
183/*
184 ********************************************************************************
185 ***************** DataExchange::Archive::_7z::Reader::New **********************
186 ********************************************************************************
187 */
188Archive::Reader::Ptr Archive::_7z::Reader::New (const Streams::InputStream::Ptr<byte>& readFrom)
189{
190 return Archive::Reader::Ptr{make_shared<Rep_> (readFrom)};
191}
192
193#endif
#define AssertNotReached()
Definition Assertions.h:355
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
nonvirtual void Add(ArgByValueType< value_type > item)
Definition Set.inl:138
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from ...