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