lzs.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * OpenConnect (SSL + DTLS) VPN client
  3. *
  4. * Copyright © 2008-2015 Intel Corporation.
  5. *
  6. * Author: David Woodhouse <dwmw2@infradead.org>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * version 2.1, as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. */
  17. #include <config.h>
  18. #include "openconnect-internal.h"
  19. #include <errno.h>
  20. #include <string.h>
  21. #include <stdint.h>
  22. #define GET_BITS(bits) \
  23. do { \
  24. /* Strictly speaking, this check ought to be on \
  25. * (srclen < 1 + (bits_left < bits)). However, when bits == 9 \
  26. * the (bits_left < bits) comparison is always true so it \
  27. * always comes out as (srclen < 2). \
  28. * And bits is only anything *other* than 9 when we're reading \
  29. * reading part of a match encoding. And in that case, there \
  30. * damn well ought to be an end marker (7 more bits) after \
  31. * what we're reading now, so it's perfectly OK to use \
  32. * (srclen < 2) in that case too. And a *lot* cheaper. */ \
  33. if (srclen < 2) \
  34. return -EINVAL; \
  35. /* Explicit comparison with 8 to optimise it into a tautology \
  36. * in the bits == 9 case, because the compiler doesn't
  37. * know that bits_left can never be larger than 8. */ \
  38. if (bits >= 8 || bits >= bits_left) { \
  39. /* We need *all* the bits that are left in the current \
  40. * byte. Take them and bump the input pointer. */ \
  41. data = (src[0] << (bits - bits_left)) & ((1 << bits) - 1); \
  42. src++; \
  43. srclen--; \
  44. bits_left += 8 - bits; \
  45. if (bits > 8 || bits_left < 8) { \
  46. /* We need bits from the next byte too... */ \
  47. data |= src[0] >> bits_left; \
  48. /* ...if we used *all* of them then (which can \
  49. * only happen if bits > 8), then bump the \
  50. * input pointer again so we never leave \
  51. * bits_left == 0. */ \
  52. if (bits > 8 && !bits_left) { \
  53. bits_left = 8; \
  54. src++; \
  55. srclen--; \
  56. } \
  57. } \
  58. } else { \
  59. /* We need fewer bits than are left in the current byte */ \
  60. data = (src[0] >> (bits_left - bits)) & ((1ULL << bits) - 1); \
  61. bits_left -= bits; \
  62. } \
  63. } while (0)
  64. int lzs_decompress(unsigned char *dst, int dstlen, const unsigned char *src, int srclen)
  65. {
  66. int outlen = 0;
  67. int bits_left = 8; /* Bits left in the current byte at *src */
  68. uint32_t data;
  69. uint16_t offset, length;
  70. while (1) {
  71. /* Get 9 bits, which is the minimum and a common case */
  72. GET_BITS(9);
  73. /* 0bbbbbbbb is a literal byte. The loop gives a hint to
  74. * the compiler that we expect to see a few of these. */
  75. while (data < 0x100) {
  76. if (outlen == dstlen)
  77. return -EFBIG;
  78. dst[outlen++] = data;
  79. GET_BITS(9);
  80. }
  81. /* 110000000 is the end marker */
  82. if (data == 0x180)
  83. return outlen;
  84. /* 11bbbbbbb is a 7-bit offset */
  85. offset = data & 0x7f;
  86. /* 10bbbbbbbbbbb is an 11-bit offset, so get the next 4 bits */
  87. if (data < 0x180) {
  88. GET_BITS(4);
  89. offset <<= 4;
  90. offset |= data;
  91. }
  92. /* This is a compressed sequence; now get the length */
  93. GET_BITS(2);
  94. if (data != 3) {
  95. /* 00, 01, 10 ==> 2, 3, 4 */
  96. length = data + 2;
  97. } else {
  98. GET_BITS(2);
  99. if (data != 3) {
  100. /* 1100, 1101, 1110 => 5, 6, 7 */
  101. length = data + 5;
  102. } else {
  103. /* For each 1111 prefix add 15 to the length. Then add
  104. the value of final nybble. */
  105. length = 8;
  106. while (1) {
  107. GET_BITS(4);
  108. if (data != 15) {
  109. length += data;
  110. break;
  111. }
  112. length += 15;
  113. }
  114. }
  115. }
  116. if (!offset || offset > outlen)
  117. return -EINVAL;
  118. if (length + outlen > dstlen)
  119. return -EFBIG;
  120. while (length) {
  121. dst[outlen] = dst[outlen - offset];
  122. outlen++;
  123. length--;
  124. }
  125. }
  126. return -EINVAL;
  127. }
  128. #define PUT_BITS(nr, bits) \
  129. do { \
  130. outbits <<= (nr); \
  131. outbits |= (bits); \
  132. nr_outbits += (nr); \
  133. if ((nr) > 8) { \
  134. nr_outbits -= 8; \
  135. if (outpos == dstlen) \
  136. return -EFBIG; \
  137. dst[outpos++] = outbits >> nr_outbits; \
  138. } \
  139. if (nr_outbits >= 8) { \
  140. nr_outbits -= 8; \
  141. if (outpos == dstlen) \
  142. return -EFBIG; \
  143. dst[outpos++] = outbits >> nr_outbits; \
  144. } \
  145. } while (0)
  146. /*
  147. * Much of the compression algorithm used here is based very loosely on ideas
  148. * from isdn_lzscomp.c by Andre Beck: http://micky.ibh.de/~beck/stuff/lzs4i4l/
  149. */
  150. int lzs_compress(unsigned char *dst, int dstlen, const unsigned char *src, int srclen)
  151. {
  152. int length, offset;
  153. int inpos = 0, outpos = 0;
  154. uint16_t longest_match_len;
  155. uint16_t hofs, longest_match_ofs;
  156. uint16_t hash;
  157. uint32_t outbits = 0;
  158. int nr_outbits = 0;
  159. /*
  160. * This is theoretically a hash. But RAM is cheap and just loading the
  161. * 16-bit value and using it as a hash is *much* faster.
  162. */
  163. #define HASH_BITS 16
  164. #define HASH_TABLE_SIZE (1ULL << HASH_BITS)
  165. #define HASH(p) (((struct oc_packed_uint16_t *)(p))->d)
  166. /*
  167. * There are two data structures for tracking the history. The first
  168. * is the true hash table, an array indexed by the hash value described
  169. * above. It yields the offset in the input buffer at which the given
  170. * hash was most recently seen. We use INVALID_OFS (0xffff) for none
  171. * since we know IP packets are limited to 64KiB and we can never be
  172. * *starting* a match at the penultimate byte of the packet.
  173. */
  174. #define INVALID_OFS 0xffff
  175. uint16_t hash_table[HASH_TABLE_SIZE]; /* Buffer offset for first match */
  176. /*
  177. * The second data structure allows us to find the previous occurrences
  178. * of the same hash value. It is a ring buffer containing links only for
  179. * the latest MAX_HISTORY bytes of the input. The lookup for a given
  180. * offset will yield the previous offset at which the same data hash
  181. * value was found.
  182. */
  183. #define MAX_HISTORY (1<<11) /* Highest offset LZS can represent is 11 bits */
  184. uint16_t hash_chain[MAX_HISTORY];
  185. /* Just in case anyone tries to use this in a more general-purpose
  186. * scenario... */
  187. if (srclen > INVALID_OFS + 1)
  188. return -EFBIG;
  189. /* No need to initialise hash_chain since we can only ever follow
  190. * links to it that have already been initialised. */
  191. memset(hash_table, 0xff, sizeof(hash_table));
  192. while (inpos < srclen - 2) {
  193. hash = HASH(src + inpos);
  194. hofs = hash_table[hash];
  195. hash_chain[inpos & (MAX_HISTORY - 1)] = hofs;
  196. hash_table[hash] = inpos;
  197. if (hofs == INVALID_OFS || hofs + MAX_HISTORY <= inpos) {
  198. PUT_BITS(9, src[inpos]);
  199. inpos++;
  200. continue;
  201. }
  202. /* Since the hash is 16-bits, we *know* the first two bytes match */
  203. longest_match_len = 2;
  204. longest_match_ofs = hofs;
  205. for (; hofs != INVALID_OFS && hofs + MAX_HISTORY > inpos;
  206. hofs = hash_chain[hofs & (MAX_HISTORY - 1)]) {
  207. /* We only get here if longest_match_len is >= 2. We need to find
  208. a match of longest_match_len + 1 for it to be interesting. */
  209. if (!memcmp(src + hofs + 2, src + inpos + 2, longest_match_len - 1)) {
  210. longest_match_ofs = hofs;
  211. do {
  212. longest_match_len++;
  213. /* If we cannot *have* a longer match because we're at the
  214. * end of the input, stop looking */
  215. if (longest_match_len + inpos == srclen)
  216. goto got_match;
  217. } while (src[longest_match_len + inpos] == src[longest_match_len + hofs]);
  218. }
  219. /* Typical compressor tuning would have a break out of the loop
  220. here depending on the number of potential match locations we've
  221. tried, or a value of longest_match_len that's considered "good
  222. enough" so we stop looking for something better. We could also
  223. do a hybrid where we count the total bytes compared, so 5
  224. attempts to find a match better than 10 bytes is worth the same
  225. as 10 attempts to find a match better than 5 bytes. Or
  226. something. Anyway, we currently don't give up until we run out
  227. of reachable history — maximal compression. */
  228. }
  229. got_match:
  230. /* Output offset, as 7-bit or 11-bit as appropriate */
  231. offset = inpos - longest_match_ofs;
  232. length = longest_match_len;
  233. if (offset < 0x80)
  234. PUT_BITS(9, 0x180 | offset);
  235. else
  236. PUT_BITS(13, 0x1000 | offset);
  237. /* Output length */
  238. if (length < 5)
  239. PUT_BITS(2, length - 2);
  240. else if (length < 8)
  241. PUT_BITS(4, length + 7);
  242. else {
  243. length += 7;
  244. while (length >= 30) {
  245. PUT_BITS(8, 0xff);
  246. length -= 30;
  247. }
  248. if (length >= 15)
  249. PUT_BITS(8, 0xf0 + length - 15);
  250. else
  251. PUT_BITS(4, length);
  252. }
  253. /* If we're already done, don't bother updating the hash tables. */
  254. if (inpos + longest_match_len >= srclen - 2) {
  255. inpos += longest_match_len;
  256. break;
  257. }
  258. /* We already added the first byte to the hash tables. Add the rest. */
  259. inpos++;
  260. while (--longest_match_len) {
  261. hash = HASH(src + inpos);
  262. hash_chain[inpos & (MAX_HISTORY - 1)] = hash_table[hash];
  263. hash_table[hash] = inpos++;
  264. }
  265. }
  266. /* Special cases at the end */
  267. if (inpos == srclen - 2) {
  268. hash = HASH(src + inpos);
  269. hofs = hash_table[hash];
  270. if (hofs != INVALID_OFS && hofs + MAX_HISTORY > inpos) {
  271. offset = inpos - hofs;
  272. if (offset < 0x80)
  273. PUT_BITS(9, 0x180 | offset);
  274. else
  275. PUT_BITS(13, 0x1000 | offset);
  276. /* The length is 2 bytes */
  277. PUT_BITS(2, 0);
  278. } else {
  279. PUT_BITS(9, src[inpos]);
  280. PUT_BITS(9, src[inpos + 1]);
  281. }
  282. } else if (inpos == srclen - 1) {
  283. PUT_BITS(9, src[inpos]);
  284. }
  285. /* End marker, with 7 trailing zero bits to ensure that it's flushed. */
  286. PUT_BITS(16, 0xc000);
  287. return outpos;
  288. }