'Z')
+ break;
+ }
+ if (ll == l-1) {
+ SAFE_APPEND_BITS2(rawolen, ol = append_switch_code(out, olen, ol, state));
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, usx_hcodes[USX_ALPHA], usx_hcode_lens[USX_ALPHA]));
+ state = USX_ALPHA;
+ is_all_upper = 1;
+ }
+ }
+ if (state == USX_DELTA && (c_in == ' ' || c_in == '.' || c_in == ',')) {
+ byte spl_code = (c_in == ',' ? 0xC0 : (c_in == '.' ? 0xE0 : (c_in == ' ' ? 0 : 0xFF)));
+ if (spl_code != 0xFF) {
+ byte spl_code_len = (c_in == ',' ? 3 : (c_in == '.' ? 4 : (c_in == ' ' ? 1 : 4)));
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, UNI_STATE_SPL_CODE, UNI_STATE_SPL_CODE_LEN));
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, spl_code, spl_code_len));
+ continue;
+ }
+ }
+ c_in -= 32;
+ if (is_all_upper && is_upper)
+ c_in += 32;
+ if (c_in == 0) {
+ if (state == USX_NUM)
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, usx_vcodes[NUM_SPC_CODE & 0x1F], usx_vcode_lens[NUM_SPC_CODE & 0x1F]));
+ else
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, usx_vcodes[1], usx_vcode_lens[1]));
+ } else {
+ c_in--;
+ SAFE_APPEND_BITS2(rawolen, ol = append_code(out, olen, ol, usx_code_94[(int)c_in], &state, usx_hcodes, usx_hcode_lens));
+ }
+ } else
+ if (c_in == 13 && c_next == 10) {
+ SAFE_APPEND_BITS2(rawolen, ol = append_code(out, olen, ol, CRLF_CODE, &state, usx_hcodes, usx_hcode_lens));
+ l++;
+ } else
+ if (c_in == 10) {
+ if (state == USX_DELTA) {
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, UNI_STATE_SPL_CODE, UNI_STATE_SPL_CODE_LEN));
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, 0xF0, 4));
+ } else
+ SAFE_APPEND_BITS2(rawolen, ol = append_code(out, olen, ol, LF_CODE, &state, usx_hcodes, usx_hcode_lens));
+ } else
+ if (c_in == 13) {
+ SAFE_APPEND_BITS2(rawolen, ol = append_code(out, olen, ol, CR_CODE, &state, usx_hcodes, usx_hcode_lens));
+ } else
+ if (c_in == '\t') {
+ SAFE_APPEND_BITS2(rawolen, ol = append_code(out, olen, ol, TAB_CODE, &state, usx_hcodes, usx_hcode_lens));
+ } else {
+ int utf8len;
+ int32_t uni = readUTF8(in, len, l, &utf8len);
+ if (uni) {
+ l += utf8len;
+ if (state != USX_DELTA) {
+ int32_t uni2 = readUTF8(in, len, l, &utf8len);
+ if (uni2) {
+ if (state != USX_ALPHA) {
+ SAFE_APPEND_BITS2(rawolen, ol = append_switch_code(out, olen, ol, state));
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, usx_hcodes[USX_ALPHA], usx_hcode_lens[USX_ALPHA]));
+ }
+ SAFE_APPEND_BITS2(rawolen, ol = append_switch_code(out, olen, ol, state));
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, usx_hcodes[USX_ALPHA], usx_hcode_lens[USX_ALPHA]));
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, usx_vcodes[1], usx_vcode_lens[1])); // code for space (' ')
+ state = USX_DELTA;
+ } else {
+ SAFE_APPEND_BITS2(rawolen, ol = append_switch_code(out, olen, ol, state));
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, usx_hcodes[USX_DELTA], usx_hcode_lens[USX_DELTA]));
+ }
+ }
+ SAFE_APPEND_BITS2(rawolen, ol = encodeUnicode(out, olen, ol, uni, prev_uni));
+ //printf("%d:%d:%d\n", l, utf8len, uni);
+ prev_uni = uni;
+ l--;
+ } else {
+ int bin_count = 1;
+ for (int bi = l + 1; bi < len; bi++) {
+ char c_bi = in[bi];
+ //if (c_bi > 0x1F && c_bi != 0x7F)
+ // break;
+ if (readUTF8(in, len, bi, &utf8len))
+ break;
+ if (bi < (len - 4) && c_bi == in[bi - 1] && c_bi == in[bi + 1] && c_bi == in[bi + 2] && c_bi == in[bi + 3])
+ break;
+ bin_count++;
+ }
+ //printf("Bin:%d:%d:%x:%d\n", l, (unsigned char) c_in, (unsigned char) c_in, bin_count);
+ SAFE_APPEND_BITS2(rawolen, ol = append_nibble_escape(out, olen, ol, state, usx_hcodes, usx_hcode_lens));
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, 0xF8, 5));
+ SAFE_APPEND_BITS2(rawolen, ol = encodeCount(out, olen, ol, bin_count));
+ do {
+ SAFE_APPEND_BITS2(rawolen, ol = append_bits(out, olen, ol, in[l++], 8));
+ } while (--bin_count);
+ l--;
+ }
+ }
+ }
+
+ if (need_full_term_codes) {
+ const int orig_ol = ol;
+ SAFE_APPEND_BITS2(rawolen, ol = append_final_bits(out, olen, ol, state, is_all_upper, usx_hcodes, usx_hcode_lens));
+ return (ol / 8) * 4 + (((ol-orig_ol)/8) & 3);
+ } else {
+ const int rst = (ol + 7) / 8;
+ append_final_bits(out, rst, ol, state, is_all_upper, usx_hcodes, usx_hcode_lens);
+ return rst;
+ }
+}
+
+// Main API function. See unishox2.h for documentation
+int unishox2_compress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]) {
+ return unishox2_compress_lines(in, len, UNISHOX_API_OUT_AND_LEN(out, olen), usx_hcodes, usx_hcode_lens, usx_freq_seq, usx_templates, NULL);
+}
+
+// Main API function. See unishox2.h for documentation
+int unishox2_compress_simple(const char *in, int len, char *out) {
+ return unishox2_compress_lines(in, len, UNISHOX_API_OUT_AND_LEN(out, INT_MAX - 1), USX_HCODES_DFLT, USX_HCODE_LENS_DFLT, USX_FREQ_SEQ_DFLT, USX_TEMPLATES, NULL);
+}
+
+// Reads one bit from in
+int readBit(const char *in, int bit_no) {
+ return in[bit_no >> 3] & (0x80 >> (bit_no % 8));
+}
+
+// Reads next 8 bits, if available
+int read8bitCode(const char *in, int len, int bit_no) {
+ int bit_pos = bit_no & 0x07;
+ int char_pos = bit_no >> 3;
+ byte code = (((byte)in[char_pos]) << bit_pos);
+ if (bit_no + bit_pos < len) {
+ code |= ((byte)in[++char_pos]) >> (8 - bit_pos);
+ } else
+ code |= (0xFF >> (8 - bit_pos));
+ return code;
+}
+
+/// The list of veritical codes is split into 5 sections. Used by readVCodeIdx()
+#define SECTION_COUNT 5
+/// Used by readVCodeIdx() for finding the section under which the code read using read8bitCode() falls
+byte usx_vsections[] = {0x7F, 0xBF, 0xDF, 0xEF, 0xFF};
+/// Used by readVCodeIdx() for finding the section vertical position offset
+byte usx_vsection_pos[] = {0, 4, 8, 12, 20};
+/// Used by readVCodeIdx() for masking the code read by read8bitCode()
+byte usx_vsection_mask[] = {0x7F, 0x3F, 0x1F, 0x0F, 0x0F};
+/// Used by readVCodeIdx() for shifting the code read by read8bitCode() to obtain the vpos
+byte usx_vsection_shift[] = {5, 4, 3, 1, 0};
+
+/// Vertical decoder lookup table - 3 bits code len, 5 bytes vertical pos
+/// code len is one less as 8 cannot be accommodated in 3 bits
+byte usx_vcode_lookup[36] = {
+ (1 << 5) + 0, (1 << 5) + 0, (2 << 5) + 1, (2 << 5) + 2, // Section 1
+ (3 << 5) + 3, (3 << 5) + 4, (3 << 5) + 5, (3 << 5) + 6, // Section 2
+ (3 << 5) + 7, (3 << 5) + 7, (4 << 5) + 8, (4 << 5) + 9, // Section 3
+ (5 << 5) + 10, (5 << 5) + 10, (5 << 5) + 11, (5 << 5) + 11, // Section 4
+ (5 << 5) + 12, (5 << 5) + 12, (6 << 5) + 13, (6 << 5) + 14,
+ (6 << 5) + 15, (6 << 5) + 15, (6 << 5) + 16, (6 << 5) + 16, // Section 5
+ (6 << 5) + 17, (6 << 5) + 17, (7 << 5) + 18, (7 << 5) + 19,
+ (7 << 5) + 20, (7 << 5) + 21, (7 << 5) + 22, (7 << 5) + 23,
+ (7 << 5) + 24, (7 << 5) + 25, (7 << 5) + 26, (7 << 5) + 27
+};
+
+/// Decodes the vertical code from the given bitstream at in \n
+/// This is designed to use less memory using a 36 byte buffer \n
+/// compared to using a 256 byte buffer to decode the next 8 bits read by read8bitCode() \n
+/// by splitting the list of vertical codes. \n
+/// Decoder is designed for using less memory, not speed. \n
+/// Returns the veritical code index or 99 if match could not be found. \n
+/// Also updates bit_no_p with how many ever bits used by the vertical code.
+int readVCodeIdx(const char *in, int len, int *bit_no_p) {
+ if (*bit_no_p < len) {
+ byte code = read8bitCode(in, len, *bit_no_p);
+ int i = 0;
+ do {
+ if (code <= usx_vsections[i]) {
+ byte vcode = usx_vcode_lookup[usx_vsection_pos[i] + ((code & usx_vsection_mask[i]) >> usx_vsection_shift[i])];
+ (*bit_no_p) += ((vcode >> 5) + 1);
+ if (*bit_no_p > len)
+ return 99;
+ return vcode & 0x1F;
+ }
+ } while (++i < SECTION_COUNT);
+ }
+ return 99;
+}
+
+/// Mask for retrieving each code to be decoded according to its length \n
+/// Same as usx_mask so redundant
+byte len_masks[] = {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF};
+/// Decodes the horizontal code from the given bitstream at in \n
+/// depending on the hcodes defined using usx_hcodes and usx_hcode_lens \n
+/// Returns the horizontal code index or 99 if match could not be found. \n
+/// Also updates bit_no_p with how many ever bits used by the horizontal code.
+int readHCodeIdx(const char *in, int len, int *bit_no_p, const byte usx_hcodes[], const byte usx_hcode_lens[]) {
+ if (!usx_hcode_lens[USX_ALPHA])
+ return USX_ALPHA;
+ if (*bit_no_p < len) {
+ byte code = read8bitCode(in, len, *bit_no_p);
+ for (int code_pos = 0; code_pos < 5; code_pos++) {
+ if (usx_hcode_lens[code_pos] && (code & len_masks[usx_hcode_lens[code_pos] - 1]) == usx_hcodes[code_pos]) {
+ *bit_no_p += usx_hcode_lens[code_pos];
+ return code_pos;
+ }
+ }
+ }
+ return 99;
+}
+
+// TODO: Last value check.. Also len check in readBit
+/// Returns the position of step code (0, 10, 110, etc.) encountered in the stream
+int getStepCodeIdx(const char *in, int len, int *bit_no_p, int limit) {
+ int idx = 0;
+ while (*bit_no_p < len && readBit(in, *bit_no_p)) {
+ idx++;
+ (*bit_no_p)++;
+ if (idx == limit)
+ return idx;
+ }
+ if (*bit_no_p >= len)
+ return 99;
+ (*bit_no_p)++;
+ return idx;
+}
+
+/// Reads specified number of bits and builds the corresponding integer
+int32_t getNumFromBits(const char *in, int len, int bit_no, int count) {
+ int32_t ret = 0;
+ while (count-- && bit_no < len) {
+ ret += (readBit(in, bit_no) ? 1 << count : 0);
+ bit_no++;
+ }
+ return count < 0 ? ret : -1;
+}
+
+/// Decodes the count from the given bit stream at in. Also updates bit_no_p
+int32_t readCount(const char *in, int *bit_no_p, int len) {
+ int idx = getStepCodeIdx(in, len, bit_no_p, 4);
+ if (idx == 99)
+ return -1;
+ if (*bit_no_p + count_bit_lens[idx] - 1 >= len)
+ return -1;
+ int32_t count = getNumFromBits(in, len, *bit_no_p, count_bit_lens[idx]) + (idx ? count_adder[idx - 1] : 0);
+ (*bit_no_p) += count_bit_lens[idx];
+ return count;
+}
+
+/// Decodes the Unicode codepoint from the given bit stream at in. Also updates bit_no_p \n
+/// When the step code is 5, reads the next step code to find out the special code.
+int32_t readUnicode(const char *in, int *bit_no_p, int len) {
+ int idx = getStepCodeIdx(in, len, bit_no_p, 5);
+ if (idx == 99)
+ return 0x7FFFFF00 + 99;
+ if (idx == 5) {
+ idx = getStepCodeIdx(in, len, bit_no_p, 4);
+ return 0x7FFFFF00 + idx;
+ }
+ if (idx >= 0) {
+ int sign = (*bit_no_p < len ? readBit(in, *bit_no_p) : 0);
+ (*bit_no_p)++;
+ if (*bit_no_p + uni_bit_len[idx] - 1 >= len)
+ return 0x7FFFFF00 + 99;
+ int32_t count = getNumFromBits(in, len, *bit_no_p, uni_bit_len[idx]);
+ count += uni_adder[idx];
+ (*bit_no_p) += uni_bit_len[idx];
+ //printf("Sign: %d, Val:%d", sign, count);
+ return sign ? -count : count;
+ }
+ return 0;
+}
+
+/// Macro to ensure that the decoder does not append more than olen bytes to out
+#define DEC_OUTPUT_CHAR(out, olen, ol, c) do { \
+ char *const obuf = (out); \
+ const int oidx = (ol); \
+ const int limit = (olen); \
+ if (limit <= oidx) return limit + 1; \
+ else if (oidx < 0) return 0; \
+ else obuf[oidx] = (c); \
+} while (0)
+
+/// Macro to ensure that the decoder does not append more than olen bytes to out
+#define DEC_OUTPUT_CHARS(olen, exp) do { \
+ const int newidx = (exp); \
+ const int limit = (olen); \
+ if (newidx > limit) return limit + 1; \
+} while (0)
+
+/// Write given unicode code point to out as a UTF-8 sequence
+int writeUTF8(char *out, int olen, int ol, int uni) {
+ if (uni < (1 << 11)) {
+ DEC_OUTPUT_CHAR(out, olen, ol++, 0xC0 + (uni >> 6));
+ DEC_OUTPUT_CHAR(out, olen, ol++, 0x80 + (uni & 0x3F));
+ } else
+ if (uni < (1 << 16)) {
+ DEC_OUTPUT_CHAR(out, olen, ol++, 0xE0 + (uni >> 12));
+ DEC_OUTPUT_CHAR(out, olen, ol++, 0x80 + ((uni >> 6) & 0x3F));
+ DEC_OUTPUT_CHAR(out, olen, ol++, 0x80 + (uni & 0x3F));
+ } else {
+ DEC_OUTPUT_CHAR(out, olen, ol++, 0xF0 + (uni >> 18));
+ DEC_OUTPUT_CHAR(out, olen, ol++, 0x80 + ((uni >> 12) & 0x3F));
+ DEC_OUTPUT_CHAR(out, olen, ol++, 0x80 + ((uni >> 6) & 0x3F));
+ DEC_OUTPUT_CHAR(out, olen, ol++, 0x80 + (uni & 0x3F));
+ }
+ return ol;
+}
+
+/// Decode repeating sequence and appends to out
+int decodeRepeat(const char *in, int len, char *out, int olen, int ol, int *bit_no, struct us_lnk_lst *prev_lines) {
+ if (prev_lines) {
+ int32_t dict_len = readCount(in, bit_no, len) + NICE_LEN;
+ if (dict_len < NICE_LEN)
+ return ol;
+ int32_t dist = readCount(in, bit_no, len);
+ if (dist < 0)
+ return ol;
+ int32_t ctx = readCount(in, bit_no, len);
+ if (ctx < 0)
+ return ol;
+ struct us_lnk_lst *cur_line = prev_lines;
+ const int left = olen - ol;
+ while (ctx--)
+ cur_line = cur_line->previous;
+ if (left <= 0) return olen + 1;
+ memmove(out + ol, cur_line->data + dist, min_of(left, dict_len));
+ if (left < dict_len) return olen + 1;
+ ol += dict_len;
+ } else {
+ int32_t dict_len = readCount(in, bit_no, len) + NICE_LEN;
+ if (dict_len < NICE_LEN)
+ return ol;
+ int32_t dist = readCount(in, bit_no, len) + NICE_LEN - 1;
+ if (dist < NICE_LEN - 1)
+ return ol;
+ const int32_t left = olen - ol;
+ //printf("Decode len: %d, dist: %d\n", dict_len - NICE_LEN, dist - NICE_LEN + 1);
+ if (left <= 0) return olen + 1;
+ memmove(out + ol, out + ol - dist, min_of(left, dict_len));
+ if (left < dict_len) return olen + 1;
+ ol += dict_len;
+ }
+ return ol;
+}
+
+/// Returns hex character corresponding to the 4 bit nibble
+char getHexChar(int32_t nibble, int hex_type) {
+ if (nibble >= 0 && nibble <= 9)
+ return '0' + nibble;
+ else if (hex_type < USX_NIB_HEX_UPPER)
+ return 'a' + nibble - 10;
+ return 'A' + nibble - 10;
+}
+
+// Main API function. See unishox2.h for documentation
+int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines) {
+
+ int dstate;
+ int bit_no;
+ int h, v;
+ byte is_all_upper;
+#if (UNISHOX_API_OUT_AND_LEN(0,1)) == 0
+ const int olen = INT_MAX - 1;
+#endif
+
+ init_coder();
+ int ol = 0;
+ bit_no = UNISHOX_MAGIC_BIT_LEN; // ignore the magic bit
+ dstate = h = USX_ALPHA;
+ is_all_upper = 0;
+
+ int prev_uni = 0;
+
+ len <<= 3;
+ while (bit_no < len) {
+ int orig_bit_no = bit_no;
+ if (dstate == USX_DELTA || h == USX_DELTA) {
+ if (dstate != USX_DELTA)
+ h = dstate;
+ int32_t delta = readUnicode(in, &bit_no, len);
+ if ((delta >> 8) == 0x7FFFFF) {
+ int spl_code_idx = delta & 0x000000FF;
+ if (spl_code_idx == 99)
+ break;
+ switch (spl_code_idx) {
+ case 0:
+ DEC_OUTPUT_CHAR(out, olen, ol++, ' ');
+ continue;
+ case 1:
+ h = readHCodeIdx(in, len, &bit_no, usx_hcodes, usx_hcode_lens);
+ if (h == 99) {
+ bit_no = len;
+ continue;
+ }
+ if (h == USX_DELTA || h == USX_ALPHA) {
+ dstate = h;
+ continue;
+ }
+ if (h == USX_DICT) {
+ DEC_OUTPUT_CHARS(olen, ol = decodeRepeat(in, len, out, olen, ol, &bit_no, prev_lines));
+ h = dstate;
+ continue;
+ }
+ break;
+ case 2:
+ DEC_OUTPUT_CHAR(out, olen, ol++, ',');
+ continue;
+ case 3:
+ DEC_OUTPUT_CHAR(out, olen, ol++, '.');
+ continue;
+ case 4:
+ DEC_OUTPUT_CHAR(out, olen, ol++, 10);
+ continue;
+ }
+ } else {
+ prev_uni += delta;
+ DEC_OUTPUT_CHARS(olen, ol = writeUTF8(out, olen, ol, prev_uni));
+ //printf("%ld, ", prev_uni);
+ }
+ if (dstate == USX_DELTA && h == USX_DELTA)
+ continue;
+ } else
+ h = dstate;
+ char c = 0;
+ byte is_upper = is_all_upper;
+ v = readVCodeIdx(in, len, &bit_no);
+ if (v == 99 || h == 99) {
+ bit_no = orig_bit_no;
+ break;
+ }
+ if (v == 0 && h != USX_SYM) {
+ if (bit_no >= len)
+ break;
+ if (h != USX_NUM || dstate != USX_DELTA) {
+ h = readHCodeIdx(in, len, &bit_no, usx_hcodes, usx_hcode_lens);
+ if (h == 99 || bit_no >= len) {
+ bit_no = orig_bit_no;
+ break;
+ }
+ }
+ if (h == USX_ALPHA) {
+ if (dstate == USX_ALPHA) {
+ if (!usx_hcode_lens[USX_ALPHA] && TERM_BYTE_PRESET_1 == (read8bitCode(in, len, bit_no - SW_CODE_LEN) & (0xFF << (8 - (is_all_upper ? TERM_BYTE_PRESET_1_LEN_UPPER : TERM_BYTE_PRESET_1_LEN_LOWER)))))
+ break; // Terminator for preset 1
+ if (is_all_upper) {
+ is_upper = is_all_upper = 0;
+ continue;
+ }
+ v = readVCodeIdx(in, len, &bit_no);
+ if (v == 99) {
+ bit_no = orig_bit_no;
+ break;
+ }
+ if (v == 0) {
+ h = readHCodeIdx(in, len, &bit_no, usx_hcodes, usx_hcode_lens);
+ if (h == 99) {
+ bit_no = orig_bit_no;
+ break;
+ }
+ if (h == USX_ALPHA) {
+ is_all_upper = 1;
+ continue;
+ }
+ }
+ is_upper = 1;
+ } else {
+ dstate = USX_ALPHA;
+ continue;
+ }
+ } else
+ if (h == USX_DICT) {
+ DEC_OUTPUT_CHARS(olen, ol = decodeRepeat(in, len, out, olen, ol, &bit_no, prev_lines));
+ continue;
+ } else
+ if (h == USX_DELTA) {
+ //printf("Sign: %d, bitno: %d\n", sign, bit_no);
+ //printf("Code: %d\n", prev_uni);
+ //printf("BitNo: %d\n", bit_no);
+ continue;
+ } else {
+ if (h != USX_NUM || dstate != USX_DELTA)
+ v = readVCodeIdx(in, len, &bit_no);
+ if (v == 99) {
+ bit_no = orig_bit_no;
+ break;
+ }
+ if (h == USX_NUM && v == 0) {
+ int idx = getStepCodeIdx(in, len, &bit_no, 5);
+ if (idx == 0) {
+ idx = getStepCodeIdx(in, len, &bit_no, 4);
+ int32_t rem = readCount(in, &bit_no, len);
+ if (rem < 0)
+ break;
+ rem = (int)strlen(usx_templates[idx]) - rem;
+ int eof = 0;
+ for (int j = 0; j < rem; j++) {
+ char c_t = usx_templates[idx][j];
+ if (c_t == 'f' || c_t == 'r' || c_t == 't' || c_t == 'o' || c_t == 'F') {
+ char nibble_len = (c_t == 'f' || c_t == 'F' ? 4 : (c_t == 'r' ? 3 : (c_t == 't' ? 2 : 1)));
+ const int32_t raw_char = getNumFromBits(in, len, bit_no, nibble_len);
+ if (raw_char < 0) {
+ eof = 1;
+ break;
+ }
+ DEC_OUTPUT_CHAR(out, olen, ol++, getHexChar((char)raw_char,
+ c_t == 'f' ? USX_NIB_HEX_LOWER : USX_NIB_HEX_UPPER));
+ bit_no += nibble_len;
+ } else
+ DEC_OUTPUT_CHAR(out, olen, ol++, c_t);
+ }
+ if (eof) break; // reach input eof
+ } else
+ if (idx == 5) {
+ int32_t bin_count = readCount(in, &bit_no, len);
+ if (bin_count < 0)
+ break;
+ if (bin_count == 0) // invalid encoding
+ break;
+ do {
+ const int32_t raw_char = getNumFromBits(in, len, bit_no, 8);
+ if (raw_char < 0)
+ break;
+ DEC_OUTPUT_CHAR(out, olen, ol++, (char)raw_char);
+ bit_no += 8;
+ } while (--bin_count);
+ if (bin_count > 0) break; // reach input eof
+ } else {
+ int32_t nibble_count = 0;
+ if (idx == 2 || idx == 4)
+ nibble_count = 32;
+ else {
+ nibble_count = readCount(in, &bit_no, len);
+ if (nibble_count < 0)
+ break;
+ if (nibble_count == 0) // invalid encoding
+ break;
+ }
+ do {
+ int32_t nibble = getNumFromBits(in, len, bit_no, 4);
+ if (nibble < 0)
+ break;
+ DEC_OUTPUT_CHAR(out, olen, ol++, getHexChar(nibble, idx < 3 ? USX_NIB_HEX_LOWER : USX_NIB_HEX_UPPER));
+ if ((idx == 2 || idx == 4) && (nibble_count == 25 || nibble_count == 21 || nibble_count == 17 || nibble_count == 13))
+ DEC_OUTPUT_CHAR(out, olen, ol++, '-');
+ bit_no += 4;
+ } while (--nibble_count);
+ if (nibble_count > 0) break; // reach input eof
+ }
+ if (dstate == USX_DELTA)
+ h = USX_DELTA;
+ continue;
+ }
+ }
+ }
+ if (is_upper && v == 1) {
+ h = dstate = USX_DELTA; // continuous delta coding
+ continue;
+ }
+ if (h < 3 && v < 28)
+ c = usx_sets[h][v];
+ if (c >= 'a' && c <= 'z') {
+ dstate = USX_ALPHA;
+ if (is_upper)
+ c -= 32;
+ } else {
+ if (c >= '0' && c <= '9') {
+ dstate = USX_NUM;
+ } else if (c == 0) {
+ if (v == 8) {
+ DEC_OUTPUT_CHAR(out, olen, ol++, '\r');
+ DEC_OUTPUT_CHAR(out, olen, ol++, '\n');
+ } else if (h == USX_NUM && v == 26) {
+ int32_t count = readCount(in, &bit_no, len);
+ if (count < 0)
+ break;
+ count += 4;
+ if (ol <= 0)
+ return 0; // invalid encoding
+ char rpt_c = out[ol - 1];
+ while (count--)
+ DEC_OUTPUT_CHAR(out, olen, ol++, rpt_c);
+ } else if (h == USX_SYM && v > 24) {
+ v -= 25;
+ const int freqlen = (int)strlen(usx_freq_seq[v]);
+ const int left = olen - ol;
+ if (left <= 0) return olen + 1;
+ memcpy(out + ol, usx_freq_seq[v], min_of(left, freqlen));
+ if (left < freqlen) return olen + 1;
+ ol += freqlen;
+ } else if (h == USX_NUM && v > 22 && v < 26) {
+ v -= (23 - 3);
+ const int freqlen = (int)strlen(usx_freq_seq[v]);
+ const int left = olen - ol;
+ if (left <= 0) return olen + 1;
+ memcpy(out + ol, usx_freq_seq[v], min_of(left, freqlen));
+ if (left < freqlen) return olen + 1;
+ ol += freqlen;
+ } else
+ break; // Terminator
+ if (dstate == USX_DELTA)
+ h = USX_DELTA;
+ continue;
+ }
+ }
+ if (dstate == USX_DELTA)
+ h = USX_DELTA;
+ DEC_OUTPUT_CHAR(out, olen, ol++, c);
+ }
+
+ return ol;
+
+}
+
+// Main API function. See unishox2.h for documentation
+int unishox2_decompress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen), const byte usx_hcodes[], const byte usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]) {
+ return unishox2_decompress_lines(in, len, UNISHOX_API_OUT_AND_LEN(out, olen), usx_hcodes, usx_hcode_lens, usx_freq_seq, usx_templates, NULL);
+}
+
+// Main API function. See unishox2.h for documentation
+int unishox2_decompress_simple(const char *in, int len, char *out) {
+ return unishox2_decompress(in, len, UNISHOX_API_OUT_AND_LEN(out, INT_MAX - 1), USX_PSET_DFLT);
+}
diff --git a/src/mesh/compression/unishox2.h b/src/mesh/compression/unishox2.h
new file mode 100644
index 000000000..bbbd7a759
--- /dev/null
+++ b/src/mesh/compression/unishox2.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2020 Siara Logics (cc)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @author Arundale Ramanathan
+ *
+ */
+
+/**
+ * @file unishox2.h
+ * @author Arundale Ramanathan, James Z. M. Gao
+ * @brief API for Unishox2 Compression and Decompression
+ *
+ * This file describes each function of the Unishox2 API \n
+ * For finding out how this API can be used in your program, \n
+ * please see test_unishox2.c.
+ */
+
+#ifndef unishox2
+#define unishox2
+
+#define UNISHOX_VERSION "2.0" ///< Unicode spec version
+
+/**
+ * Macro switch to enable/disable output buffer length parameter in low level api \n
+ * Disabled by default \n
+ * When this macro is defined, the all the API functions \n
+ * except the simple API functions accept an additional parameter olen \n
+ * that enables the developer to pass the size of the output buffer provided \n
+ * so that the api function may not write beyond that length. \n
+ * This can be disabled if the developer knows that the buffer provided is sufficient enough \n
+ * so no additional parameter is passed and the program is faster since additional check \n
+ * for output length is not performed at each step \n
+ * The simple api, i.e. unishox2_(de)compress_simple will always omit the buffer length
+ */
+#ifndef UNISHOX_API_WITH_OUTPUT_LEN
+# define UNISHOX_API_WITH_OUTPUT_LEN 0
+#endif
+
+/// Upto 8 bits of initial magic bit sequence can be included. Bit count can be specified with UNISHOX_MAGIC_BIT_LEN
+#ifndef UNISHOX_MAGIC_BITS
+# define UNISHOX_MAGIC_BITS 0xFF
+#endif
+
+/// Desired length of Magic bits defined by UNISHOX_MAGIC_BITS
+#ifdef UNISHOX_MAGIC_BIT_LEN
+# if UNISHOX_MAGIC_BIT_LEN < 0 || 9 <= UNISHOX_MAGIC_BIT_LEN
+# error "UNISHOX_MAGIC_BIT_LEN need between [0, 8)"
+# endif
+#else
+# define UNISHOX_MAGIC_BIT_LEN 1
+#endif
+
+//enum {USX_ALPHA = 0, USX_SYM, USX_NUM, USX_DICT, USX_DELTA};
+
+/// Default Horizontal codes. When composition of text is know beforehand, the other hcodes in this section can be used to achieve more compression.
+#define USX_HCODES_DFLT (const unsigned char[]) {0x00, 0x40, 0x80, 0xC0, 0xE0}
+/// Length of each default hcode
+#define USX_HCODE_LENS_DFLT (const unsigned char[]) {2, 2, 2, 3, 3}
+
+/// Horizontal codes preset for English Alphabet content only
+#define USX_HCODES_ALPHA_ONLY (const unsigned char[]) {0x00, 0x00, 0x00, 0x00, 0x00}
+/// Length of each Alpha only hcode
+#define USX_HCODE_LENS_ALPHA_ONLY (const unsigned char[]) {0, 0, 0, 0, 0}
+
+/// Horizontal codes preset for Alpha Numeric content only
+#define USX_HCODES_ALPHA_NUM_ONLY (const unsigned char[]) {0x00, 0x00, 0x80, 0x00, 0x00}
+/// Length of each Alpha numeric hcode
+#define USX_HCODE_LENS_ALPHA_NUM_ONLY (const unsigned char[]) {1, 0, 1, 0, 0}
+
+/// Horizontal codes preset for Alpha Numeric and Symbol content only
+#define USX_HCODES_ALPHA_NUM_SYM_ONLY (const unsigned char[]) {0x00, 0x80, 0xC0, 0x00, 0x00}
+/// Length of each Alpha numeric and symbol hcodes
+#define USX_HCODE_LENS_ALPHA_NUM_SYM_ONLY (const unsigned char[]) {1, 2, 2, 0, 0}
+
+/// Horizontal codes preset favouring Alphabet content
+#define USX_HCODES_FAVOR_ALPHA (const unsigned char[]) {0x00, 0x80, 0xA0, 0xC0, 0xE0}
+/// Length of each hcode favouring Alpha content
+#define USX_HCODE_LENS_FAVOR_ALPHA (const unsigned char[]) {1, 3, 3, 3, 3}
+
+/// Horizontal codes preset favouring repeating sequences
+#define USX_HCODES_FAVOR_DICT (const unsigned char[]) {0x00, 0x40, 0xC0, 0x80, 0xE0}
+/// Length of each hcode favouring repeating sequences
+#define USX_HCODE_LENS_FAVOR_DICT (const unsigned char[]) {2, 2, 3, 2, 3}
+
+/// Horizontal codes preset favouring symbols
+#define USX_HCODES_FAVOR_SYM (const unsigned char[]) {0x80, 0x00, 0xA0, 0xC0, 0xE0}
+/// Length of each hcode favouring symbols
+#define USX_HCODE_LENS_FAVOR_SYM (const unsigned char[]) {3, 1, 3, 3, 3}
+
+//#define USX_HCODES_FAVOR_UMLAUT {0x00, 0x40, 0xE0, 0xC0, 0x80}
+//#define USX_HCODE_LENS_FAVOR_UMLAUT {2, 2, 3, 3, 2}
+
+/// Horizontal codes preset favouring umlaut letters
+#define USX_HCODES_FAVOR_UMLAUT (const unsigned char[]) {0x80, 0xA0, 0xC0, 0xE0, 0x00}
+/// Length of each hcode favouring umlaut letters
+#define USX_HCODE_LENS_FAVOR_UMLAUT (const unsigned char[]) {3, 3, 3, 3, 1}
+
+/// Horizontal codes preset for no repeating sequences
+#define USX_HCODES_NO_DICT (const unsigned char[]) {0x00, 0x40, 0x80, 0x00, 0xC0}
+/// Length of each hcode for no repeating sequences
+#define USX_HCODE_LENS_NO_DICT (const unsigned char[]) {2, 2, 2, 0, 2}
+
+/// Horizontal codes preset for no Unicode characters
+#define USX_HCODES_NO_UNI (const unsigned char[]) {0x00, 0x40, 0x80, 0xC0, 0x00}
+/// Length of each hcode for no Unicode characters
+#define USX_HCODE_LENS_NO_UNI (const unsigned char[]) {2, 2, 2, 2, 0}
+
+/// Default frequently occuring sequences. When composition of text is know beforehand, the other sequences in this section can be used to achieve more compression.
+#define USX_FREQ_SEQ_DFLT (const char *[]) {"\": \"", "\": ", "", "=\"", "\":\"", "://"}
+/// Frequently occuring sequences in text content
+#define USX_FREQ_SEQ_TXT (const char *[]) {" the ", " and ", "tion", " with", "ing", "ment"}
+/// Frequently occuring sequences in URL content
+#define USX_FREQ_SEQ_URL (const char *[]) {"https://", "www.", ".com", "http://", ".org", ".net"}
+/// Frequently occuring sequences in JSON content
+#define USX_FREQ_SEQ_JSON (const char *[]) {"\": \"", "\": ", "\",", "}}}", "\":\"", "}}"}
+/// Frequently occuring sequences in HTML content
+#define USX_FREQ_SEQ_HTML (const char *[]) {"", "=\"", "div", "href", "class", ""}
+/// Frequently occuring sequences in XML content
+#define USX_FREQ_SEQ_XML (const char *[]) {"", "=\"", "\">", "
#include
-#include
#include
#include
+#ifndef DISABLE_NTP
+#include
+#endif
+
using namespace concurrency;
static void WiFiEvent(WiFiEvent_t event);
@@ -23,7 +26,10 @@ DNSServer dnsServer;
// NTP
WiFiUDP ntpUDP;
+
+#ifndef DISABLE_NTP
NTPClient timeClient(ntpUDP, "0.pool.ntp.org");
+#endif
uint8_t wifiDisconnectReason = 0;
@@ -67,13 +73,13 @@ static int32_t reconnectWiFi()
DEBUG_MSG("... Reconnecting to WiFi access point\n");
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw);
-
// Starting timeClient;
}
}
- //if (*wifiName) {
+#ifndef DISABLE_NTP
+ // if (*wifiName) {
if (WiFi.isConnected()) {
DEBUG_MSG("Updating NTP time\n");
if (timeClient.update()) {
@@ -89,6 +95,7 @@ static int32_t reconnectWiFi()
DEBUG_MSG("NTP Update failed\n");
}
}
+#endif
return 30 * 1000; // every 30 seconds
}
@@ -155,9 +162,11 @@ static void onNetworkConnected()
MDNS.addService("https", "tcp", 443);
}
+#ifndef DISABLE_NTP
DEBUG_MSG("Starting NTP time client\n");
timeClient.begin();
- timeClient.setUpdateInterval(60*60); // Update once an hour
+ timeClient.setUpdateInterval(60 * 60); // Update once an hour
+#endif
initWebServer();
initApiServer();