1
- /* Original code: https://oku.edu.mie-u.ac.jp/~okumura/compression/lzss.c */
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
+ */
2
12
3
13
/* *************************************************************************************
4
14
INCLUDE
5
15
**************************************************************************************/
6
-
7
16
#include " lzss.h"
8
17
18
+ #include < stdlib.h>
19
+
9
20
/* *************************************************************************************
10
- DEFINE
21
+ LZSS DECODER CLASS IMPLEMENTATION
11
22
**************************************************************************************/
12
23
13
- #define EI 11 /* typically 10..13 */
14
- #define EJ 4 /* typically 4..5 */
15
- #define P 1 /* If match length <= P then output one character */
16
- #define N (1 << EI) /* buffer size */
17
- #define L ((1 << EJ) + 1 ) /* lookahead buffer size */
18
-
19
- #define LZSS_EOF (-1 )
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
+ }
20
39
21
- /* *************************************************************************************
22
- GLOBAL VARIABLES
23
- **************************************************************************************/
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
+ }
24
45
25
- /* Used to bind local module function to actual class instance */
26
- static Arduino_ESP32_OTA * esp_ota_obj_ptr = 0 ;
27
46
28
- static size_t LZSS_FILE_SIZE = 0 ;
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
+ }
29
52
30
- int bit_buffer = 0 , bit_mask = 128 ;
31
- unsigned char buffer[N * 2 ] ;
53
+ LZSSDecoder::status LZSSDecoder::handle_state () {
54
+ LZSSDecoder::status res = IN_PROGRESS ;
32
55
33
- static size_t bytes_written_fputc = 0 ;
34
- static size_t bytes_read_fgetc = 0 ;
56
+ int c = getbit (bits_required (this ->state ));
35
57
36
- /* *************************************************************************************
37
- PRIVATE FUNCTIONS
38
- **************************************************************************************/
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
+ }
39
104
40
- void lzss_fputc (int const c)
41
- {
42
- esp_ota_obj_ptr->write_byte_to_flash ((uint8_t )c);
43
-
44
- /* write byte callback */
45
- bytes_written_fputc++;
105
+ return res;
46
106
}
47
107
48
- int lzss_fgetc ()
49
- {
50
- /* lzss_file_size is set within SSUBoot:main
51
- * and contains the size of the LZSS file. Once
52
- * all those bytes have been read its time to return
53
- * LZSS_EOF in order to signal that the end of
54
- * the file has been reached.
55
- */
56
- if (bytes_read_fgetc == LZSS_FILE_SIZE)
57
- return LZSS_EOF;
58
-
59
- /* read byte callback */
60
- uint8_t const c = esp_ota_obj_ptr->read_byte_from_network ();
61
- bytes_read_fgetc++;
62
-
63
- return c;
64
- }
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
+ }
65
113
66
- /* *************************************************************************************
67
- LZSS FUNCTIONS
68
- **************************************************************************************/
114
+ status res = IN_PROGRESS;
69
115
70
- void putbit1 (void )
71
- {
72
- bit_buffer |= bit_mask;
73
- if ((bit_mask >>= 1 ) == 0 ) {
74
- lzss_fputc (bit_buffer);
75
- bit_buffer = 0 ; bit_mask = 128 ;
76
- }
77
- }
116
+ while ((res = handle_state ()) == IN_PROGRESS);
78
117
79
- void putbit0 (void )
80
- {
81
- if ((bit_mask >>= 1 ) == 0 ) {
82
- lzss_fputc (bit_buffer);
83
- bit_buffer = 0 ; bit_mask = 128 ;
84
- }
85
- }
118
+ this ->in_buffer = nullptr ;
86
119
87
- void output1 (int c)
88
- {
89
- int mask;
90
-
91
- putbit1 ();
92
- mask = 256 ;
93
- while (mask >>= 1 ) {
94
- if (c & mask) putbit1 ();
95
- else putbit0 ();
96
- }
120
+ return res;
97
121
}
98
122
99
- void output2 (int x, int y)
100
- {
101
- int mask;
102
-
103
- putbit0 ();
104
- mask = N;
105
- while (mask >>= 1 ) {
106
- if (x & mask) putbit1 ();
107
- else putbit0 ();
108
- }
109
- mask = (1 << EJ);
110
- while (mask >>= 1 ) {
111
- if (y & mask) putbit1 ();
112
- else putbit0 ();
113
- }
114
- }
123
+ int LZSSDecoder::getbit (uint8_t n) { // get n bits from buffer
124
+ int x=0 , c;
115
125
116
- int getbit (int n) /* get n bits */
117
- {
118
- int i, x;
119
- static int buf, mask = 0 ;
120
-
121
- x = 0 ;
122
- for (i = 0 ; i < n; i++) {
123
- if (mask == 0 ) {
124
- if ((buf = lzss_fgetc ()) == LZSS_EOF) return LZSS_EOF;
125
- mask = 128 ;
126
- }
127
- x <<= 1 ;
128
- if (buf & mask) x++;
129
- mask >>= 1 ;
130
- }
131
- return x;
132
- }
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 ;
133
134
134
- void lzss_decode (void )
135
- {
136
- int i, j, k, r, c;
137
-
138
- for (i = 0 ; i < N - L; i++) buffer[i] = ' ' ;
139
- r = N - L;
140
- while ((c = getbit (1 )) != LZSS_EOF) {
141
- if (c) {
142
- if ((c = getbit (8 )) == LZSS_EOF) break ;
143
- lzss_fputc (c);
144
- buffer[r++] = c; r &= (N - 1 );
145
- } else {
146
- if ((i = getbit (EI)) == LZSS_EOF) break ;
147
- if ((j = getbit (EJ)) == LZSS_EOF) break ;
148
- for (k = 0 ; k <= j + 1 ; k++) {
149
- c = buffer[(i + k) & (N - 1 )];
150
- lzss_fputc (c);
151
- buffer[r++] = c; r &= (N - 1 );
152
- }
135
+ buf |= (uint8_t )c;
136
+ buf_size += sizeof (uint8_t )*8 ;
153
137
}
154
- }
155
- }
156
138
157
- /* *************************************************************************************
158
- PUBLIC FUNCTIONS
159
- **************************************************************************************/
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;
160
146
161
- int lzss_download (Arduino_ESP32_OTA * instance, size_t const lzss_file_size)
162
- {
163
- esp_ota_obj_ptr = instance;
164
- LZSS_FILE_SIZE = lzss_file_size;
165
- bytes_written_fputc = 0 ;
166
- bytes_read_fgetc = 0 ;
167
- lzss_decode ();
168
- return bytes_written_fputc;
147
+ return x;
169
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