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