Main Page · Modules · All Classes · Class Hierarchy
MCZipper.cpp
1 /*
2  * This file is part of the AiBO+ project
3  *
4  * Copyright (C) 2005-2016 Csaba Kertész (csaba.kertesz@gmail.com)
5  *
6  * AiBO+ is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * AiBO+ is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
19  *
20  */
21 
22 #include "MCZipper.hpp"
23 
24 #include "MCBinaryData.hpp"
25 #include "MCDefs.hpp"
26 #include "MCLog.hpp"
27 #include "MCThreadLocalData.hpp"
28 #include "MCTimer.hpp"
29 
30 #include <bzlib.h>
31 #include <lz4.h>
32 #include <lzoconf.h>
33 #include <minilzo.h>
34 #include <quicklz.h>
35 #include <Shrinker.h>
36 #include <snappy.h>
37 #include <zlib.h>
38 
39 // This include needed to avoid redefinition warning/error with __STDC_LIMIT_MACROS on MinGW caused by minilzo.h
40 #if defined(__MINGW32__) || defined(__MINGW64__)
41 #include <boost/config.hpp>
42 #endif
43 
44 namespace
45 {
46 // Compression buffer
47 MCThreadLocalData<qlz_state_compress> StateCompress(true);
48 MCThreadLocalData<qlz_state_decompress> StateDecompress(true);
49 MCThreadLocalData<MCBinaryData> CompressionBuffer(true);
50 
51 void CheckStaticZipperVariables()
52 {
53  if (unlikely(!CompressionBuffer.get()))
54  {
55  CompressionBuffer.reset(new MCBinaryData(10000));
56  StateCompress.reset(new qlz_state_compress);
57  // We can get "Conditional jump or move depends on uninitialised value(s)" error
58  // in valgrind if this structure is not cleared.
59  memset(StateCompress.get(), 0, sizeof(qlz_state_compress));
60  StateDecompress.reset(new qlz_state_decompress);
61  // We can get "Conditional jump or move depends on uninitialised value(s)" error
62  // in valgrind if this structure is not cleared.
63  memset(StateDecompress.get(), 0, sizeof(qlz_state_decompress));
64  }
65 }
66 }
67 
68 namespace MC
69 {
70 const StringList CompressionTypeStrs = {"Invalid", "Lz4", "Zlib", "QuickLZ", "MiniLzo", "Shrinker",
71  "Snappy", "Bzip2"};
72 const StringList CompressionLevelTypeStrs = {"Fast", "Medium", "Best"};
73 }
74 
75 void MCZipper::CompressQuickLz(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
76 {
77  CheckStaticZipperVariables();
78  // Test with quicklz
79  // The benchmark used compressed audio data on AIBO.
80  // Level 1: 181229 -> 138162 (164753 bytes / 10 msec)
81  // Level 2: 181229 -> 109329 (120819 bytes / 10 msec)
82  // Level 3: 181229 -> 109838 (226536 bytes / 10 msec) <-- This level is used
83  int CompressedSize = 0;
84  std::string IdStr = MC::CompressionTypeStrs[(int)MC::QuickLzCompression];
85 
86  if (CompressionBuffer->GetSize() < input_buffer.GetSize()+400+(int)IdStr.size())
87  {
88  CompressionBuffer->Allocate(input_buffer.GetSize()+400+IdStr.size());
89  }
90  CompressedSize = qlz_compress((char*)input_buffer.GetData(), (char*)CompressionBuffer->GetData(),
91  input_buffer.GetSize(), &*StateCompress);
92  int FinalSize = CompressedSize+(int)IdStr.size()+4;
93 
94  if (output_buffer.GetSize() != FinalSize)
95  {
96  output_buffer.Allocate(FinalSize);
97  }
98  output_buffer.SetPosition(0);
99  output_buffer.AddInt32(FinalSize);
100  memcpy((char*)&output_buffer.GetData()[4], IdStr.c_str(), IdStr.size());
101  memcpy((char*)&output_buffer.GetData()[IdStr.size()+4], (char*)CompressionBuffer->GetData(),
102  CompressedSize);
103 }
104 
105 
106 void MCZipper::DecompressQuickLz(const MCBinaryData& input_buffer, MCBinaryData& output_buffer,
107  bool without_header)
108 {
109  if (!without_header && DetectCompressionMethod(input_buffer) != MC::QuickLzCompression)
110  return;
111 
112  CheckStaticZipperVariables();
113  std::string IdStr = MC::CompressionTypeStrs[(int)MC::QuickLzCompression];
114  char* DataStart = !without_header ? (char*)&input_buffer.GetData()[IdStr.size()+4] :
115  (char*)input_buffer.GetData();
116  int DecompressedSize = qlz_size_decompressed(DataStart);
117 
118  if (!without_header)
119  {
120  MCBinaryData& Packet = const_cast<MCBinaryData&>(input_buffer);
121  int OldPosition = input_buffer.GetPosition();
122  int PacketSize = 0;
123 
124  Packet.SetPosition(0);
125  PacketSize = Packet.GetInt32();
126  Packet.SetPosition(OldPosition);
127  if (PacketSize != input_buffer.GetSize())
128  return;
129  }
130  if (output_buffer.GetSize() != DecompressedSize)
131  {
132  output_buffer.Allocate(DecompressedSize);
133  }
134  qlz_decompress(DataStart, (char*)output_buffer.GetData(), &*StateDecompress);
135 }
136 
137 
138 void MCZipper::CompressLz4(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
139 {
140  CheckStaticZipperVariables();
141  std::string IdStr = MC::CompressionTypeStrs[(int)MC::Lz4Compression];
142  int BufferSize = LZ4_compressBound(input_buffer.GetSize());
143 
144  if (CompressionBuffer->GetSize() < BufferSize)
145  {
146  CompressionBuffer->Allocate(BufferSize);
147  }
148  int OriginalSize = input_buffer.GetSize();
149  int CompressedSize = LZ4_compress((char*)input_buffer.GetData(), (char*)CompressionBuffer->GetData(),
150  input_buffer.GetSize());
151  int FinalSize = CompressedSize+(int)IdStr.size()+12;
152 
153  if (output_buffer.GetSize() != FinalSize)
154  {
155  output_buffer.Allocate(FinalSize);
156  }
157  output_buffer.SetPosition(0);
158  output_buffer.AddInt32(FinalSize);
159  memcpy((char*)&output_buffer.GetData()[4], IdStr.c_str(), IdStr.size());
160  output_buffer.IncrementPosition(IdStr.size());
161  output_buffer.AddInt32(OriginalSize);
162  output_buffer.AddInt32(CompressedSize);
163  memcpy((char*)&output_buffer.GetData()[IdStr.size()+12], (char*)CompressionBuffer->GetData(),
164  CompressedSize);
165 }
166 
167 
168 void MCZipper::DecompressLz4(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
169 {
170  if (DetectCompressionMethod(input_buffer) != MC::Lz4Compression)
171  return;
172 
173  CheckStaticZipperVariables();
174  std::string IdStr = MC::CompressionTypeStrs[(int)MC::Lz4Compression];
175  MCBinaryData& Packet = const_cast<MCBinaryData&>(input_buffer);
176  int OldPosition = Packet.GetPosition();
177  int PacketSize = 0;
178  int OriginalSize = 0;
179  int CompressedSize = 0;
180 
181  Packet.SetPosition(0);
182  PacketSize = Packet.GetInt32();
183  Packet.IncrementPosition(IdStr.size());
184  OriginalSize = Packet.GetInt32();
185  CompressedSize = Packet.GetInt32();
186  Packet.SetPosition(OldPosition);
187  if (PacketSize != input_buffer.GetSize() || OriginalSize <= 0 ||
188  CompressedSize+12+(int)IdStr.size() != input_buffer.GetSize())
189  {
190  return;
191  }
192  if (CompressionBuffer->GetSize() < OriginalSize)
193  {
194  CompressionBuffer->Allocate(OriginalSize);
195  }
196  int Result = LZ4_decompress_safe((char*)&input_buffer.GetData()[IdStr.size()+12],
197  (char*)CompressionBuffer->GetData(),
198  input_buffer.GetSize()-IdStr.size()-12, CompressionBuffer->GetSize());
199 
200  if (Result != OriginalSize)
201  return;
202  if (output_buffer.GetSize() != Result)
203  {
204  output_buffer.Allocate(Result);
205  }
206  memcpy(output_buffer.GetData(), CompressionBuffer->GetData(), Result);
207 }
208 
209 
210 void MCZipper::CompressMiniLzo(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
211 {
212  CheckStaticZipperVariables();
213  std::string IdStr = MC::CompressionTypeStrs[(int)MC::MiniLzoCompression];
214  int BufferSize = (int)input_buffer.GetSize()*11 / 10+100;
215 
216  output_buffer.Allocate((int)LZO1X_1_MEM_COMPRESS);
217  if (CompressionBuffer->GetSize() < BufferSize)
218  {
219  CompressionBuffer->Allocate(BufferSize);
220  }
221  lzo_init();
222 
223  lzo_uint OutputBufferSize = (lzo_uint)output_buffer.GetSize();
224  int Result = lzo1x_1_compress((lzo_bytep)input_buffer.GetData(), (lzo_uint)input_buffer.GetSize(),
225  (lzo_bytep)CompressionBuffer->GetData(), (lzo_uintp)&OutputBufferSize,
226  (lzo_voidp)output_buffer.GetData());
227 
228  if (Result == LZO_E_OK)
229  {
230  int FinalSize = (int)OutputBufferSize+(int)IdStr.size()+8;
231  int OriginalSize = input_buffer.GetSize();
232 
233  if (output_buffer.GetSize() != FinalSize)
234  {
235  output_buffer.Allocate(FinalSize);
236  }
237  output_buffer.SetPosition(0);
238  output_buffer.AddInt32(FinalSize);
239  memcpy((char*)&output_buffer.GetData()[4], IdStr.c_str(), IdStr.size());
240  output_buffer.IncrementPosition(IdStr.size());
241  output_buffer.AddInt32(OriginalSize);
242  memcpy((char*)&output_buffer.GetData()[IdStr.size()+8], (char*)CompressionBuffer->GetData(),
243  (int)OutputBufferSize);
244  }
245 }
246 
247 
248 void MCZipper::DecompressMiniLzo(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
249 {
250  if (DetectCompressionMethod(input_buffer) != MC::MiniLzoCompression)
251  return;
252 
253  CheckStaticZipperVariables();
254  std::string IdStr = MC::CompressionTypeStrs[(int)MC::MiniLzoCompression];
255  MCBinaryData& Packet = const_cast<MCBinaryData&>(input_buffer);
256  int OldPosition = Packet.GetPosition();
257  int PacketSize = 0;
258  int OriginalSize = 0;
259 
260  Packet.SetPosition(0);
261  PacketSize = Packet.GetInt32();
262  Packet.IncrementPosition(IdStr.size());
263  OriginalSize = Packet.GetInt32();
264  Packet.SetPosition(OldPosition);
265  if (PacketSize != input_buffer.GetSize() || OriginalSize <= 0)
266  return;
267  lzo_init();
268  if (CompressionBuffer->GetSize() < OriginalSize)
269  {
270  CompressionBuffer->Allocate(OriginalSize);
271  }
272  lzo_uint FinalSize = CompressionBuffer->GetSize();
273  int Result = lzo1x_decompress_safe((lzo_bytep)&input_buffer.GetData()[IdStr.size()+8],
274  (lzo_uint)(input_buffer.GetSize()-IdStr.size()-8),
275  (lzo_bytep)CompressionBuffer->GetData(), (lzo_uintp)&FinalSize,
276  (lzo_voidp)nullptr);
277 
278  if (Result != LZO_E_OK)
279  return;
280  if (output_buffer.GetSize() != (int)FinalSize)
281  {
282  output_buffer.Allocate((int)FinalSize);
283  }
284  memcpy(output_buffer.GetData(), CompressionBuffer->GetData(), (int)FinalSize);
285 }
286 
287 
288 void MCZipper::CompressShrinker(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
289 {
290  CheckStaticZipperVariables();
291  std::string IdStr = MC::CompressionTypeStrs[(int)MC::ShrinkerCompression];
292 
293  if (CompressionBuffer->GetSize() < input_buffer.GetSize()+200)
294  {
295  CompressionBuffer->Allocate(input_buffer.GetSize()+200);
296  }
297  int Result = shrinker_compress((char*)input_buffer.GetData(), (char*)CompressionBuffer->GetData(),
298  input_buffer.GetSize());
299 
300  if (Result > 0)
301  {
302  int FinalSize = Result+(int)IdStr.size()+8;
303  int OriginalSize = input_buffer.GetSize();
304 
305  if (output_buffer.GetSize() != FinalSize)
306  {
307  output_buffer.Allocate(FinalSize);
308  }
309  output_buffer.SetPosition(0);
310  output_buffer.AddInt32(FinalSize);
311  memcpy((char*)&output_buffer.GetData()[4], IdStr.c_str(), IdStr.size());
312  output_buffer.IncrementPosition(IdStr.size());
313  output_buffer.AddInt32(OriginalSize);
314  memcpy((char*)&output_buffer.GetData()[IdStr.size()+8], (char*)CompressionBuffer->GetData(), Result);
315  }
316 }
317 
318 
319 void MCZipper::DecompressShrinker(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
320 {
321  if (DetectCompressionMethod(input_buffer) != MC::ShrinkerCompression)
322  return;
323 
324  CheckStaticZipperVariables();
325  std::string IdStr = MC::CompressionTypeStrs[(int)MC::ShrinkerCompression];
326  MCBinaryData& Packet = const_cast<MCBinaryData&>(input_buffer);
327  int OldPosition = Packet.GetPosition();
328  int PacketSize = 0;
329  int OriginalSize = 0;
330 
331  Packet.SetPosition(0);
332  PacketSize = Packet.GetInt32();
333  Packet.IncrementPosition(IdStr.size());
334  OriginalSize = Packet.GetInt32();
335  Packet.SetPosition(OldPosition);
336  if (PacketSize != input_buffer.GetSize() || input_buffer.GetSize() < 36+(int)IdStr.size()+8 ||
337  OriginalSize <= 0)
338  {
339  return;
340  }
341  if (output_buffer.GetSize() < OriginalSize)
342  {
343  output_buffer.Allocate(OriginalSize);
344  }
345  shrinker_decompress(&input_buffer.GetData()[IdStr.size()+8], output_buffer.GetData());
346 }
347 
348 
349 void MCZipper::CompressSnappy(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
350 {
351  CheckStaticZipperVariables();
352  std::string IdStr = MC::CompressionTypeStrs[(int)MC::SnappyCompression];
353  size_t BufferSize = (int)snappy::MaxCompressedLength((size_t)input_buffer.GetSize())+IdStr.size();
354 
355  if (CompressionBuffer->GetSize() < (int)BufferSize)
356  {
357  CompressionBuffer->Allocate((int)BufferSize);
358  } else {
359  BufferSize = (size_t)CompressionBuffer->GetSize();
360  }
361  snappy::RawCompress((char*)input_buffer.GetData(), (size_t)input_buffer.GetSize(),
362  (char*)CompressionBuffer->GetData(), &BufferSize);
363  int FinalSize = (int)BufferSize+(int)IdStr.size()+8;
364 
365  if (output_buffer.GetSize() != FinalSize)
366  {
367  output_buffer.Allocate(FinalSize);
368  }
369  output_buffer.SetPosition(0);
370  output_buffer.AddInt32(FinalSize);
371  memcpy((char*)&output_buffer.GetData()[4], IdStr.c_str(), IdStr.size());
372  memcpy((char*)&output_buffer.GetData()[IdStr.size()+4], (char*)CompressionBuffer->GetData(),
373  (int)BufferSize);
374 }
375 
376 
377 void MCZipper::DecompressSnappy(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
378 {
379  if (DetectCompressionMethod(input_buffer) != MC::SnappyCompression)
380  return;
381 
382  CheckStaticZipperVariables();
383  std::string IdStr = MC::CompressionTypeStrs[(int)MC::SnappyCompression];
384  MCBinaryData& Packet = const_cast<MCBinaryData&>(input_buffer);
385  int OldPosition = Packet.GetPosition();
386  int PacketSize = 0;
387 
388  Packet.SetPosition(0);
389  PacketSize = Packet.GetInt32();
390  Packet.SetPosition(OldPosition);
391  if (PacketSize != input_buffer.GetSize())
392  return;
393 
394  size_t DecompressedSize = 0;
395 
396  if (snappy::GetUncompressedLength((char*)&input_buffer.GetData()[IdStr.size()+4],
397  (size_t)(input_buffer.GetSize()-IdStr.size()-4),
398  &DecompressedSize))
399  {
400  if (output_buffer.GetSize() != (int)DecompressedSize)
401  {
402  output_buffer.Allocate((int)DecompressedSize);
403  }
404  snappy::RawUncompress((char*)&input_buffer.GetData()[IdStr.size()+4],
405  (size_t)(input_buffer.GetSize()-IdStr.size()-4),
406  (char*)output_buffer.GetData());
407  }
408 }
409 
410 
411 void MCZipper::CompressZlib(const MCBinaryData& input_buffer, MCBinaryData& output_buffer,
412  MC::CompressionLevelsType compression_level)
413 {
414  CheckStaticZipperVariables();
415  std::string IdStr = MC::CompressionTypeStrs[(int)MC::ZlibCompression];
416  uLong BufferSize = compressBound((uLong)input_buffer.GetSize())+IdStr.size()+8;
417 
418  if (CompressionBuffer->GetSize() < (int)BufferSize)
419  {
420  CompressionBuffer->Allocate((int)BufferSize);
421  }
422  uLongf OutputBufferSize = (uLongf)CompressionBuffer->GetSize();
423  int CompressionLevel = compression_level == MC::BestCompression ? Z_BEST_COMPRESSION :
424  (compression_level == MC::MediumCompression ? Z_DEFAULT_COMPRESSION :
425  Z_BEST_SPEED);
426  compress2((Bytef*)CompressionBuffer->GetData(), &OutputBufferSize, (Bytef*)input_buffer.GetData(),
427  (uLong)input_buffer.GetSize(), CompressionLevel);
428  int FinalSize = (int)OutputBufferSize+(int)IdStr.size()+8;
429  int OriginalSize = input_buffer.GetSize();
430 
431  if (output_buffer.GetSize() != FinalSize)
432  {
433  output_buffer.Allocate((int)FinalSize);
434  }
435  output_buffer.SetPosition(0);
436  output_buffer.AddInt32(FinalSize);
437  memcpy((char*)&output_buffer.GetData()[4], IdStr.c_str(), IdStr.size());
438  output_buffer.IncrementPosition(IdStr.size());
439  output_buffer.AddInt32(OriginalSize);
440  memcpy((char*)&output_buffer.GetData()[IdStr.size()+8], (char*)CompressionBuffer->GetData(),
441  (int)OutputBufferSize);
442 }
443 
444 
445 void MCZipper::DecompressZlib(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
446 {
447  if (DetectCompressionMethod(input_buffer) != MC::ZlibCompression)
448  return;
449 
450  CheckStaticZipperVariables();
451  std::string IdStr = MC::CompressionTypeStrs[(int)MC::ZlibCompression];
452  MCBinaryData& Packet = const_cast<MCBinaryData&>(input_buffer);
453  int OldPosition = Packet.GetPosition();
454  int PacketSize = 0;
455  int OriginalSize = 0;
456 
457  Packet.SetPosition(0);
458  PacketSize = Packet.GetInt32();
459  Packet.IncrementPosition(IdStr.size());
460  OriginalSize = Packet.GetInt32();
461  Packet.SetPosition(OldPosition);
462  if (PacketSize != input_buffer.GetSize() || OriginalSize <= 0)
463  return;
464  if (CompressionBuffer->GetSize() < OriginalSize)
465  {
466  CompressionBuffer->Allocate(OriginalSize);
467  }
468  uLongf FinalSize = (uLongf)CompressionBuffer->GetSize();
469  int Result = uncompress((Bytef*)CompressionBuffer->GetData(), &FinalSize,
470  (Bytef*)&input_buffer.GetData()[IdStr.size()+8],
471  (uLong)(input_buffer.GetSize()-IdStr.size()-8));
472 
473  if (Result == Z_OK)
474  {
475  output_buffer.Allocate((int)FinalSize);
476  memcpy(output_buffer.GetData(), CompressionBuffer->GetData(), (int)FinalSize);
477  }
478 }
479 
480 
481 void MCZipper::CompressBzip2(const MCBinaryData& input_buffer, MCBinaryData& output_buffer,
482  MC::CompressionLevelsType compression_level)
483 {
484  CheckStaticZipperVariables();
485  std::string IdStr = MC::CompressionTypeStrs[(int)MC::Bzip2Compression];
486  unsigned int BufferSize = input_buffer.GetSize()*105 / 100+700;
487 
488  if (CompressionBuffer->GetSize() < (int)BufferSize)
489  {
490  CompressionBuffer->Allocate((int)BufferSize);
491  }
492  int CompressionLevel = compression_level == MC::BestCompression ? 9 :
493  (compression_level == MC::MediumCompression ? 5 : 1);
494 
495  BZ2_bzBuffToBuffCompress((char*)CompressionBuffer->GetData(), &BufferSize,
496  (char*)input_buffer.GetData(), input_buffer.GetSize(),
497  CompressionLevel, 0, 0);
498  int FinalSize = (int)BufferSize+(int)IdStr.size()+8;
499  int OriginalSize = input_buffer.GetSize();
500 
501  if (output_buffer.GetSize() != FinalSize)
502  {
503  output_buffer.Allocate(FinalSize);
504  }
505  output_buffer.SetPosition(0);
506  output_buffer.AddInt32(FinalSize);
507  memcpy((char*)&output_buffer.GetData()[4], IdStr.c_str(), IdStr.size());
508  output_buffer.IncrementPosition(IdStr.size());
509  output_buffer.AddInt32(OriginalSize);
510  memcpy((char*)&output_buffer.GetData()[IdStr.size()+8], (char*)CompressionBuffer->GetData(),
511  BufferSize);
512 }
513 
514 
515 void MCZipper::DecompressBzip2(const MCBinaryData& input_buffer, MCBinaryData& output_buffer)
516 {
517  if (DetectCompressionMethod(input_buffer) != MC::Bzip2Compression)
518  return;
519 
520  CheckStaticZipperVariables();
521  std::string IdStr = MC::CompressionTypeStrs[(int)MC::Bzip2Compression];
522  MCBinaryData& Packet = const_cast<MCBinaryData&>(input_buffer);
523  int OldPosition = Packet.GetPosition();
524  int PacketSize = 0;
525  int OriginalSize = 0;
526 
527  Packet.SetPosition(0);
528  PacketSize = Packet.GetInt32();
529  Packet.IncrementPosition(IdStr.size());
530  OriginalSize = Packet.GetInt32();
531  Packet.SetPosition(OldPosition);
532  if (PacketSize != input_buffer.GetSize() || OriginalSize <= 0)
533  return;
534  if (CompressionBuffer->GetSize() < OriginalSize)
535  {
536  CompressionBuffer->Allocate(OriginalSize);
537  }
538  unsigned int DecompressedSize = CompressionBuffer->GetSize();
539  int Result = BZ2_bzBuffToBuffDecompress((char*)CompressionBuffer->GetData(), &DecompressedSize,
540  (char*)&input_buffer.GetData()[IdStr.size()+8],
541  input_buffer.GetSize()-IdStr.size()-8, 0, 0);
542 
543  if (Result == BZ_OK)
544  {
545  output_buffer.Allocate((int)DecompressedSize);
546  memcpy(output_buffer.GetData(), CompressionBuffer->GetData(), (int)DecompressedSize);
547  }
548 }
549 
550 
551 MC::CompressionDescriptor MCZipper::FindBestCompression(const MCBinaryData& input_buffer,
552  MCBinaryData& output_buffer, bool test_mode)
553 {
554  MC::BinaryDataSPtr TempBuffer(new MCBinaryData);
555  MC::CompressionDescriptor BestCompression;
556  MCTimer Timer;
557 
558  if (test_mode)
559  MC_LOG("Original data size: %d", input_buffer.GetSize());
560  BestCompression.second = MC::MediumCompression;
561  for (int i = (int)MC::Lz4Compression; i <= (int)MC::Bzip2Compression; ++i)
562  {
563  for (int i1 = (int)MC::FastCompression; i1 <= (int)MC::BestCompression; ++i1)
564  {
565  if ((i1 == (int)MC::FastCompression || i1 == (int)MC::BestCompression) &&
566  i != (int)MC::Bzip2Compression && i != (int)MC::ZlibCompression)
567  {
568  continue;
569  }
570  Timer.Start();
571  if (i == (int)MC::Lz4Compression)
572  CompressLz4(input_buffer, *TempBuffer);
573  if (i == (int)MC::ZlibCompression)
574  CompressZlib(input_buffer, *TempBuffer, (MC::CompressionLevelsType)i1);
575  if (i == (int)MC::QuickLzCompression)
576  CompressQuickLz(input_buffer, *TempBuffer);
577  if (i == (int)MC::MiniLzoCompression)
578  CompressMiniLzo(input_buffer, *TempBuffer);
579  if (i == (int)MC::ShrinkerCompression)
580  CompressShrinker(input_buffer, *TempBuffer);
581  if (i == (int)MC::SnappyCompression)
582  CompressSnappy(input_buffer, *TempBuffer);
583  if (i == (int)MC::Bzip2Compression)
584  CompressBzip2(input_buffer, *TempBuffer, (MC::CompressionLevelsType)i1);
585 
586  if (test_mode)
587  {
588  MC::BinaryDataSPtr TempBuffer2(new MCBinaryData);
589 
590  MC_LOG("Compression size and speed (%s/%s): %d bytes, %d bytes / msec",
591  MC::CompressionTypeStrs[i].c_str(), MC::CompressionLevelTypeStrs[i1].c_str(),
592  TempBuffer->GetSize(),
593  (int)((int64_t)input_buffer.GetSize()*1000 / Timer.GetElapsedTimeInUSecs()));
594  Timer.Start();
595  if (i == (int)MC::Lz4Compression)
596  DecompressLz4(*TempBuffer, *TempBuffer2);
597  if (i == (int)MC::ZlibCompression)
598  DecompressZlib(*TempBuffer, *TempBuffer2);
599  if (i == (int)MC::QuickLzCompression)
600  DecompressQuickLz(*TempBuffer, *TempBuffer2);
601  if (i == (int)MC::MiniLzoCompression)
602  DecompressMiniLzo(*TempBuffer, *TempBuffer2);
603  if (i == (int)MC::ShrinkerCompression)
604  DecompressShrinker(*TempBuffer, *TempBuffer2);
605  if (i == (int)MC::SnappyCompression)
606  DecompressSnappy(*TempBuffer, *TempBuffer2);
607  if (i == (int)MC::Bzip2Compression)
608  DecompressBzip2(*TempBuffer, *TempBuffer2);
609  int64_t ElapsedTime = Timer.GetElapsedTimeInUSecs();
610 
611  ElapsedTime = (ElapsedTime > 0 ? ElapsedTime : 1);
612  MC_LOG("Decompression speed (%s/%s): %d bytes / msec",
613  MC::CompressionTypeStrs[i].c_str(), MC::CompressionLevelTypeStrs[i1].c_str(),
614  (int)((int64_t)input_buffer.GetSize()*1000 / ElapsedTime));
615  }
616  if (i == (int)MC::Lz4Compression || TempBuffer->GetSize() < output_buffer.GetSize())
617  {
618  output_buffer = std::move(*TempBuffer);
619  BestCompression.first = (MC::CompressionsType)i;
620  BestCompression.second = (MC::CompressionLevelsType)i1;
621  }
622  }
623  }
624  return BestCompression;
625 }
626 
627 
628 MC::CompressionsType MCZipper::DetectCompressionMethod(const MCBinaryData& input_buffer,
629  MC::CompressionsType compression)
630 {
631  if (input_buffer.GetSize() < 4)
632  return MC::InvalidCompression;
633 
634  int Size = 0;
635  MCBinaryData& Packet = const_cast<MCBinaryData&>(input_buffer);
636  int OldPosition = Packet.GetPosition();
637 
638  Packet.SetPosition(0);
639  Size = Packet.GetInt32();
640  Packet.SetPosition(OldPosition);
641  if (Size < 0 || Size > input_buffer.GetSize())
642  return MC::InvalidCompression;
643  for (int i = (int)MC::Lz4Compression; i <= (int)MC::Bzip2Compression; ++i)
644  {
645  // Skip other methods if a desired one is specified
646  if (compression != MC::InvalidCompression && compression != (MC::CompressionsType)i)
647  continue;
648 
649  std::string IdStr = MC::CompressionTypeStrs[(MC::CompressionsType)i];
650 
651  if (input_buffer.GetSize() < (int)IdStr.size()+4)
652  continue;
653  bool Found = true;
654 
655  for (unsigned int i1 = 0; i1 < IdStr.size(); ++i1)
656  {
657  if (IdStr.c_str()[i1] != input_buffer.GetData()[i1+4])
658  {
659  Found = false;
660  break;
661  }
662  }
663  if (Found)
664  return (MC::CompressionsType)i;
665  }
666  return MC::InvalidCompression;
667 }
668 
669 
671 {
672  CheckStaticZipperVariables();
673  CompressionBuffer->Allocate(10000);
674 }
void Start(int time_shift=0)
Start the timer.
Definition: MCTimer.cpp:183
static void DecompressSnappy(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Decompress data with snappy algorithm.
Definition: MCZipper.cpp:377
static void CompressShrinker(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Compress data with shrinker algorithm.
Definition: MCZipper.cpp:288
Binary data class.
static void ReleaseCache()
Release the allocated temporal compression cache.
Definition: MCZipper.cpp:670
static void DecompressMiniLzo(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Decompress data with minilzo algorithm.
Definition: MCZipper.cpp:248
static void DecompressLz4(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Decompress data with lz4 algorithm.
Definition: MCZipper.cpp:168
static MC::CompressionDescriptor FindBestCompression(const MCBinaryData &input_buffer, MCBinaryData &output_buffer, bool test_mode=false)
Find the best compression.
Definition: MCZipper.cpp:551
void Allocate(int size)
Allocate a certain data size.
static void DecompressShrinker(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Decompress data with shrinker algorithm.
Definition: MCZipper.cpp:319
void AddInt32(int32_t new_int, bool reverse_order=false)
Add a 32 bit integer at the current position.
static void CompressLz4(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Compress data with lz4 algorithm.
Definition: MCZipper.cpp:138
static void DecompressQuickLz(const MCBinaryData &input_buffer, MCBinaryData &output_buffer, bool without_header=false)
Decompress data with QuickLZ algorithm.
Definition: MCZipper.cpp:106
void SetPosition(unsigned int position)
Set the cursor position.
void IncrementPosition(unsigned int position=1)
Increment the cursor position.
static void CompressMiniLzo(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Compress data with minilzo algorithm.
Definition: MCZipper.cpp:210
static void DecompressZlib(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Decompress data with zlib algorithm.
Definition: MCZipper.cpp:445
unsigned char * GetData() const
Get direct access to the binary data.
Simple timer class with microsecond precision.
Definition: MCTimer.hpp:59
int64_t GetElapsedTimeInUSecs()
Get the elapsed time in microseconds since the timer has been started or since the last timeout...
Definition: MCTimer.cpp:211
static void CompressBzip2(const MCBinaryData &input_buffer, MCBinaryData &output_buffer, MC::CompressionLevelsType compression_level)
Compress data with bzip2 algorithm.
Definition: MCZipper.cpp:481
int32_t GetInt32(bool reverse_order=false)
Get a 32 bit integer from the current position.
A wrapper class to cover boost::thread_specific_ptr/folly::ThreadLocal API on certain targets...
static MC::CompressionsType DetectCompressionMethod(const MCBinaryData &input_buffer, MC::CompressionsType compression=MC::InvalidCompression)
Detect the compression method of a buffer.
Definition: MCZipper.cpp:628
static void CompressSnappy(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Compress data with snappy algorithm.
Definition: MCZipper.cpp:349
#define MC_LOG(...)
Debug macro.
Definition: MCLog.hpp:41
static void CompressZlib(const MCBinaryData &input_buffer, MCBinaryData &output_buffer, MC::CompressionLevelsType compression_level)
Compress data with zlib algorithm.
Definition: MCZipper.cpp:411
static void DecompressBzip2(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Decompress data with bzip2 algorithm.
Definition: MCZipper.cpp:515
int GetPosition() const
Get the current position in the binary data.
static void CompressQuickLz(const MCBinaryData &input_buffer, MCBinaryData &output_buffer)
Compress data with QuickLZ algorithm.
Definition: MCZipper.cpp:75
int GetSize() const
Get binary data size.