PocketLzma  1.0.0
A cross-platform singleheader LZMA compression/decompression library for C++11
pocketlzma_class.hpp
Go to the documentation of this file.
1 //
2 // Created by robin on 29.12.2020.
3 //
4 
5 #ifndef POCKETLZMA_POCKETLZMA_CLASS_HPP
6 #define POCKETLZMA_POCKETLZMA_CLASS_HPP
7 
8 namespace plz
9 {
10  class PocketLzma
11  {
12  public:
13  PocketLzma() = default;
14  inline explicit PocketLzma(Preset preset);
15  inline explicit PocketLzma(const Settings &settings) : m_settings {settings} {};
16  inline void setSettings(const Settings &settings);
17  inline void usePreset (Preset preset);
18 
19  inline StatusCode compress(const std::vector<uint8_t> &input, std::vector<uint8_t> &output);
20  inline StatusCode compress(const uint8_t *input, const size_t inputSize, std::vector<uint8_t> &output);
21 
22  inline StatusCode decompress(const std::vector<uint8_t> &input, std::vector<uint8_t> &output);
23  inline StatusCode decompress(const uint8_t *input, const size_t inputSize, std::vector<uint8_t> &output);
24 
25  inline StatusCode decompressBuffered(const std::vector<uint8_t> &input, std::vector<uint8_t> &output, uint32_t bufferSize = PLZ_BUFFER_SIZE);
26  inline StatusCode decompressBuffered(const uint8_t *input, const size_t inputSize, std::vector<uint8_t> &output, uint32_t bufferSize = PLZ_BUFFER_SIZE);
27  private:
28  Settings m_settings {};
29  };
30 
32  {
33  usePreset(preset);
34  }
35 
44  void PocketLzma::setSettings(const Settings &settings)
45  {
46  m_settings = settings;
47  }
48 
60  {
61  m_settings.usePreset(preset);
62  }
63 
64  StatusCode PocketLzma::compress(const std::vector <uint8_t> &input, std::vector <uint8_t> &output)
65  {
66  return compress(&input[0], input.size(), output);
67  }
68 
69  StatusCode PocketLzma::compress(const uint8_t *input, const size_t inputSize, std::vector<uint8_t> &output)
70  {
71  m_settings.validate();
72  size_t propsSize = LZMA_PROPS_SIZE;
73  uint8_t propsEncoded[propsSize];
74 
75  size_t outSize = inputSize + (inputSize / 3) + 128;
76  uint8_t out[outSize];
77 
78  int rc = plz::c::LzmaCompress(out, &outSize, input, inputSize, propsEncoded, &propsSize, m_settings.level, m_settings.dictionarySize,
79  m_settings.literalContextBits,m_settings.literalPositionBits,m_settings.positionBits,m_settings.fastBytes,1);
80 
81  StatusCode status = static_cast<StatusCode>(rc);
82  if(status == StatusCode::Ok)
83  {
84  std::vector<uint8_t> sizeBits;
85  for (int i = 0; i < 8; i++)
86  sizeBits.push_back((inputSize >> (i * 8)) & 0xFF);
87 
88  output.insert(output.end(), propsEncoded, propsEncoded + propsSize); // Property header
89  output.insert(output.end(), sizeBits.begin(), sizeBits.end()); // Add decompress size information
90  output.insert(output.end(), out, out + outSize); // Data
91  }
92 
93  return status;
94  }
95 
106  StatusCode PocketLzma::decompress(const std::vector<uint8_t> &input, std::vector<uint8_t> &output)
107  {
108  return decompress(&input[0], input.size(), output);
109  }
110 
121  StatusCode PocketLzma::decompress(const uint8_t *input, const size_t inputSize, std::vector<uint8_t> &output)
122  {
123  if(inputSize <= PLZ_MINIMUM_LZMA_SIZE)
124  return StatusCode::InvalidLzmaData;
125 
126  size_t propsSize = LZMA_PROPS_SIZE + 8; //header + decompress_size
127  size_t size = 0;
128  bool sizeInfoMissing = true; //True until proven otherwise
129 
130  for (int i = 0; i < 8; i++)
131  {
132  uint8_t value = input[LZMA_PROPS_SIZE + i];
133  if(value != 0xFF)
134  sizeInfoMissing = false;
135 
136  size |= (value << (i * 8));
137  }
138 
139  if(sizeInfoMissing)
140  return decompressBuffered(input, inputSize, output, PLZ_BUFFER_SIZE); //StatusCode::MissingSizeInfoInHeader;
141 
142  uint8_t out[size];
143  size_t outSize = size;
144 
145  size_t inSize = inputSize - propsSize;
146  int rc = plz::c::LzmaUncompress(out, &outSize, &input[propsSize], &inSize, &input[0], LZMA_PROPS_SIZE);
147 
148  StatusCode status = static_cast<StatusCode>(rc);
149 
150  output.insert(output.end(), out, out + outSize);
151 
152  return status;
153  }
154 
170  StatusCode PocketLzma::decompressBuffered(const std::vector<uint8_t> &input, std::vector<uint8_t> &output, uint32_t bufferSize)
171  {
172  return decompressBuffered(&input[0], input.size(), output, bufferSize);
173  }
174 
190  StatusCode PocketLzma::decompressBuffered(const uint8_t *input, const size_t inputSize, std::vector<uint8_t> &output, uint32_t bufferSize)
191  {
192  if(inputSize <= PLZ_MINIMUM_LZMA_SIZE)
193  return StatusCode::InvalidLzmaData;
194 
195  size_t unpackSize;
196 
197  plz::c::CLzmaDec state;
198  size_t propsSize = LZMA_PROPS_SIZE + 8; //header + decompress_size
199 
200  /* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
201  unsigned char header[propsSize];
202 
203  //Read header data
204  for(int i = 0; i < propsSize; ++i)
205  header[i] = input[i];
206 
207  LzmaDec_Construct(&state);
208  int res = 0;
209  res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &plz::c::g_Alloc);
210 
211  uint8_t outBuf[bufferSize];
212  size_t inPos = 0, inSize = 0, outPos = 0;
213  inSize = inputSize - propsSize;
214  plz::c::LzmaDec_Init(&state);
215  for (;;)
216  {
217  {
218  plz::c::SizeT inProcessed = inSize - inPos;
219  plz::c::SizeT outProcessed = bufferSize - outPos;
220  plz::c::ELzmaFinishMode finishMode = plz::c::LZMA_FINISH_ANY;
221  plz::c::ELzmaStatus status;
222 
223 
224  res = plz::c::LzmaDec_DecodeToBuf(&state, outBuf + outPos, &outProcessed,
225  &input[propsSize] + inPos, &inProcessed, finishMode, &status);
226 
227 
228  inPos += inProcessed;
229  outPos += outProcessed;
230  unpackSize -= outProcessed;
231 
232  output.insert(output.end(), outBuf, outBuf + outPos);
233 
234  outPos = 0;
235 
236  if (res != SZ_OK)
237  break;
238 
239  if (inProcessed == 0 && outProcessed == 0)
240  {
241  if (status != plz::c::LZMA_STATUS_FINISHED_WITH_MARK)
242  {
243  LzmaDec_Free(&state, &plz::c::g_Alloc);
244  return static_cast<StatusCode>(SZ_ERROR_DATA);
245  }
246  break;
247  }
248  }
249  }
250  LzmaDec_Free(&state, &plz::c::g_Alloc);
251 
252  return static_cast<StatusCode>(res);
253  }
254 
255 }
256 
257 #endif //POCKETLZMA_POCKETLZMA_CLASS_HPP
plz::Settings
Definition: Settings.hpp:11
plz::PocketLzma::decompress
StatusCode decompress(const std::vector< uint8_t > &input, std::vector< uint8_t > &output)
Definition: pocketlzma_class.hpp:106
plz::Settings::dictionarySize
uint32_t dictionarySize
Definition: Settings.hpp:53
plz::Preset
Preset
Definition: pocketlzma_common.hpp:56
plz::PocketLzma
Definition: pocketlzma_class.hpp:11
plz::StatusCode
StatusCode
Definition: pocketlzma_common.hpp:30
plz::PocketLzma::setSettings
void setSettings(const Settings &settings)
Definition: pocketlzma_class.hpp:44
plz::StatusCode::Ok
@ Ok
plz::Settings::level
uint8_t level
Definition: Settings.hpp:41
plz::PocketLzma::PocketLzma
PocketLzma()=default
plz::Settings::usePreset
void usePreset(Preset preset)
Definition: Settings.hpp:118
plz::Settings::literalPositionBits
uint8_t literalPositionBits
Definition: Settings.hpp:69
plz::Settings::literalContextBits
uint8_t literalContextBits
Definition: Settings.hpp:60
plz::PLZ_BUFFER_SIZE
const uint32_t PLZ_BUFFER_SIZE
Definition: pocketlzma_common.hpp:26
plz::Settings::positionBits
uint8_t positionBits
Definition: Settings.hpp:76
plz::PocketLzma::usePreset
void usePreset(Preset preset)
Definition: pocketlzma_class.hpp:59
plz::Settings::validate
void validate()
Definition: Settings.hpp:92
plz::PocketLzma::PocketLzma
PocketLzma(const Settings &settings)
Definition: pocketlzma_class.hpp:15
plz::PLZ_MINIMUM_LZMA_SIZE
const uint8_t PLZ_MINIMUM_LZMA_SIZE
Definition: pocketlzma_common.hpp:27
plz::Settings::fastBytes
uint16_t fastBytes
Definition: Settings.hpp:84
plz::PocketLzma::compress
StatusCode compress(const std::vector< uint8_t > &input, std::vector< uint8_t > &output)
Definition: pocketlzma_class.hpp:64
plz::PocketLzma::decompressBuffered
StatusCode decompressBuffered(const std::vector< uint8_t > &input, std::vector< uint8_t > &output, uint32_t bufferSize=PLZ_BUFFER_SIZE)
Definition: pocketlzma_class.hpp:170
plz
Definition: File.hpp:11