BmnRoot 26.10.0-18-g4e3414f9
Software framework of the BM@N experiment
Loading...
Searching...
No Matches
BmnFileReaderXzLzma.cxx
Go to the documentation of this file.
1// headers from this target
2#include "BmnFileReaderXzLzma.h"
3
4#include "BmnDefinitions.h"
5// std:: headers
6#include <cassert>
7#include <filesystem>
8// the main XZ LZMA2 header
9#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
10// This header holds various smaller headers and a few definitions - it's best to only add that header
11#include <lzma.h>
12#else
13// If we build without the library, it would be find to use #pragma on the entire object, without push
14// and pop, but it's nothing too important for us here - just for simplicity I'm going with this def
16#endif // BMNCOMPRESSION_WITH_XZ_LZMA
17
18/*
19 * A wrapper around lzma_stream as it may not be forward declared due to the way devs wrote
20 * its definition. While we could use `void*` in `BmnFileReaderXzLzma.hpp`, this is more readable
21 */
23{
24#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
26 : fLzmaStream(LZMA_STREAM_INIT)
27 {}
28 ~LzmaContext() { lzma_end(&fLzmaStream); }
29
30 public:
31 lzma_stream fLzmaStream;
32#else
33 LzmaContext() = default;
34 ~LzmaContext() = default;
35#endif // BMNCOMPRESSION_WITH_XZ_LZMA
36};
37
38// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
39// ================== static function declaration ==================
40// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
41
42#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
43
44/*
45 * A method that can be used for obtaining a string based on an error ID return by some LZMA function
46 * @param errorID An error ID return by a LZMA function
47 */
48[[nodiscard]] static std::string GetLzmaReturnTypeDescription(const int32_t errorID) noexcept;
49/*
50 * A method that can be used for obtaining a string based on a lzma_ret value
51 * @param lzmaReturnEnum An enum-type returned by a LZMA function
52 */
53[[nodiscard]] static std::string GetLzmaReturnTypeDescription(const lzma_ret lzmaReturnEnum) noexcept;
54
55#endif // BMNCOMPRESSION_WITH_XZ_LZMA
56
57// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
58// ================== BmnFileReaderXzLzma public methods ==================
59// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
60
61size_t BmnFileReaderXzLzma::sMaximalAllowedMemory = 256ull * 1024ull * 1024ull;
62
63BmnFileReaderXzLzma::BmnFileReaderXzLzma(const std::string& fileName)
65 , fLzmaStream(nullptr)
66 , fArchiveReadManager(*this)
67 , fNumberOfReadBytes(0ull)
69{}
70
72 : BmnIFileReader(BmnFileType::XZ_LZMA, std::move(fileName))
73 , fLzmaStream(nullptr)
74 , fArchiveReadManager(*this)
75 , fNumberOfReadBytes(0ull)
77{}
78
79BmnFileReaderXzLzma::BmnFileReaderXzLzma(const std::filesystem::path& filePath)
81 , fLzmaStream(nullptr)
82 , fArchiveReadManager(*this)
83 , fNumberOfReadBytes(0ull)
85{}
86
87BmnFileReaderXzLzma::BmnFileReaderXzLzma(std::filesystem::path&& filePath)
88 : BmnIFileReader(BmnFileType::XZ_LZMA, std::move(filePath))
89 , fLzmaStream(nullptr)
90 , fArchiveReadManager(*this)
91 , fNumberOfReadBytes(0ull)
93{}
94
99
101{
102#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
103 /*
104 While we actually don't need so many comments and checks here, we are still performing them just to ensure
105 one doesn't make an accidental mistake - it might be easier to catch it
106 */
107 if (fLzmaStream) {
108 LOG(error) << "LZMA stream is already valid!";
109 return;
110 }
111 if (!PerformStandardChecksBeforeOpening(processingFlags))
112 return;
113 fArchiveReadManager.Open(fFilePath, std::ios::in | std::ios::binary);
114 fLzmaStream = new LzmaContext{};
115 // we are looking for .xz files, not raw lzma so `lzma_stream_decoder` is find, no need to use `lzma_auto_decoder`
116 lzma_ret aReturnStatus = lzma_stream_decoder(&fLzmaStream->fLzmaStream, sMaximalAllowedMemory, LZMA_CONCATENATED);
117 if (aReturnStatus != lzma_ret::LZMA_OK) {
118 fArchiveReadManager.Close();
119 delete fLzmaStream;
120 fLzmaStream = nullptr;
121 LOG(error) << "Failed to initialize lzma stream! Reason: " << GetLzmaReturnTypeDescription(aReturnStatus)
122 << '\n';
123 }
124#else
125 throw std::runtime_error{"Trying to use LZMA while BMN is not compiled with it!"};
126#endif // BMNCOMPRESSION_WITH_XZ_LZMA
127}
128
130{
131#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
132 if (!fLzmaStream)
133 return;
134 // while lzma.h tells us we can reuse the stream, we could save some time that we will spend for allocating new
135 // buffers, but it's a safer and less error-prone approach - thus, I'm deleting buffers while closing
136 delete fLzmaStream;
137 fLzmaStream = nullptr;
138 fArchiveReadManager.Close();
139 fNumberOfReadBytes = 0ull;
141#endif // BMNCOMPRESSION_WITH_XZ_LZMA
142}
143
144int64_t BmnFileReaderXzLzma::Read(void* dataToFill, const int64_t sizeToFill)
145{
146#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
147 if (!IsStreamInGoodState())
148 return 0ll;
149 return fArchiveReadManager.Read(dataToFill, sizeToFill);
150#else
151 throw std::runtime_error{"Trying to use LZMA while BMN is not compiled with it!"};
152#endif // BMNCOMPRESSION_WITH_XZ_LZMA
153}
154
155int64_t BmnFileReaderXzLzma::Tell() const noexcept
156{
157 return fNumberOfReadBytes + fArchiveReadManager.GetCurrentOutputBufferPosition()
158 - fArchiveReadManager.GetTotalOutputBufferFilledSize();
159}
160
161void BmnFileReaderXzLzma::Seek(int64_t value)
162{
163#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
164 if (value < 0ll || (size_t)value == fNumberOfReadBytes)
165 return;
166 if (!IsStreamInGoodState()) {
167 LOG(error) << "Before calling `BmnFileReaderXzLzma::Seek` ensure to clear bad flags!\n";
168 return;
169 }
170 if (!fLzmaStream) {
171 LOG(error) << "Before calling `BmnFileReaderXzLzma::Seek` ensure to open the stream!\n";
172 return;
173 }
174 if (!fArchiveReadManager.IsOpen()) {
175 LOG(error) << "Reading file missing while calling `BmnFileReaderXzLzma::Seek`\n";
176 return;
177 }
178 if ((size_t)value < (fNumberOfReadBytes - fArchiveReadManager.GetTotalOutputBufferFilledSize())) {
179 Close();
181 }
182 // in theory I could check IsOpen again for unexpected errors, but....
183 fArchiveReadManager.MoveToDecompressingLocation(value);
184#else
185 throw std::runtime_error{"Trying to use LZMA while BMN is not compiled with it!"};
186#endif // BMNCOMPRESSION_WITH_XZ_LZMA
187}
188
189bool BmnFileReaderXzLzma::IsGood() const noexcept
190{
191#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
193#else
194 return false;
195#endif // BMNCOMPRESSION_WITH_XZ_LZMA
196}
197
198bool BmnFileReaderXzLzma::IsEOF() const noexcept
199{
200 return fArchiveReadManager.IsEOF();
201}
202
204{
205 // I don't like this method much
206 fLastReturnStatus = 0ull;
207 fArchiveReadManager.Clear();
208}
209
210bool BmnFileReaderXzLzma::IsOpen() const noexcept
211{
212 return fArchiveReadManager.IsOpen() && fLzmaStream;
213}
214
215// ========== BmnIArchiveLib Interface ==========
216
218 const size_t sourceTotalSize,
219 size_t& numberOfReadBytes,
220 void* output,
221 const size_t outputTotalSize,
222 size_t& numberOfSetOutputBytes)
223{
224 if (!fLzmaStream)
226#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
227 if (!IsStreamInGoodState())
229 fLzmaStream->fLzmaStream.next_out = (uint8_t*)output;
230 fLzmaStream->fLzmaStream.avail_out = outputTotalSize;
231 fLzmaStream->fLzmaStream.total_out = 0ull;
232 fLzmaStream->fLzmaStream.next_in = (uint8_t*)source;
233 fLzmaStream->fLzmaStream.avail_in = sourceTotalSize;
234 fLzmaStream->fLzmaStream.total_in = 0ull;
235 if (sourceTotalSize == 0ull)
236 fLastReturnStatus = (int32_t)lzma_code(&fLzmaStream->fLzmaStream, lzma_action::LZMA_FINISH);
237 else
238 fLastReturnStatus = (int32_t)lzma_code(&fLzmaStream->fLzmaStream, lzma_action::LZMA_RUN);
239 if (!IsStreamInGoodState())
241 numberOfReadBytes = (size_t)fLzmaStream->fLzmaStream.total_in;
242 numberOfSetOutputBytes = (size_t)fLzmaStream->fLzmaStream.total_out;
243 fNumberOfReadBytes += numberOfSetOutputBytes;
244 if (fLastReturnStatus == 1)
247#else
248 throw std::runtime_error{"Trying to use LZMA while BMN is not compiled with it!"};
249#endif // BMNCOMPRESSION_WITH_XZ_LZMA
250}
251
253{
254#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
256#else
257 return std::string{"BMN NOT BUILT WITH XZ LZMA"};
258#endif // BMNCOMPRESSION_WITH_XZ_LZMA
259}
260
262{
263 return false;
264}
265
267{
268 /*
269 In general with XZ LZMA we could allow jumping while carefully building LZMA blocks. Still,
270 that would be allowed only in files written by our own encoder, while XZ would not produce
271 the same results. Thus, we don't allow jumps no matter what and if jumps are needed, we can
272 think about it and adapt later
273 */
274 LOG(warning) << "Calling `BmnFileReaderXzLzma::JumpTo` while the type doesn't allow jumping!\n";
275}
276
278{
279 return fNumberOfReadBytes;
280}
281
283{
284#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
285 return fLastReturnStatus == 1;
286#else
287 return true;
288#endif // BMNCOMPRESSION_WITH_XZ_LZMA
289}
290
292{
293#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
294 assert(fLastReturnStatus >= 0);
295 return fLastReturnStatus < 4;
296#else
297 return false;
298#endif // BMNCOMPRESSION_WITH_XZ_LZMA
299}
300
301// ========== BmnFileReaderXzLzma methods ==========
302
304{
305#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
306 if (!fLzmaStream)
307 return 0ull;
308 return lzma_memusage(&fLzmaStream->fLzmaStream);
309#else
310 return 0ull;
311#endif // BMNCOMPRESSION_WITH_XZ_LZMA
312}
313
314// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
315// ================== static function definition ==================
316// o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o
317
318#ifdef BMNCOMPRESSION_WITH_XZ_LZMA
319
320static std::string GetLzmaReturnTypeDescription(const int32_t errorID) noexcept
321{
322 assert(errorID < 12);
323 return GetLzmaReturnTypeDescription(static_cast<lzma_ret>(errorID));
324}
325
326static std::string GetLzmaReturnTypeDescription(const lzma_ret lzmaReturnEnum) noexcept
327{
328 switch (lzmaReturnEnum) {
329 case lzma_ret::LZMA_OK:
330 return std::string{"OK"};
331 case LZMA_STREAM_END:
332 return std::string{"STREAM END"};
333 case LZMA_NO_CHECK:
334 return std::string{"NO INFO"};
335 case LZMA_UNSUPPORTED_CHECK:
336 return std::string{"NO CHECK"};
337 case LZMA_GET_CHECK:
338 return std::string{"GET CHECK"}; // don't understand this one
339 case LZMA_MEM_ERROR:
340 return std::string{"MEMORY ALLOCATION FAILED"};
341 case LZMA_MEMLIMIT_ERROR:
342 return std::string{"MEMORY LIMIT REACHED"};
343 case LZMA_FORMAT_ERROR:
344 return std::string{"FILE IS NOT XZ LZMA"};
345 case LZMA_OPTIONS_ERROR:
346 return std::string{"BAD DECODING OPTIONS"};
347 case LZMA_DATA_ERROR:
348 return std::string{"LZMA DATA CORRUPTED"};
349 case LZMA_BUF_ERROR:
350 return std::string{"BAD BUFFERS"};
351 case LZMA_PROG_ERROR:
352 return std::string{"INVALID ARGUMENTS"};
353 default:
354 // HOW??
355 assert(false);
356 return std::string{};
357 }
358}
359#endif // BMNCOMPRESSION_WITH_XZ_LZMA
360
361#ifndef BMNCOMPRESSION_WITH_XZ_LZMA
363#endif // BMNCOMPRESSION_WITH_XZ_LZMA
static std::string GetLzmaReturnTypeDescription(const int32_t errorID) noexcept
#define RESTORE_UNUSED_PARAM_WARNING
#define DISABLE_UNUSED_PARAM_WARNING
BmnFileReaderXzLzma(const std::string &fileName="")
virtual void Open(const BmnBinaryFileProcessingOptions processingFlags=BmnBinaryFileProcessingOptions::ReadBinary) override
virtual void Seek(int64_t value) override
virtual int64_t Tell() const noexcept override
virtual int64_t Read(void *dataToFill, const int64_t sizeToFill) override
BmnReaderCacheManager< 32ull *1024ull, 64ull *1024ull > fArchiveReadManager
virtual bool HasReachedTheEndOfStream() const noexcept override
virtual void ClearStateFlags() override
virtual void JumpTo(size_t) override
virtual bool IsGood() const noexcept override
virtual BmnFileStreamResults Uncompress(const void *source, const size_t sourceTotalSize, size_t &numberOfReadBytes, void *output, const size_t outputTotalSize, size_t &numberOfSetOutputBytes) override
size_t GetUsedMemoryByLZMA() const noexcept
virtual void Close() noexcept override
static size_t sMaximalAllowedMemory
virtual bool IsOpen() const noexcept override
virtual std::string GetLastUncompressErrorDescription() const noexcept override
virtual ~BmnFileReaderXzLzma() override
virtual size_t GetNumberOfDecompressedBytes() const noexcept override
virtual bool JumpsAllowed() const noexcept override
virtual bool IsEOF() const noexcept override
virtual bool IsStreamInGoodState() const noexcept override
BmnIFileReader(const BmnFileType fileType, const std::string &fileName="")
std::filesystem::path fFilePath
bool PerformStandardChecksBeforeOpening(const BmnBinaryFileProcessingOptions processingFlags)
BmnBinaryFileProcessingOptions
Definition json.hpp:4446
lzma_stream fLzmaStream