1 /**************************************************************************************
2    INCLUDE
3  **************************************************************************************/
4 
5 #include "lzss.h"
6 
7 #include <stdlib.h>
8 #include <stdint.h>
9 
10 #include <FlashStorage.h>
11 
12 /**************************************************************************************
13    DEFINE
14  **************************************************************************************/
15 
16 #define EI 11             /* typically 10..13 */
17 #define EJ  4             /* typically 4..5 */
18 #define P   1             /* If match length <= P then output one character */
19 #define N (1 << EI)       /* buffer size */
20 #define F ((1 << EJ) + 1) /* lookahead buffer size */
21 
22 #define LZSS_EOF       (-1)
23 
24 #define FPUTC_BUF_SIZE (64)
25 #define FGETC_BUF_SIZE (64)
26 
27 /**************************************************************************************
28    GLOBAL VARIABLES
29  **************************************************************************************/
30 
31 extern FlashClass flash;
32 extern const char * UPDATE_FILE_NAME_LZSS;
33 
34 static uint32_t SKETCH_START = 0;
35 static uint32_t LZSS_FILE_SIZE = 0;
36 static WiFiStorageFile * update_file = 0;
37 
38 int bit_buffer = 0, bit_mask = 128;
39 unsigned char buffer[N * 2];
40 
41 static char write_buf[FPUTC_BUF_SIZE];
42 static size_t write_buf_num_bytes = 0;
43 static size_t bytes_written_fputc = 0;
44 static size_t bytes_written_flash = 0;
45 static uint32_t flash_addr = 0;
46 
47 /**************************************************************************************
48    PUBLIC FUNCTIONS
49  **************************************************************************************/
50 
lzss_init(WiFiStorageFile * update_file_ptr, uint32_t const sketch_start, uint32_t const lzss_file_size)51 void lzss_init(WiFiStorageFile * update_file_ptr, uint32_t const sketch_start, uint32_t const lzss_file_size)
52 {
53   SKETCH_START = sketch_start;
54   flash_addr = sketch_start;
55   update_file = update_file_ptr;
56   LZSS_FILE_SIZE = lzss_file_size;
57 }
58 
lzss_flush()59 void lzss_flush()
60 {
61   bytes_written_fputc += write_buf_num_bytes;
62 
63   /* Only write to the flash once we've surpassed
64    * the SSU in the update binary.
65    */
66   if (bytes_written_fputc > (SKETCH_START - 0x2000))
67   {
68     flash.write((void*)flash_addr, write_buf, write_buf_num_bytes);
69     flash_addr += write_buf_num_bytes;
70   }
71 
72   write_buf_num_bytes = 0;
73 }
74 
75 /**************************************************************************************
76    PRIVATE FUNCTIONS
77  **************************************************************************************/
78 
lzss_fputc(int const c)79 void lzss_fputc(int const c)
80 {
81   /* Buffer the decompressed data into a buffer so
82    * we can perform block writes and don't need to
83    * write every byte singly on the flash (which
84    * wouldn't be possible anyway).
85    */
86   write_buf[write_buf_num_bytes] = static_cast<char>(c);
87   write_buf_num_bytes++;
88 
89   /* The write buffer is full of decompressed
90    * data, write it to the flash now.
91    */
92   if (write_buf_num_bytes == FPUTC_BUF_SIZE)
93     lzss_flush();
94 }
95 
lzss_fgetc()96 int lzss_fgetc()
97 {
98   static uint8_t read_buf[FGETC_BUF_SIZE];
99   static size_t read_buf_pos = FGETC_BUF_SIZE;
100   static size_t bytes_read_fgetc = 0;
101   static size_t bytes_read_from_modem = 0;
102 
103   /* lzss_file_size is set within SSUBoot:main
104    * and contains the size of the LZSS file. Once
105    * all those bytes have been read its time to return
106    * LZSS_EOF in order to signal that the end of
107    * the file has been reached.
108    */
109   if (bytes_read_fgetc == LZSS_FILE_SIZE)
110     return LZSS_EOF;
111 
112   /* If there is no data left to be read from the read buffer
113    * than read a new block and store it into the read buffer.
114    */
115   if (read_buf_pos == FGETC_BUF_SIZE)
116   {
117     /* Read the next block from the flash memory. */
118     bytes_read_from_modem += update_file->read(read_buf, FGETC_BUF_SIZE);
119     /* Reset the read buffer position. */
120     read_buf_pos = 0;
121   }
122 
123   uint8_t const c = read_buf[read_buf_pos];
124   read_buf_pos++;
125   bytes_read_fgetc++;
126 
127   return c;
128 }
129 
130 /**************************************************************************************
131    LZSS FUNCTIONS
132  **************************************************************************************/
133 
putbit1(void)134 void putbit1(void)
135 {
136     bit_buffer |= bit_mask;
137     if ((bit_mask >>= 1) == 0) {
138         lzss_fputc(bit_buffer);
139         bit_buffer = 0;  bit_mask = 128;
140     }
141 }
142 
putbit0(void)143 void putbit0(void)
144 {
145     if ((bit_mask >>= 1) == 0) {
146         lzss_fputc(bit_buffer);
147         bit_buffer = 0;  bit_mask = 128;
148     }
149 }
150 
output1(int c)151 void output1(int c)
152 {
153     int mask;
154 
155     putbit1();
156     mask = 256;
157     while (mask >>= 1) {
158         if (c & mask) putbit1();
159         else putbit0();
160     }
161 }
162 
output2(int x, int y)163 void output2(int x, int y)
164 {
165     int mask;
166 
167     putbit0();
168     mask = N;
169     while (mask >>= 1) {
170         if (x & mask) putbit1();
171         else putbit0();
172     }
173     mask = (1 << EJ);
174     while (mask >>= 1) {
175         if (y & mask) putbit1();
176         else putbit0();
177     }
178 }
179 
getbit(int n)180 int getbit(int n) /* get n bits */
181 {
182     int i, x;
183     static int buf, mask = 0;
184 
185     x = 0;
186     for (i = 0; i < n; i++) {
187         if (mask == 0) {
188             if ((buf = lzss_fgetc()) == LZSS_EOF) return LZSS_EOF;
189             mask = 128;
190         }
191         x <<= 1;
192         if (buf & mask) x++;
193         mask >>= 1;
194     }
195     return x;
196 }
197 
lzss_decode(void)198 void lzss_decode(void)
199 {
200     int i, j, k, r, c;
201 
202     for (i = 0; i < N - F; i++) buffer[i] = ' ';
203     r = N - F;
204     while ((c = getbit(1)) != LZSS_EOF) {
205         if (c) {
206             if ((c = getbit(8)) == LZSS_EOF) break;
207             lzss_fputc(c);
208             buffer[r++] = c;  r &= (N - 1);
209         } else {
210             if ((i = getbit(EI)) == LZSS_EOF) break;
211             if ((j = getbit(EJ)) == LZSS_EOF) break;
212             for (k = 0; k <= j + 1; k++) {
213                 c = buffer[(i + k) & (N - 1)];
214                 lzss_fputc(c);
215                 buffer[r++] = c;  r &= (N - 1);
216             }
217         }
218     }
219 }
220