8 data_error::data_error(const char* errmsg
) : std::runtime_error(errmsg
) {}
10 input_stream::~input_stream()
14 inline void reload(input_stream
& in
, unsigned char& byte
, unsigned char& bits
)
18 int r
= in
.read("Unexpected end of compressed data");
25 inline bool read1(input_stream
& in
, unsigned char& byte
, unsigned char& bits
)
28 reload(in
, byte
, bits
);
29 bool ret
= ((byte
& 0x80) != 0);
36 inline size_t read_n(input_stream
& in
, unsigned char& byte
, unsigned char& bits
, unsigned count
)
42 //Satisfiable immediately.
43 size_t ret
= byte
>> (8 - count
);
50 //Read the first incomplete byte if any.
52 ret
= byte
>> (8 - bits
);
56 //Read complete bytes.
57 while(readc
+ 8 <= count
) {
58 int r
= in
.read("Unexpected end of compressed data");
59 ret
= (ret
<< 8) | (r
& 0xFF);
62 size_t tailbits
= count
- readc
;
65 reload(in
, byte
, bits
);
66 ret
= (ret
<< tailbits
) | (byte
>> (8 - tailbits
));
73 void lzs_decompress(input_stream
& in
, output_stream
& out
, size_t size
)
75 unsigned char cbits
= in
.read("Incomplete compression header");
76 unsigned char sbits
= in
.read("Incomplete compression header");
77 unsigned char lbits
= in
.read("Incomplete compression header");
78 size_t maxbits
= sizeof(size_t) * CHAR_BIT
;
79 if((sbits
>= maxbits
|| lbits
>= maxbits
) || (sbits
== maxbits
- 1 && lbits
== maxbits
- 1))
80 throw data_error("Can't handle the backward offset space");
82 throw data_error("Can't handle the copy length space");
84 size_t maxoffset
= 2 + (size_t(1) << sbits
) + (size_t(1) << lbits
);
86 size_t longbias
= 2 + (size_t(1) << sbits
);
87 maxoffset
= (size
< maxoffset
) ? size
: maxoffset
;
88 std::vector
<unsigned char> tmp
;
89 tmp
.resize(maxoffset
);
91 uint8_t pending_byte
= 0;
92 uint8_t pending_bits
= 0;
94 size_t copy_remaining
= 0;
95 size_t copy_backward
= 0;
96 size_t cyclic_pointer
= 0;
97 while(output
< size
) {
98 assert(pending_bits
<= 8);
101 if(copy_backward
<= cyclic_pointer
)
102 cindex
= cyclic_pointer
- copy_backward
;
104 cindex
= maxoffset
+ cyclic_pointer
- copy_backward
;
106 out
.put(tmp
[cyclic_pointer
++] = tmp
[cindex
]);
107 if(cyclic_pointer
== maxoffset
)
112 if(read1(in
, pending_byte
, pending_bits
)) {
113 if(read1(in
, pending_byte
, pending_bits
)) {
115 out
.put(tmp
[cyclic_pointer
++] = static_cast<unsigned char>(read_n(in
,
116 pending_byte
, pending_bits
, 8)));
117 if(cyclic_pointer
== maxoffset
)
122 copy_backward
= longbias
+ read_n(in
, pending_byte
, pending_bits
, lbits
);
123 copy_remaining
= 2 + read_n(in
, pending_byte
, pending_bits
, cbits
);
124 if(copy_backward
> output
)
125 throw data_error("Backward copy offset too large");
129 copy_backward
= shortbias
+ read_n(in
, pending_byte
, pending_bits
, sbits
);
130 copy_remaining
= 2 + read_n(in
, pending_byte
, pending_bits
, cbits
);
131 if(copy_backward
> output
)
132 throw data_error("Backward copy offset too large");