Euphoria
decompress.cc
Go to the documentation of this file.
1 // clang-tidy: ignore
2 #include "core/decompress.h"
3 
4 #include <cstring>
5 
6 #include "assert/assert.h"
7 
8 namespace eu::core
9 {
10 
11 unsigned int Decompressor::stb_decompress_length(const unsigned char *input)
12 {
13  return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
14 }
15 
16 void Decompressor::stb_match(const unsigned char *data, unsigned int length)
17 {
18  // INVERSE of memmove... write each byte before copying the next...
19  ASSERT(stb_dout + length <= stb_barrier_out_e);
20  if (stb_dout + length > stb_barrier_out_e) { stb_dout += length; return; }
21  if (data < stb_barrier_out_b) { stb_dout = stb_barrier_out_e+1; return; }
22  while (length--) *stb_dout++ = *data++;
23 }
24 
25 void Decompressor::stb_lit(const unsigned char *data, unsigned int length)
26 {
27  ASSERT(stb_dout + length <= stb_barrier_out_e);
28  if (stb_dout + length > stb_barrier_out_e) { stb_dout += length; return; }
29  if (data < stb_barrier_in_b) { stb_dout = stb_barrier_out_e+1; return; }
30  memcpy(stb_dout, data, length);
31  stb_dout += length;
32 }
33 
34 #define STB_IN2(x) ((i[x] << 8) + i[(x)+1])
35 #define STB_IN3(x) ((i[x] << 16) + STB_IN2((x)+1))
36 #define STB_IN4(x) ((i[x] << 24) + STB_IN3((x)+1))
37 
38 const unsigned char * Decompressor::stb_decompress_token(const unsigned char *i)
39 {
40  if (*i >= 0x20) { // use fewer if's for cases that expand small
41  if (*i >= 0x80) stb_match(stb_dout-i[1]-1, i[0] - 0x80 + 1), i += 2;
42  else if (*i >= 0x40) stb_match(stb_dout-(STB_IN2(0) - 0x4000 + 1), i[2]+1), i += 3;
43  else /* *i >= 0x20 */ stb_lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
44  } else { // more ifs for cases that expand large, since overhead is amortized
45  if (*i >= 0x18) stb_match(stb_dout-(STB_IN3(0) - 0x180000 + 1), i[3]+1), i += 4;
46  else if (*i >= 0x10) stb_match(stb_dout-(STB_IN3(0) - 0x100000 + 1), STB_IN2(3)+1), i += 5;
47  else if (*i >= 0x08) stb_lit(i+2, STB_IN2(0) - 0x0800 + 1), i += 2 + (STB_IN2(0) - 0x0800 + 1);
48  else if (*i == 0x07) stb_lit(i+3, STB_IN2(1) + 1), i += 3 + (STB_IN2(1) + 1);
49  else if (*i == 0x06) stb_match(stb_dout-(STB_IN3(1)+1), i[4]+1), i += 5;
50  else if (*i == 0x04) stb_match(stb_dout-(STB_IN3(1)+1), STB_IN2(4)+1), i += 6;
51  }
52  return i;
53 }
54 
55 unsigned int Decompressor::stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
56 {
57  const unsigned long ADLER_MOD = 65521;
58  unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
59  unsigned long blocklen, i;
60 
61  blocklen = buflen % 5552;
62  while (buflen) {
63  for (i=0; i + 7 < blocklen; i += 8) {
64  s1 += buffer[0], s2 += s1;
65  s1 += buffer[1], s2 += s1;
66  s1 += buffer[2], s2 += s1;
67  s1 += buffer[3], s2 += s1;
68  s1 += buffer[4], s2 += s1;
69  s1 += buffer[5], s2 += s1;
70  s1 += buffer[6], s2 += s1;
71  s1 += buffer[7], s2 += s1;
72 
73  buffer += 8;
74  }
75 
76  for (; i < blocklen; ++i)
77  s1 += *buffer++, s2 += s1;
78 
79  s1 %= ADLER_MOD, s2 %= ADLER_MOD;
80  buflen -= blocklen;
81  blocklen = 5552;
82  }
83  return (unsigned int)(s2 << 16) + (unsigned int)s1;
84 }
85 
86 unsigned int Decompressor::stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/)
87 {
88  unsigned int olen;
89  if (STB_IN4(0) != 0x57bC0000) return 0;
90  if (STB_IN4(4) != 0) return 0; // error! stream is > 4GB
91  olen = stb_decompress_length(i);
93  stb_barrier_out_e = output + olen;
94  stb_barrier_out_b = output;
95  i += 16;
96 
97  stb_dout = output;
98  for (;;) {
99  const unsigned char *old_i = i;
101  if (i == old_i) {
102  if (*i == 0x05 && i[1] == 0xfa) {
103  ASSERT(stb_dout == output + olen);
104  if (stb_dout != output + olen) return 0;
105  if (stb_adler32(1, output, olen) != (unsigned int) STB_IN4(2))
106  return 0;
107  return olen;
108  } else {
109  ASSERT(0); /* NOTREACHED */
110  return 0;
111  }
112  }
113  ASSERT(stb_dout <= output + olen);
114  if (stb_dout > output + olen)
115  return 0;
116  }
117 }
118 
119 
120 }
#define ASSERT(x)
Definition: assert.h:29
#define STB_IN2(x)
Definition: decompress.cc:34
#define STB_IN4(x)
Definition: decompress.cc:36
#define STB_IN3(x)
Definition: decompress.cc:35
std::string buffer
Definition: nlp_sentence.cc:87
unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int)
Definition: decompress.cc:86
static unsigned int stb_decompress_length(const unsigned char *input)
Definition: decompress.cc:11
void stb_match(const unsigned char *data, unsigned int length)
Definition: decompress.cc:16
const unsigned char * stb_decompress_token(const unsigned char *i)
Definition: decompress.cc:38
unsigned char * stb_barrier_out_e
Definition: decompress.h:21
const unsigned char * stb_barrier_in_b
Definition: decompress.h:22
unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
Definition: decompress.cc:55
unsigned char * stb_barrier_out_b
Definition: decompress.h:21
unsigned char * stb_dout
Definition: decompress.h:23
void stb_lit(const unsigned char *data, unsigned int length)
Definition: decompress.cc:25