31 #include <type_traits>
62 template<
typename InputFunctor,
typename OutputFunctor,
typename WindowFunctor>
63 int Deflate(InputFunctor&& input, OutputFunctor&& output, WindowFunctor&& outputcopy);
77 #ifndef DOXYGEN_SHOULD_SKIP_THIS
84 static constexpr
bool USE_BITARRAY_TEMPORARY_IN_HUFFMAN_CREATION =
false;
85 static constexpr
bool USE_BITARRAY_FOR_LENGTHS =
false;
86 static constexpr
bool USE_BITARRAY_FOR_HUFFNODES =
false;
88 static constexpr
unsigned MAX_WINDOW_SIZE = 32768u;
90 static_assert(MAX_WINDOW_SIZE >= 1,
"Max window size should be >= 1");
91 static_assert(MAX_WINDOW_SIZE <= 32768u,
"Window sizes larger than 32768 are not supported by deflate standard. Edit the source code to remove this assert if you need it.");
94 #define DEFLATE_USE_DATA_TABLES
96 #if !defined(DEFLATE_ALLOCATION_AUTOMATIC) && !defined(DEFLATE_ALLOCATION_STATIC) && !defined(DEFLATE_ALLOCATION_DYNAMIC)
98 #define DEFLATE_ALLOCATION_AUTOMATIC
103 constexpr
unsigned Flag_InputAbortable = 0x01;
104 constexpr
unsigned Flag_OutputAbortable = 0x02;
105 constexpr
unsigned Flag_TrackIn = 0x40;
106 constexpr
unsigned Flag_TrackOut = 0x80;
107 constexpr
unsigned Flag_NoTrackFlagMask = 0x03;
110 #ifdef DEFLATE_ALLOCATION_DYNAMIC
115 template<
typename U = std::u
int_least64_t>
116 struct RandomAccessBitArrayBase
119 static constexpr
unsigned Ubytes =
sizeof(U), Ubits = Ubytes*8;
121 static std::uint_fast64_t Get_Unclean(
unsigned Size,
const U* data,
unsigned index)
throw()
123 unsigned bitpos = index*Size, unitpos = bitpos / Ubits, shift = bitpos % Ubits;
124 std::uint_fast64_t result = data[unitpos] >> shift;
126 unsigned acquired = Ubits - shift;
127 for(; acquired < Size; acquired += Ubits)
129 result += (std::uint_fast64_t)data[++unitpos] << acquired;
134 template<
unsigned Size>
135 static std::uint_fast64_t Get(
const U* data,
unsigned index)
throw()
137 std::uint_fast64_t result = Get_Unclean(Size,data,index);
138 return (Size >=
sizeof(result)*8) ? result : (result & ((std::uint64_t(1) << Size)-1));
141 template<
unsigned Size,
bool update = false>
142 static void Set(U* data,
unsigned index, std::uint_fast64_t value)
throw()
144 unsigned bitpos = index*Size, unitpos = bitpos / Ubits, eat = 0;
149 if(Size % Ubits != 0)
151 unsigned shift = bitpos % Ubits;
152 eat = Ubits - shift;
if(eat > Size) eat = Size;
156 std::uint_fast64_t vmask = (std::uint64_t(1) << eat)-1;
158 data[unitpos] = (data[unitpos] & ~(vmask << shift)) | (value << shift);
160 data[unitpos] |= value << shift;
166 for(
unsigned remain = Size-eat; ; ++unitpos)
174 std::uint_fast64_t vmask = ((std::uint64_t(1) << eat)-1);
175 data[unitpos] = (data[unitpos] & ~vmask) | value;
179 data[unitpos] |= value;
185 data[unitpos] = value;
186 value >>= Ubits/2; value >>= Ubits/2;
194 template<
unsigned Nbits,
typename U = std::u
int_least64_t>
195 struct RandomAccessBitArray
197 static constexpr
unsigned Ubytes =
sizeof(U), Ubits = Ubytes*8, Nunits = (Nbits+Ubits-1)/Ubits;
200 template<
unsigned Size>
201 inline std::uint_fast64_t Get(
unsigned index)
const throw()
203 return RandomAccessBitArrayBase<U>::template Get<Size>(data, index);
206 template<
unsigned Size,
bool update = false>
207 inline void Set(
unsigned index, std::uint_fast64_t value)
throw()
209 RandomAccessBitArrayBase<U>::template Set<Size,update>(data, index, value);
218 template<
unsigned long N>
struct CeilLog2_s{
static constexpr
unsigned result = 1+CeilLog2_s<(N+1)/2>::result; };
219 template<>
struct CeilLog2_s<0> {
static constexpr
unsigned result = 0; };
220 template<>
struct CeilLog2_s<1> {
static constexpr
unsigned result = 0; };
221 template<
unsigned long N>
static constexpr
unsigned CeilLog2 = CeilLog2_s<N>::result;
224 template<
unsigned long N>
struct FloorLog2_s{
static constexpr
unsigned result = 1+FloorLog2_s<N/2>::result; };
225 template<>
struct FloorLog2_s<0> {
static constexpr
unsigned result = 0; };
226 template<>
struct FloorLog2_s<1> {
static constexpr
unsigned result = 0; };
227 template<
unsigned long N>
static constexpr
unsigned FloorLog2 = FloorLog2_s<N>::result;
230 template<
unsigned bits>
231 using SmallestType = std::conditional_t< (bits<=16),
232 std::conditional_t< (bits<= 8), std::uint_least8_t, std::uint_least16_t>,
233 std::conditional_t< (bits<=32), std::uint_least32_t, std::uint_least64_t>>;
236 static_assert(FloorLog2<1> == 0,
"FloorLog2 fail"); static_assert(CeilLog2<1> == 0,
"CeilLog2 fail");
237 static_assert(FloorLog2<2> == 1,
"FloorLog2 fail"); static_assert(CeilLog2<2> == 1,
"CeilLog2 fail");
238 static_assert(FloorLog2<3> == 1,
"FloorLog2 fail"); static_assert(CeilLog2<3> == 2,
"CeilLog2 fail");
239 static_assert(FloorLog2<4> == 2,
"FloorLog2 fail"); static_assert(CeilLog2<4> == 2,
"CeilLog2 fail");
240 static_assert(FloorLog2<5> == 2,
"FloorLog2 fail"); static_assert(CeilLog2<5> == 3,
"CeilLog2 fail");
241 static_assert(FloorLog2<6> == 2,
"FloorLog2 fail"); static_assert(CeilLog2<6> == 3,
"CeilLog2 fail");
242 static_assert(FloorLog2<7> == 2,
"FloorLog2 fail"); static_assert(CeilLog2<7> == 3,
"CeilLog2 fail");
243 static_assert(FloorLog2<8> == 3,
"FloorLog2 fail"); static_assert(CeilLog2<8> == 3,
"CeilLog2 fail");
244 static_assert(FloorLog2<9> == 3,
"FloorLog2 fail"); static_assert(CeilLog2<9> == 4,
"CeilLog2 fail");
246 template<
bool packed,
unsigned Dimension,
unsigned ElementSize>
247 struct RandomAccessArray {};
249 template<
unsigned Dim,
unsigned Elem>
250 struct RandomAccessArray<true, Dim, Elem>
252 RandomAccessBitArray<Dim*Elem> impl;
253 inline std::uint_fast64_t Get(
unsigned index)
const {
return impl.template Get<Elem>(index); }
254 inline void Set(
unsigned index, std::uint_fast32_t value) { impl.template Set<Elem,true>(index, value); }
255 inline void QSet(
unsigned index, std::uint_fast32_t value) { impl.template Set<Elem,false>(index, value); }
256 template<
unsigned Bits>
257 inline void WSet(
unsigned index, std::uint_fast64_t value) { impl.template Set<Bits,true>(index, value); }
260 template<
unsigned Dim,
unsigned Elem>
261 struct RandomAccessArray<false, Dim, Elem>
263 typedef SmallestType<Elem> E;
265 inline E Get(
unsigned index)
const {
return data[index]; }
266 inline void Set(
unsigned index, E value) { data[index] = value; }
267 inline void QSet(
unsigned index, E value) { data[index] = value; }
268 template<
unsigned Bits>
269 inline void WSet(
unsigned index, std::uint_fast64_t value)
272 for(
unsigned b=0; b<Bits; b+=Elem, value>>=Elem)
273 QSet(index++, (value % (1u << Elem)));
282 template<
bool Abortable,
unsigned A,
unsigned B,
typename LengthFunctor>
283 bool CreateHuffmanTree(
const char*
284 #ifdef DEFL_DO_HUFF_STATS
287 , RandomAccessArray<USE_BITARRAY_FOR_HUFFNODES,A,B>& tree,
289 LengthFunctor&& ReadLength)
throw()
298 constexpr
unsigned ElemBits = CeilLog2<A-15>;
299 static_assert((1u << B) >= (A-15),
"B is too small");
300 assert(num_values <= (A-15));
302 RandomAccessArray<USE_BITARRAY_TEMPORARY_IN_HUFFMAN_CREATION, 15, ElemBits> offs{};
306 tree.template WSet<(15*B + 63) & ~63>(0, 0);
308 #ifdef DEFL_DO_HUFF_STATS
309 unsigned largest_treetable_value = 0, largest_offs = 0, smallest_treetable_value = ~0u;
310 unsigned largest_treetrans_index=0, largest_treetrans_value=0;
311 unsigned longest_length = 0;
313 for(
unsigned a = 0; a < num_values; ++a)
315 int length = ReadLength(a);
316 if(Abortable && length < 0)
return true;
319 unsigned v = tree.Get(0 + length-1)+1;
320 #ifdef DEFL_DO_HUFF_STATS
321 largest_treetable_value = std::max(largest_treetable_value, v);
322 longest_length = std::max(longest_length,
unsigned(length));
325 tree.Set(0 + length-1, v);
334 for(
unsigned sum=0, a = 1; a < 16; ++a)
337 sum += tree.Get(0 + a-1);
339 #ifdef DEFL_DO_HUFF_STATS
340 for(
unsigned a=1; a<=longest_length; ++a)
341 smallest_treetable_value = std::min(smallest_treetable_value, (
unsigned)tree.Get(0 + a-1));
345 for(
unsigned value = 0; value < num_values; ++value)
347 int length = ReadLength(value);
348 if(Abortable && length < 0)
return true;
351 unsigned q = offs.Get(length-1); offs.Set(length-1, q+1);
352 #ifdef DEFL_DO_HUFF_STATS
353 largest_offs = std::max(q, largest_offs);
354 largest_treetrans_index = std::max(largest_treetrans_index, q);
355 largest_treetrans_value = std::max(largest_treetrans_value, value);
357 assert(q < num_values );
359 tree.Set(15 + q, value);
362 #ifdef DEFL_DO_HUFF_STATS
363 std::fprintf(stderr,
"Largest \"%12s\"(treetable_value=%4u..%4u, offs=%4u, treetrans_index=%4u, treetrans_value=%4u)\n",
364 why, smallest_treetable_value,largest_treetable_value,
365 largest_offs, largest_treetrans_index, largest_treetrans_value);
379 #ifdef DEFLATE_USE_DATA_TABLES
381 inline const std::uint_least8_t* GetBTable() throw()
383 static const std::uint_least8_t data[] {
385 0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224,255, 0,0,0,
390 3*3,17*3,15*3,13*3,11*3,9*3,7*3,5*3,4*3,6*3,8*3,10*3,12*3,14*3,16*3,18*3,0*3,1*3,2*3
403 inline unsigned lbase(
unsigned lencode) {
return GetBTable<>()[lencode-257+0] + 3; }
406 inline unsigned rshift(
unsigned a) {
return GetBTable<>()[a + 32]; }
408 inline unsigned lbase(
unsigned lencode) {
return (lencode > 285 ? 3 : ((lencode >= 265) ? (((lencode-257)%4+4) << ((lencode-257)/4-1)) + (lencode==285 ? 2 : 3) : (lencode-254))); }
409 inline unsigned rshift(
unsigned a) {
if(!a)
return 3*3;
else if(a>=16)
return (a-16)*3;
int r = 12 + 7*(a<8) - a*2;
return (r<0 ? -r : r)*3; }
411 inline unsigned dbase(
unsigned distcode) {
return (1 + (distcode>=4 ? ((2+distcode%2) << (distcode/2-1)) : distcode)); }
412 inline unsigned dbits(
unsigned distcode) {
return distcode>=4 ? distcode/2-1 : 0; }
413 inline unsigned lbits(
unsigned lencode) {
return ((lencode>=265 && lencode<285) ? ((lencode-265)/4+1) : 0); }
426 using remove_cvref_t = std::remove_reference_t<std::remove_cv_t<T>>;
430 static_assert((T)
false,
"result_of<CallableType> is invalid; use "
431 "result_of<CallableType(zero or more argument types)> instead.");
433 #if __cplusplus > 202000UL
434 template <
typename F,
typename... Args>
435 struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
437 template <
typename F,
typename... Args>
438 struct result_of<F(Args...)> : std::result_of<F(Args...)> {};
441 using result_of_t =
typename result_of<T>::type;
443 #define BEGIN_COND(name) \
444 template<typename T, typename=void> struct name : public std::false_type {}; \
445 template<typename T> struct name<T, std::enable_if_t<
446 #define END_COND(name) \
447 , void>> : public std::true_type {}; \
448 template<typename T> \
449 inline constexpr bool name ## _v = name<T>::value; \
452 BEGIN_COND(is_input_functor)
453 std::is_convertible_v<result_of_t<remove_cvref_t<T>()>,
int>
454 END_COND(is_input_functor)
455 BEGIN_COND(is_input_iterator)
456 std::is_convertible_v<typename std::iterator_traits<remove_cvref_t<T>>::value_type,
unsigned char>
457 && std::is_same_v<typename std::iterator_traits<remove_cvref_t<T>>::iterator_category, std::input_iterator_tag>
458 END_COND(is_input_iterator)
459 BEGIN_COND(is_bidir_input)
460 std::is_convertible_v<typename std::iterator_traits<remove_cvref_t<T>>::value_type,
unsigned char>
461 && (std::is_same_v<typename std::iterator_traits<remove_cvref_t<T>>::iterator_category, std::forward_iterator_tag>
462 || std::is_same_v<typename std::iterator_traits<remove_cvref_t<T>>::iterator_category, std::bidirectional_iterator_tag>
463 || std::is_same_v<typename std::iterator_traits<remove_cvref_t<T>>::iterator_category, std::random_access_iterator_tag>)
464 END_COND(is_bidir_input)
465 BEGIN_COND(is_size_type)
466 std::is_convertible_v<remove_cvref_t<T>, std::size_t> && !std::is_pointer_v<remove_cvref_t<T>>
467 END_COND(is_size_type)
469 BEGIN_COND(is_random_iterator)
470 std::is_convertible_v<typename std::iterator_traits<remove_cvref_t<T>>::value_type,
unsigned char>
471 && !std::is_const_v<typename std::iterator_traits<remove_cvref_t<T>>::reference>
472 && std::is_same_v<typename std::iterator_traits<remove_cvref_t<T>>::iterator_category, std::random_access_iterator_tag>
473 END_COND(is_random_iterator)
474 BEGIN_COND(is_output_iterator)
475 std::is_convertible_v<typename std::iterator_traits<remove_cvref_t<T>>::value_type,
unsigned char>
476 && !std::is_const_v<typename std::iterator_traits<remove_cvref_t<T>>::reference>
477 && !std::is_pointer_v<remove_cvref_t<T>>
478 && (std::is_same_v<typename std::iterator_traits<remove_cvref_t<T>>::iterator_category, std::output_iterator_tag>
479 || std::is_same_v<typename std::iterator_traits<remove_cvref_t<T>>::iterator_category, std::forward_iterator_tag>
480 || std::is_same_v<typename std::iterator_traits<remove_cvref_t<T>>::iterator_category, std::bidirectional_iterator_tag>)
481 END_COND(is_output_iterator)
483 BEGIN_COND(is_output_functor)
484 std::is_same_v<result_of_t<remove_cvref_t<T>(
int)>,
void> || std::is_convertible_v<result_of_t<remove_cvref_t<T>(
int)>,
bool>
485 END_COND(is_output_functor)
486 BEGIN_COND(is_window_functor)
487 std::is_same_v<result_of_t<remove_cvref_t<T>(
int,
int)>,
void> || std::is_convertible_v<result_of_t<remove_cvref_t<T>(
int,
int)>,
int>
488 END_COND(is_window_functor)
490 BEGIN_COND(is_abortable_input_type)
491 !(std::is_same_v<T, unsigned char> || std::is_same_v<T, signed char> || std::is_same_v<T, char>)
492 END_COND(is_abortable_input_type)
498 constexpr
bool DeflAbortable_InFun = is_abortable_input_type_v<remove_cvref_t<result_of_t<T()>>>;
500 constexpr
bool DeflAbortable_OutFun = std::is_same_v<result_of_t<T(
int)>,
bool>;
502 constexpr
bool DeflAbortable_WinFun = std::is_convertible_v<remove_cvref_t<result_of_t<T(
int,
int)>>,
int>;
504 template<
bool Abortable>
507 template<
typename OutputFunctor>
508 static inline bool output(OutputFunctor&& output,
unsigned char byte)
513 template<
typename WindowFunctor>
514 static inline bool outputcopy(WindowFunctor&& outputcopy, std::uint_least16_t length, std::uint_fast32_t offset)
516 outputcopy(length, offset);
522 struct OutputHelper<true>
524 template<
typename OutputFunctor>
525 static inline bool output(OutputFunctor&& output,
unsigned char byte)
529 template<
typename WindowFunctor>
530 static inline bool outputcopy(WindowFunctor&& outputcopy, std::uint_least16_t& length, std::uint_fast32_t offset)
532 length = outputcopy(length, offset);
537 struct SizeTracker_NoOutput
539 inline void OutByte() { }
540 inline void OutBytes(std::uint_fast64_t) { }
544 static inline constexpr T&& ForwardOutput(std::remove_reference_t<T>& fun) {
return static_cast<T&&
>(fun); }
546 static inline constexpr T&& ForwardOutput(std::remove_reference_t<T>&& fun) {
return static_cast<T&&
>(fun); }
549 static inline constexpr T&& ForwardWindow(std::remove_reference_t<T>& fun) {
return static_cast<T&&
>(fun); }
551 static inline constexpr T&& ForwardWindow(std::remove_reference_t<T>&& fun) {
return static_cast<T&&
>(fun); }
553 struct SizeTracker_NoInput
555 inline void InByte() { }
556 inline void InBytes(std::uint_fast64_t) { }
559 static inline constexpr T&& ForwardInput(std::remove_reference_t<T>& fun) {
return static_cast<T&&
>(fun); }
561 static inline constexpr T&& ForwardInput(std::remove_reference_t<T>&& fun) {
return static_cast<T&&
>(fun); }
563 struct SizeTracker_DoInput
565 std::uint_fast64_t insize=0;
567 inline void InByte() { ++insize; }
568 inline void InBytes(std::uint_fast64_t n) { insize += n; }
570 template<
typename InputFunctor, std::enable_if_t<!DeflAbortable_InFun<InputFunctor>,gunzip_ns::dummy>...>
571 auto ForwardInput(
const InputFunctor& input)
573 return [&]() { InByte();
return input(); };
576 template<
typename InputFunctor, std::enable_if_t<DeflAbortable_InFun<InputFunctor>,gunzip_ns::dummy>...>
577 auto ForwardInput(
const InputFunctor& input)
579 return [&]() {
auto r = input();
if(!(r & ~0xFF)) { InByte(); }
return r; };
582 struct SizeTracker_DoOutput
584 std::uint_fast64_t outsize=0;
586 inline void OutByte() { ++outsize; }
587 inline void OutBytes(std::uint_fast64_t n) { outsize += n; }
589 template<
typename OutputFunctor, std::enable_if_t<!DeflAbortable_OutFun<OutputFunctor>,gunzip_ns::dummy>...>
590 auto ForwardOutput(
const OutputFunctor& output)
592 return [&](
unsigned char byte) { OutByte();
return output(
byte); };
595 template<
typename OutputFunctor, std::enable_if_t<DeflAbortable_OutFun<OutputFunctor>,gunzip_ns::dummy>...>
596 auto ForwardOutput(
const OutputFunctor& output)
598 return [&](
unsigned char byte) {
auto r = output(
byte);
if(!r) { OutByte(); }
return r; };
601 template<
typename WindowFunctor, std::enable_if_t<!DeflAbortable_WinFun<WindowFunctor>,gunzip_ns::dummy>...>
602 auto ForwardWindow(
const WindowFunctor& outputcopy)
604 return [&](std::uint_least16_t length, std::uint_fast32_t offset)
607 return outputcopy(length, offset);
611 template<
typename WindowFunctor, std::enable_if_t<DeflAbortable_WinFun<WindowFunctor>,gunzip_ns::dummy>...>
612 auto ForwardWindow(
const WindowFunctor& outputcopy)
614 return [&](std::uint_least16_t length, std::uint_fast32_t offset)
616 auto remain = outputcopy(length, offset);
617 OutBytes(length - remain);
623 template<
typename TrackType>
624 struct SizeTracker:
public SizeTracker_NoOutput,
public SizeTracker_NoInput
626 inline int operator() (
int returncode)
const {
return returncode; }
629 struct SizeTracker<
DeflateTrackOutSize>:
public SizeTracker_NoInput,
public SizeTracker_DoOutput
631 typedef std::pair<int,std::uint_fast64_t> result;
632 inline result operator() (
int returncode)
const {
return result{returncode,outsize}; }
635 struct SizeTracker<
DeflateTrackInSize>:
public SizeTracker_NoOutput,
public SizeTracker_DoInput
637 typedef std::pair<int,std::uint_fast64_t> result;
638 inline result operator() (
int returncode)
const {
return result{returncode,insize}; }
641 struct SizeTracker<
DeflateTrackBothSize>:
public SizeTracker_DoInput,
public SizeTracker_DoOutput
643 typedef std::pair<int, std::pair<std::uint_fast64_t,std::uint_fast64_t>> result;
644 inline result operator() (
int returncode)
const {
return result{returncode,std::make_pair(insize,outsize)}; }
647 #ifdef DO_DEFDB_DUMPING
648 unsigned bitcounter=0;
650 struct DeflateBitCache
652 std::uint_least8_t BitCache = 0, BitCount = 0;
654 template<
bool Abortable,
typename InputFunctor>
655 std::uint_least64_t GetBits(InputFunctor&& input,
unsigned numbits)
657 #ifdef DO_DEFDB_DUMPING
658 bitcounter += numbits;
660 std::uint_fast64_t result = BitCache;
661 if(numbits <= BitCount)
664 BitCache >>= numbits;
665 result &= ((1u << numbits)-1);
668 for(
unsigned acquired = BitCount; ; acquired += 8)
670 unsigned byte = input();
671 if(Abortable && (
byte & ~0xFFu))
674 return ~std::uint_least64_t(0);
676 unsigned eat = numbits-acquired;
680 result |= ((std::uint_fast64_t)(
byte & ((1u << eat)-1))) << acquired;
682 BitCache =
byte >> eat;
685 result |= ((std::uint_fast64_t)(
byte)) << acquired;
689 template<
bool Abortable,
typename InputFunctor,
unsigned A,
unsigned B>
690 std::uint_least32_t HuffRead(InputFunctor&& input,
691 RandomAccessArray<USE_BITARRAY_FOR_HUFFNODES,A,B>& tree)
693 int sum=0, cur=0, len=0;
694 #ifdef DEFL_DO_HUFF_STATS
695 static int maxlen = 0;
699 auto p = GetBits<Abortable>(std::forward<InputFunctor>(input), 1);
703 return ~std::uint_least32_t(0);
705 cur = (unsigned(cur) << 1) |
bool(p);
706 #ifdef DEFL_DO_HUFF_STATS
710 std::fprintf(stderr,
"maxlen access: %d (%d)\n", maxlen, (
int)tree.Get(0 + len));
713 auto v = tree.Get(0 + len++);
717 return tree.Get(15 + sum + cur);
721 template<
bool Backtrackable>
722 struct DeflateState:
public DeflateBitCache
724 std::uint_least8_t lencode = 0, num = 0;
727 RandomAccessArray<USE_BITARRAY_FOR_LENGTHS, 288, CeilLog2<16>> Lengths;
731 RandomAccessArray<USE_BITARRAY_FOR_HUFFNODES, 15+288, CeilLog2<289>> ltree;
735 RandomAccessArray<USE_BITARRAY_FOR_HUFFNODES, 15+32, CeilLog2<33>> dtree;
737 RandomAccessArray<USE_BITARRAY_FOR_HUFFNODES, 15+32, CeilLog2<33>>& lltree = dtree;
745 template<
bool Abortable,
typename InputFunctor,
typename BacktrackFunctor>
746 auto DynTreeFunc(InputFunctor&& input, std::uint_fast16_t length, BacktrackFunctor&& ,
748 #ifdef DO_DEFDB_DUMPING
755 for(std::uint_fast16_t code = 0; ; )
757 #ifdef DO_DEFDB_DUMPING
758 unsigned bits_before=bitcounter;
762 auto p = HuffRead<Abortable>(std::forward<InputFunctor>(input), lltree);
763 if(Abortable && !~p) { error =
true;
goto done; }
764 std::uint_least8_t what = p;
766 if(!(what & 16)) { lencode = what * 0x11u; what = 0x01; }
767 else if(what < 17) { lencode = (lencode >> 4) * 0x11u; what = 0x23; }
768 else if(what == 17) { lencode = 0; what = 0x33; }
769 else { lencode = 0; what = 0x7B; }
771 p = GetBits<Abortable>(std::forward<InputFunctor>(input), what >> 4);
772 #ifdef DO_DEFDB_DUMPING
775 char tmp[64]=
"[_]"; sprintf(tmp,
"[%d]",
int(bitcounter-bits_before));
776 fprintf(stderr,
"%4s %cREP (%d times)\n", tmp, (lencode&0xF)?
'L':
'Z', p+(what&0xF));
780 if(Abortable && !~p) { error =
true;
goto done; }
781 num = p + (what & 0xF);
784 #ifdef DO_DEFDB_DUMPING
788 #ifdef DO_DEFDB_DUMPING
789 char tmp[64]=
"[_]";
if(!rep) sprintf(tmp,
"[%d]",
int(bitcounter-bits_before));
791 fprintf(stderr,
"%4s EofB CL (val:%2d)\n", tmp,
int(lencode&0xF));
793 fprintf(stderr,
"%4s d_%02d CL (val:%2d)\n", tmp,
int(code),
int(lencode&0xF));
794 else if(code > 0x100)
795 fprintf(stderr,
"%4s l_%02d CL (val:%2d)\n", tmp,
int(code- 0x101),
int(lencode&0xF));
797 fprintf(stderr,
"%4s 0x%02X CL (val:%2d)\n", tmp, (
int)code,
int(lencode&0xF));
801 Lengths.QSet(code++, lencode & 0xF);
802 if(code == length) {
goto done; }
806 return [
this,error](
unsigned index) -> std::conditional_t<Abortable, int, unsigned char>
808 if(Abortable && error)
return -1;
809 return Lengths.Get(index);
815 struct DeflateState<true>:
public DeflateBitCache
820 RandomAccessArray<USE_BITARRAY_FOR_HUFFNODES, 15+288, CeilLog2<289>> ltree;
825 RandomAccessArray<USE_BITARRAY_FOR_HUFFNODES, 15+32, CeilLog2<33>> dtree;
830 RandomAccessArray<USE_BITARRAY_FOR_HUFFNODES, 15+19, CeilLog2<20>> lltree;
838 std::uint_least8_t lencode, num;
839 std::uint_least8_t checkpoint_lencode, checkpoint_num;
840 std::uint_least8_t checkpoint_BitCache, checkpoint_BitCount;
842 template<
bool Abortable,
typename InputFunctor,
typename BacktrackFunctor>
843 auto DynTreeFunc(InputFunctor&& input, std::uint_fast16_t , BacktrackFunctor&& backtrack,
845 #ifdef DO_DEFDB_DUMPING
851 checkpoint_lencode = 0;
853 checkpoint_BitCache = BitCache;
854 checkpoint_BitCount = BitCount;
857 return [
this,&input,&backtrack](
unsigned index) -> std::conditional_t<Abortable, int, unsigned char>
862 lencode = checkpoint_lencode;
863 num = checkpoint_num;
864 BitCache = checkpoint_BitCache;
865 BitCount = checkpoint_BitCount;
869 if(Abortable && (num==0xFF))
return -1;
873 auto p = HuffRead<Abortable>(std::forward<InputFunctor>(input), lltree);
874 if(Abortable && !~p) { num = 0xFF;
return -1; }
875 std::uint_least8_t what = p;
877 if(!(what & 16)) { lencode = what * 0x11u; what = 0x01; }
878 else if(what < 17) { lencode = (lencode >> 4) * 0x11u; what = 0x23; }
879 else if(what == 17) { lencode = 0; what = 0x33; }
880 else { lencode = 0; what = 0x7B; }
882 p = GetBits<Abortable>(std::forward<InputFunctor>(input), what >> 4);
884 if(Abortable && !~p) { num = 0xFF;
return -1; }
885 num = p + (what & 0xF);
888 return (lencode & 0xF);
895 unsigned char Data[gunzip_ns::MAX_WINDOW_SIZE];
896 SmallestType<CeilLog2<gunzip_ns::MAX_WINDOW_SIZE>> Head = 0;
899 #ifdef DEFLATE_ALLOCATION_STATIC
900 template<
typename ObjectType>
901 ObjectType& GetStaticObj()
903 static thread_local ObjectType obj;
905 new(&obj) ObjectType();
925 template<
unsigned char Abortable,
926 typename InputFunctor,
typename OutputFunctor,
typename WindowFunctor,
927 typename BacktrackFunctor>
928 int Gunzip(InputFunctor&& input,
929 OutputFunctor&& output,
930 WindowFunctor&& outputcopy,
931 BacktrackFunctor&& backtrack)
933 using namespace gunzip_ns;
935 typedef DeflateState<!std::is_same_v<remove_cvref_t<BacktrackFunctor>,dummy>> StateType;
936 #ifdef DEFLATE_ALLOCATION_AUTOMATIC
938 #elif defined(DEFLATE_ALLOCATION_STATIC)
939 auto& state = gunzip_ns::GetStaticObj<StateType>();
940 #elif defined(DEFLATE_ALLOCATION_DYNAMIC)
941 std::unique_ptr<StateType> stateptr(
new StateType);
942 auto& state = *stateptr;
949 #define DummyGetBits(numbits) do { \
950 auto p = state.template GetBits<bool(Abortable&Flag_InputAbortable)>(std::forward<InputFunctor>(input), numbits); \
951 if((Abortable & Flag_InputAbortable) && !~p) return -2; \
954 #define GetBits(numbits, target) \
955 auto p = state.template GetBits<bool(Abortable&Flag_InputAbortable)>(std::forward<InputFunctor>(input), numbits); \
956 if((Abortable & Flag_InputAbortable) && !~p) return -2; \
960 #define HuffRead(tree, target) \
961 auto p = state.template HuffRead<bool(Abortable&Flag_InputAbortable)>(std::forward<InputFunctor>(input), tree); \
962 if((Abortable & Flag_InputAbortable) && !~p) return -2; \
965 #define Fail_If(condition) do { \
967 if(condition) return -1; \
971 GetBits(16, std::uint_least16_t header);
976 GetBits(64, header); Fail_If((header & 0xFF) != 8);
978 { GetBits(16, std::uint_fast16_t q); DummyGetBits(8*q); }
979 if(header&0x0800)
for(;;) { GetBits(8,
bool q);
if(!q)
break; }
980 if(header&0x1000)
for(;;) { GetBits(8,
bool q);
if(!q)
break; }
981 if(header&0x0200) { DummyGetBits(16); }
982 outputcopy(0, 32768u);
986 Fail_If((header & 0x208F) != 0x0008 || ((((header<<8)+(header>>8))&0xFFFF)%31) != 0);
987 outputcopy(0, 256 << ((header >> 4) & 0xF));
998 std::uint_least16_t nlen_ndist_ncode;
999 GetBits(14, nlen_ndist_ncode);
1001 #define nlen (((nlen_ndist_ncode >> 0u) & 0x1Fu) + 257u)
1002 #define ndist (((nlen_ndist_ncode >> 5u) & 0x1Fu) + 1u)
1005 std::uint_least8_t ncode = ((nlen_ndist_ncode >> 10u) + 4u);
1006 {std::uint_fast64_t lenlens; GetBits(ncode*3, lenlens);
1007 #ifdef DO_DEFDB_DUMPING
1008 fprintf(stderr,
" [5] HLIT%5d (val:%d)\n [5] HDIST%4d (val:%d)\n [4] HCLEN%4d (val:%d)\n",
1009 nlen,nlen-257, ndist,ndist-1, ncode,ncode-4);
1010 for(
unsigned a=0; a<19; ++a)
1011 for(
unsigned b=0; b<19; ++b)
1012 if(rshift(b) == 3*a)
1015 fprintf(stderr,
" [3]%3d CLL (val: %d)\n", b,
int((lenlens >> rshift(b)) & 7));
1017 fprintf(stderr,
" [_]%3d CLL (val: %d)\n", b,
int((lenlens >> rshift(b)) & 7));
1021 auto lltree_fun = [=](
unsigned a) ->
unsigned char {
return (lenlens >> rshift(a)) & 7; };
1022 while(CreateHuffmanTree<
bool(Abortable&Flag_InputAbortable)>(
"Len Lengths", state.lltree, 19, lltree_fun)) {
return -2; }}
1024 {
auto ltree_fun = state.template DynTreeFunc<bool(Abortable&Flag_InputAbortable)>(std::forward<InputFunctor>(input), nlen, std::forward<BacktrackFunctor>(backtrack),
false);
1025 while(CreateHuffmanTree<
bool(Abortable&Flag_InputAbortable)>(
"Dyn Lengths", state.ltree, nlen, ltree_fun)) {
return -2; }}
1027 {
auto dtree_fun = state.template DynTreeFunc<bool(Abortable&Flag_InputAbortable)>(std::forward<InputFunctor>(input), ndist, std::forward<BacktrackFunctor>(backtrack),
true);
1028 while(CreateHuffmanTree<
bool(Abortable&Flag_InputAbortable)>(
"Dyn Dists", state.dtree, ndist, dtree_fun)) {
return -2; }}
1037 DummyGetBits(state.BitCount%8);
1038 GetBits(32, std::uint_least32_t a);
1039 Fail_If(((a ^ (a >> 16)) & 0xFFFF) != 0xFFFF);
1040 #ifdef DO_DEFDB_DUMPING
1041 fprintf(stderr,
"raw block of %d bytes (0x%X)\n", (
unsigned short)a, a);
1047 GetBits(8,
unsigned char octet);
1048 while(OutputHelper<
bool(Abortable&Flag_OutputAbortable)>::output(output, octet)) {
return -3; }
1053 unsigned char (*ltree_fun)(unsigned) = [](
unsigned n)->unsigned
char{
return (n<0x90 || n>=0x118) ? 8u : (n<0x100 ? 9u : 7u); };
1054 unsigned char (*dtree_fun)(unsigned) = [](
unsigned )->unsigned
char{
return 5u;};
1055 while(CreateHuffmanTree<false>(
"Stat Lengths", state.ltree, 288, ltree_fun)) {
return -2; }
1056 while(CreateHuffmanTree<false>(
"Stat Dists", state.dtree, 32, dtree_fun)) {
return -2; }
1061 #ifdef DO_DEFDB_DUMPING
1062 unsigned a=bitcounter;
1064 HuffRead(state.ltree, std::uint_least16_t lencode);
1065 if(!(lencode & -256))
1067 #ifdef DO_DEFDB_DUMPING
1068 {
char tmp[64];sprintf(tmp,
"[%d]",bitcounter-a); fprintf(stderr,
"%4s %02X\n", tmp, lencode);}
1070 while(OutputHelper<
bool(Abortable&Flag_OutputAbortable)>::output(output, lencode)) {
return -3; }
1072 else if(!(lencode & 0xFF))
break;
1075 GetBits(lbits(lencode), std::uint_least16_t length); length += lbase(lencode);
1076 {HuffRead(state.dtree, std::uint_least8_t distcode);
1077 {GetBits(dbits(distcode), std::uint_least32_t offset); offset += dbase(distcode);
1078 #ifdef DO_DEFDB_DUMPING
1079 {
char tmp[64];sprintf(tmp,
"[%d]",bitcounter-a); fprintf(stderr,
"%4s (%d,%d)\n", tmp,length,offset);}
1081 while(OutputHelper<
bool(Abortable&Flag_OutputAbortable)>::outputcopy(outputcopy,length,offset)) {
return -4; }}}
1084 skipdef:
if(header & 1)
break;
1123 #ifdef DEFLATE_ALLOCATION_AUTOMATIC
1124 #define DeflDeclWindow gunzip_ns::DeflateWindow window;
1125 #elif defined(DEFLATE_ALLOCATION_STATIC)
1126 #define DeflDeclWindow auto& window = gunzip_ns::GetStaticObj<gunzip_ns::DeflateWindow>();
1127 #elif defined(DEFLATE_ALLOCATION_DYNAMIC)
1128 #define DeflDeclWindow std::unique_ptr<gunzip_ns::DeflateWindow> winptr(new gunzip_ns::DeflateWindow); \
1129 auto& window = *winptr;
1132 template<
unsigned char code,
typename I,
typename O,
typename C,
typename B>
1133 auto DeflateDispatchFinal(I&& i, O&& o, C&& c, B&& b)
1135 if constexpr(code & (Flag_TrackIn | Flag_TrackOut))
1138 SizeTracker<DeflateTrackBothSize> tracker;
1139 return tracker(Gunzip<code & Flag_NoTrackFlagMask>
1140 (tracker.template ForwardInput(i), tracker.template ForwardOutput(o), tracker.template ForwardWindow(c), std::forward<B>(b)));
1142 else if constexpr(code & Flag_TrackIn)
1145 SizeTracker<DeflateTrackInSize> tracker;
1146 return tracker(Gunzip<code & Flag_NoTrackFlagMask>
1147 (tracker.template ForwardInput(i),std::forward<O>(o),std::forward<C>(c),std::forward<B>(b)));
1149 else if constexpr(code & Flag_TrackOut)
1152 SizeTracker<DeflateTrackOutSize> tracker;
1153 return tracker(Gunzip<code & Flag_NoTrackFlagMask>
1154 (std::forward<I>(i), tracker.template ForwardOutput(o), tracker.template ForwardWindow(c), std::forward<B>(b)));
1159 return Gunzip<code & Flag_NoTrackFlagMask>(std::forward<I>(i),std::forward<O>(o),std::forward<C>(c),std::forward<B>(b));
1164 template<
unsigned char code,
typename BtFun,
typename InFun,
typename T1>
1165 auto DeflateOutputDispatch(BtFun&& bt, InFun&& infun, T1&& param1)
1168 if constexpr(is_random_iterator_v<T1>)
1171 auto output = [&](
unsigned char l) { *param1 = l; ++param1; };
1172 auto outputcopy = [&](std::uint_least16_t length, std::uint_fast32_t offs)
1175 for(; length--; ++param1) { *param1 = *(param1-offs); }
1177 return DeflateDispatchFinal<code>(std::forward<InFun>(infun), output, outputcopy, std::forward<BtFun>(bt));
1180 else if constexpr(is_output_iterator_v<T1>)
1184 auto output = [&](
unsigned char l)
1186 window.Data[window.Head++ % MAX_WINDOW_SIZE] = l;
1187 *param1 = l; ++param1;
1189 auto outputcopy = [&](std::uint_least16_t length, std::uint_fast32_t offs)
1192 for(; length>0; --length)
1194 unsigned char byte = window.Data[(window.Head - offs) % MAX_WINDOW_SIZE];
1199 return DeflateDispatchFinal<code>(std::forward<InFun>(infun), output, outputcopy, std::forward<BtFun>(bt));
1202 else if constexpr(is_output_functor_v<T1>)
1206 auto output = [&](
unsigned char l)
1208 window.Data[window.Head++ % MAX_WINDOW_SIZE] = l;
1211 auto outputcopy = [&](std::uint_least16_t length, std::uint_fast32_t offs)
1214 for(; length>0; --length)
1216 unsigned char byte = window.Data[(window.Head - offs) % MAX_WINDOW_SIZE];
1217 if(OutputHelper<DeflAbortable_OutFun<T1>>::output(output,
byte))
1222 return DeflateDispatchFinal
1223 <code | (DeflAbortable_OutFun<T1> ? Flag_OutputAbortable : 0)>
1224 (std::forward<InFun>(infun), output, outputcopy, std::forward<BtFun>(bt));
1229 static_assert(code==0xFF,
"Deflate: Unknown output parameter type");
1234 template<
unsigned char code,
typename BtFun,
typename InFun,
typename T1,
typename T2>
1235 auto DeflateOutputDispatch(BtFun&& bt, InFun&& infun, T1&& param1, T2&& param2)
1240 return DeflateOutputDispatch<code> (std::forward<BtFun>(bt), std::forward<InFun>(infun), std::forward<T1>(param1));
1245 return DeflateOutputDispatch<code | Flag_TrackIn> (std::forward<BtFun>(bt), std::forward<InFun>(infun), std::forward<T1>(param1));
1250 return DeflateOutputDispatch<code | Flag_TrackOut> (std::forward<BtFun>(bt), std::forward<InFun>(infun), std::forward<T1>(param1));
1255 return DeflateOutputDispatch<code | Flag_TrackIn | Flag_TrackOut> (std::forward<BtFun>(bt), std::forward<InFun>(infun), std::forward<T1>(param1));
1258 else if constexpr(std::is_same_v<T1,T2> && is_random_iterator_v<T1>)
1261 auto output = [&](
unsigned char l)
1263 if(param1 == param2)
return true;
1264 *param1 = l; ++param1;
1267 auto outputcopy = [&](std::uint_least16_t length, std::uint_fast32_t offs)
1270 for(; length > 0 && !(param1 == param2); --length, ++param1)
1272 *param1 = *(param1 - offs);
1276 return DeflateDispatchFinal<code | Flag_OutputAbortable>(std::forward<InFun>(infun), output, outputcopy, std::forward<BtFun>(bt));
1279 else if constexpr(is_size_type_v<T2> && is_random_iterator_v<T1>)
1282 typename std::iterator_traits<remove_cvref_t<T1>>::difference_type used{}, cap=param2;
1283 auto output = [&](
unsigned char l)
1285 if(used >= cap)
return true;
1286 param1[used] = l; ++used;
1289 auto outputcopy = [&](std::uint_least16_t length, std::uint_fast32_t offs)
1292 for(; length > 0 && used < cap; ++used, --length)
1294 param1[used] = param1[used - offs];
1298 return DeflateDispatchFinal<code | Flag_OutputAbortable>(std::forward<InFun>(infun), output, outputcopy, std::forward<BtFun>(bt));
1301 else if constexpr(is_output_functor_v<T1> && is_window_functor_v<T2>)
1304 return DeflateDispatchFinal
1305 <code | ( (DeflAbortable_OutFun<T1> && DeflAbortable_WinFun<T2>) ? Flag_OutputAbortable : 0 ) >
1306 (std::forward<InFun>(infun), std::forward<T1>(param1), std::forward<T2>(param2), std::forward<BtFun>(bt));
1311 static_assert(code==0xFF,
"Deflate: Unknown output parameter type");
1316 template<
unsigned char code,
typename BtFun,
typename InFun,
typename T1,
typename T2,
typename T3>
1317 auto DeflateOutputDispatch(BtFun&& bt, InFun&& infun, T1&& p1, T2&& p2, T3)
1322 return DeflateOutputDispatch<code> (std::forward<BtFun>(bt), std::forward<InFun>(infun), std::forward<T1>(p1), std::forward<T2>(p2));
1327 return DeflateOutputDispatch<code | Flag_TrackIn> (std::forward<BtFun>(bt), std::forward<InFun>(infun), std::forward<T1>(p1), std::forward<T2>(p2));
1332 return DeflateOutputDispatch<code | Flag_TrackOut> (std::forward<BtFun>(bt), std::forward<InFun>(infun), std::forward<T1>(p1), std::forward<T2>(p2));
1337 return DeflateOutputDispatch<code | Flag_TrackIn | Flag_TrackOut> (std::forward<BtFun>(bt), std::forward<InFun>(infun), std::forward<T1>(p1), std::forward<T2>(p2));
1342 static_assert(code==0xFF,
"Deflate: Mismatched parameters. Expected last parameter to be a DeflateTrack option.");
1347 template<
unsigned char code,
typename BtFun,
typename T1,
typename T2,
typename... T>
1348 auto DeflateInputDispatch(BtFun&& bt, T1&& param1, T2&& param2, T&&... args)
1350 using namespace gunzip_ns;
1352 if constexpr(std::is_same_v<T1, T2> && is_input_iterator_v<T1>)
1355 auto inputfun = [&]() -> std::common_type_t<
int, decltype(*param1)>
1356 {
if(param1 == param2) {
return -1; }
int r = *param1; ++param1;
return r; };
1357 return DeflateOutputDispatch<code|Flag_InputAbortable>(std::forward<BtFun>(bt), inputfun, std::forward<T>(args)...);
1360 else if constexpr(std::is_same_v<T1, T2> && is_bidir_input_v<T1>)
1363 remove_cvref_t<T1> saved{param1};
1364 auto btfun = [&](
bool act) {
if(act) param1 = saved;
else saved = std::move(param1); };
1365 auto inputfun = [&]() -> std::common_type_t<
int, decltype(*param1)>
1366 {
if(param1 == param2) {
return -1; }
int r = *param1; ++param1;
return r; };
1367 return DeflateOutputDispatch<code|Flag_InputAbortable>(btfun, inputfun, std::forward<T>(args)...);
1370 else if constexpr(is_size_type_v<T2> && is_input_iterator_v<T1>)
1373 typename std::iterator_traits<remove_cvref_t<T1>>::difference_type remain{param2};
1374 auto inputfun = [&]() -> std::common_type_t<
int, decltype(*param1)>
1375 {
if(!remain)
return -1; --remain;
int r = *param1; ++param1;
return r; };
1376 return DeflateOutputDispatch<code|Flag_InputAbortable>(std::forward<BtFun>(bt), inputfun, std::forward<T>(args)...);
1379 else if constexpr(is_size_type_v<T2> && is_bidir_input_v<T1>)
1382 typename std::iterator_traits<remove_cvref_t<T1>>::difference_type remain{param2}, savestate{};
1383 auto btfun = [&](
bool act) {
if(act) { param1 -= (savestate-remain); remain = savestate; }
else savestate = remain; };
1384 auto inputfun = [&]() -> std::common_type_t<
int, decltype(*param1)>
1385 {
if(!remain)
return -1; --remain;
int r = *param1; ++param1;
return r; };
1386 return DeflateOutputDispatch<code|Flag_InputAbortable>(btfun, inputfun, std::forward<T>(args)...);
1389 else if constexpr(is_input_iterator_v<T1>)
1392 auto inputfun = [&]() -> std::remove_cv_t<decltype(*param1)> {
auto r = *param1; ++param1;
return r; };
1393 return DeflateOutputDispatch
1394 <code | ( is_abortable_input_type_v<remove_cvref_t<decltype(*param1)>> ? Flag_InputAbortable : 0 ) >
1395 (std::forward<BtFun>(bt), inputfun, std::forward<T2>(param2), std::forward<T>(args)...);
1398 else if constexpr(is_bidir_input_v<T1>)
1401 remove_cvref_t<T1> saved{param1};
1402 auto btfun = [&](
bool act) {
if(act) param1 = saved;
else saved = std::move(param1); };
1403 auto inputfun = [&]() -> std::remove_cv_t<decltype(*param1)> {
auto r = *param1; ++param1;
return r; };
1404 return DeflateOutputDispatch<code>(btfun, inputfun, std::forward<T2>(param2), std::forward<T>(args)...);
1407 else if constexpr(is_input_functor_v<T1>)
1410 return DeflateOutputDispatch
1411 <code | ( DeflAbortable_InFun<T1> ? Flag_InputAbortable : 0 ) >
1412 (std::forward<BtFun>(bt), std::forward<T1>(param1), std::forward<T2>(param2), std::forward<T>(args)...);
1417 static_assert(code==0xFF,
"Deflate: Mismatched parameters. Expected something for an input.");
1420 #undef DeflDeclWindow
1424 template<
typename... T>
1425 auto Deflate(T&&... args)
1427 return gunzip_ns::DeflateInputDispatch<0>(gunzip_ns::dummy{}, std::forward<T>(args)...);