1
+ /*
2
+ This file is part of the ArduinoIoTCloud library.
3
+
4
+ Copyright (c) 2024 Arduino SA
5
+
6
+ This Source Code Form is subject to the terms of the Mozilla Public
7
+ License, v. 2.0. If a copy of the MPL was not distributed with this
8
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
9
+
10
+ This implementation took inspiration from https://okumuralab.org/~okumura/compression/lzss.c source code
11
+ */
12
+
13
+ /* *************************************************************************************
14
+ INCLUDE
15
+ **************************************************************************************/
16
+ #include " lzssDecoder.h"
17
+
18
+ #include < stdlib.h>
19
+
20
+ /* *************************************************************************************
21
+ LZSS DECODER CLASS IMPLEMENTATION
22
+ **************************************************************************************/
23
+
24
+ // get the number of bits the algorithm will try to get given the state
25
+ uint8_t LZSSDecoder::bits_required (LZSSDecoder::FSM_STATES s) {
26
+ switch (s) {
27
+ case FSM_0:
28
+ return 1 ;
29
+ case FSM_1:
30
+ return 8 ;
31
+ case FSM_2:
32
+ return EI;
33
+ case FSM_3:
34
+ return EJ;
35
+ default :
36
+ return 0 ;
37
+ }
38
+ }
39
+
40
+ LZSSDecoder::LZSSDecoder (std::function<int ()> getc_cbk, std::function<void(const uint8_t )> putc_cbk)
41
+ : available(0 ), state(FSM_0), put_char_cbk(putc_cbk), get_char_cbk(getc_cbk) {
42
+ for (int i = 0 ; i < N - F; i++) buffer[i] = ' ' ;
43
+ r = N - F;
44
+ }
45
+
46
+
47
+ LZSSDecoder::LZSSDecoder (std::function<void (const uint8_t )> putc_cbk)
48
+ : available(0 ), state(FSM_0), put_char_cbk(putc_cbk), get_char_cbk(nullptr ) {
49
+ for (int i = 0 ; i < N - F; i++) buffer[i] = ' ' ;
50
+ r = N - F;
51
+ }
52
+
53
+ LZSSDecoder::status LZSSDecoder::handle_state () {
54
+ LZSSDecoder::status res = IN_PROGRESS;
55
+
56
+ int c = getbit (bits_required (this ->state ));
57
+
58
+ if (c == LZSS_BUFFER_EMPTY) {
59
+ res = NOT_COMPLETED;
60
+ } else if (c == LZSS_EOF) {
61
+ res = DONE;
62
+ this ->state = FSM_EOF;
63
+ } else {
64
+ switch (this ->state ) {
65
+ case FSM_0:
66
+ if (c) {
67
+ this ->state = FSM_1;
68
+ } else {
69
+ this ->state = FSM_2;
70
+ }
71
+ break ;
72
+ case FSM_1:
73
+ putc (c);
74
+ buffer[r++] = c;
75
+ r &= (N - 1 ); // equivalent to r = r % N when N is a power of 2
76
+
77
+ this ->state = FSM_0;
78
+ break ;
79
+ case FSM_2:
80
+ this ->i = c;
81
+ this ->state = FSM_3;
82
+ break ;
83
+ case FSM_3: {
84
+ int j = c;
85
+
86
+ // This is where the actual decompression takes place: we look into the local buffer for reuse
87
+ // of byte chunks. This can be improved by means of memcpy and by changing the putc function
88
+ // into a put_buf function in order to avoid buffering on the other end.
89
+ // TODO improve this section of code
90
+ for (int k = 0 ; k <= j + 1 ; k++) {
91
+ c = buffer[(this ->i + k) & (N - 1 )]; // equivalent to buffer[(i+k) % N] when N is a power of 2
92
+ putc (c);
93
+ buffer[r++] = c;
94
+ r &= (N - 1 ); // equivalent to r = r % N
95
+ }
96
+ this ->state = FSM_0;
97
+
98
+ break ;
99
+ }
100
+ case FSM_EOF:
101
+ break ;
102
+ }
103
+ }
104
+
105
+ return res;
106
+ }
107
+
108
+ LZSSDecoder::status LZSSDecoder::decompress (uint8_t * const buffer, uint32_t size) {
109
+ if (!get_char_cbk) {
110
+ this ->in_buffer = buffer;
111
+ this ->available += size;
112
+ }
113
+
114
+ status res = IN_PROGRESS;
115
+
116
+ while ((res = handle_state ()) == IN_PROGRESS);
117
+
118
+ this ->in_buffer = nullptr ;
119
+
120
+ return res;
121
+ }
122
+
123
+ int LZSSDecoder::getbit (uint8_t n) { // get n bits from buffer
124
+ int x=0 , c;
125
+
126
+ // if the local bit buffer doesn't have enough bit get them
127
+ while (buf_size < n) {
128
+ switch (c=getc ()) {
129
+ case LZSS_EOF:
130
+ case LZSS_BUFFER_EMPTY:
131
+ return c;
132
+ }
133
+ buf <<= 8 ;
134
+
135
+ buf |= (uint8_t )c;
136
+ buf_size += sizeof (uint8_t )*8 ;
137
+ }
138
+
139
+ // the result is the content of the buffer starting from msb to n successive bits
140
+ x = buf >> (buf_size-n);
141
+
142
+ // remove from the buffer the read bits with a mask
143
+ buf &= (1 <<(buf_size-n))-1 ;
144
+
145
+ buf_size-=n;
146
+
147
+ return x;
148
+ }
149
+
150
+ int LZSSDecoder::getc () {
151
+ int c;
152
+
153
+ if (get_char_cbk) {
154
+ c = get_char_cbk ();
155
+ } else if (in_buffer == nullptr || available == 0 ) {
156
+ c = LZSS_BUFFER_EMPTY;
157
+ } else {
158
+ c = *in_buffer;
159
+ in_buffer++;
160
+ available--;
161
+ }
162
+ return c;
163
+ }
0 commit comments