1/**************************************************************************************
2   INCLUDE
3 **************************************************************************************/
4
5#include "lzssEncode.h"
6
7#include <stdlib.h>
8#include <stdint.h>
9
10#include <MKRNB.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 (512)
25#define FGETC_BUF_SIZE (512)
26
27/**************************************************************************************
28   GLOBAL VARIABLES
29 **************************************************************************************/
30
31extern NBFileUtils fileUtils;
32extern const char * UPDATE_FILE_NAME_LZSS;
33
34int bit_buffer = 0, bit_mask = 128;
35unsigned long textcount = 0;
36unsigned char buffer[N * 2];
37
38static char write_buf[FPUTC_BUF_SIZE];
39static size_t write_buf_num_bytes = 0;
40static size_t bytes_written_fputc = 0;
41
42bool append = false;
43bool endOfFile = false;
44
45/**************************************************************************************
46   PUBLIC FUNCTIONS
47 **************************************************************************************/
48
49void lzss_flush()
50{
51  bytes_written_fputc += write_buf_num_bytes;
52
53  fileUtils.downloadFile(UPDATE_FILE_NAME_LZSS, write_buf, write_buf_num_bytes, append);        //UPDATE.BIN.LZSS
54  append = true;
55
56  write_buf_num_bytes = 0;
57}
58
59/**************************************************************************************
60   PRIVATE FUNCTIONS
61 **************************************************************************************/
62
63void lzss_fputc(int const c)
64{
65  /* Buffer the compressed data into a buffer so
66   * we can perform block writes and don't need to
67   * write every byte singly on the modem
68   */
69  write_buf[write_buf_num_bytes] = static_cast<char>(c);
70  write_buf_num_bytes++;
71
72  /* The write buffer is full of compressed
73   * data, write it to the modem now.
74   */
75  if (write_buf_num_bytes == FPUTC_BUF_SIZE || endOfFile)
76    lzss_flush();
77}
78
79/**************************************************************************************
80   LZSS FUNCTIONS
81 **************************************************************************************/
82
83void putbit1(void)
84{
85    bit_buffer |= bit_mask;
86    if ((bit_mask >>= 1) == 0) {
87        lzss_fputc(bit_buffer);
88        bit_buffer = 0;  bit_mask = 128;
89    }
90}
91
92void putbit0(void)
93{
94    if ((bit_mask >>= 1) == 0) {
95        lzss_fputc(bit_buffer);
96        bit_buffer = 0;  bit_mask = 128;
97    }
98}
99
100void flush_bit_buffer(void)
101{
102    if (bit_mask != 128) {
103        lzss_fputc(bit_buffer);
104    }
105}
106
107void output1(int c)
108{
109    int mask;
110
111    putbit1();
112    mask = 256;
113    while (mask >>= 1) {
114        if (c & mask) putbit1();
115        else putbit0();
116    }
117}
118
119void output2(int x, int y)
120{
121    int mask;
122
123    putbit0();
124    mask = N;
125    while (mask >>= 1) {
126        if (x & mask) putbit1();
127        else putbit0();
128    }
129    mask = (1 << EJ);
130    while (mask >>= 1) {
131        if (y & mask) putbit1();
132        else putbit0();
133    }
134}
135
136int lzss_encode(const char buf_in[], uint32_t size)
137{
138    int i, j, f1, x, y, r, s, bufferend, c;
139
140    for (i = 0; i < N - F; i++) buffer[i] = ' ';
141    for (i = N - F; i < N * 2; i++) {
142        if (textcount >= size) {
143            endOfFile = true;
144            break;
145        } else {
146            buffer[i] = buf_in[textcount];
147            textcount++;
148        }
149    }
150    bufferend = i;  r = N - F;  s = 0;
151    while (r < bufferend) {
152        f1 = (F <= bufferend - r) ? F : bufferend - r;
153        x = 0;  y = 1;  c = buffer[r];
154        for (i = r - 1; i >= s; i--)
155            if (buffer[i] == c) {
156                for (j = 1; j < f1; j++)
157                    if (buffer[i + j] != buffer[r + j]) break;
158                if (j > y) {
159                    x = i;  y = j;
160                }
161            }
162        if (y <= P) {  y = 1;  output1(c);  }
163        else output2(x & (N - 1), y - 2);
164        r += y;  s += y;
165        if (r >= N * 2 - F) {
166            for (i = 0; i < N; i++) buffer[i] = buffer[i + N];
167            bufferend -= N;  r -= N;  s -= N;
168            while (bufferend < N * 2) {
169                if (textcount >= size) {
170                    endOfFile = true;
171                    break;
172                } else {
173                    buffer[bufferend++] = buf_in[textcount];
174                    textcount++;
175                }
176            }
177        }
178    }
179    flush_bit_buffer();
180
181    return bytes_written_fputc;
182}