^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * LZO1X Compressor from LZO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * The full LZO package can be found at:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * http://www.oberhumer.com/opensource/lzo/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Changed for Linux kernel use by:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Nitin Gupta <nitingupta910@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Richard Purdie <rpurdie@openedhand.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/lzo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "lzodefs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static noinline size_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned char *out, size_t *out_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) size_t ti, void *wrkmem, signed char *state_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) const unsigned char bitstream_version)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) const unsigned char *ip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned char *op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) const unsigned char * const in_end = in + in_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) const unsigned char * const ip_end = in + in_len - 20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) const unsigned char *ii;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) lzo_dict_t * const dict = (lzo_dict_t *) wrkmem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) op = out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) ip = in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) ii = ip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) ip += ti < 4 ? 4 - ti : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) const unsigned char *m_pos = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) size_t t, m_len, m_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) u32 dv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) u32 run_length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) literal:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) ip += 1 + ((ip - ii) >> 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) next:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (unlikely(ip >= ip_end))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) dv = get_unaligned_le32(ip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (dv == 0 && bitstream_version) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) const unsigned char *ir = ip + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) const unsigned char *limit = ip_end
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) < (ip + MAX_ZERO_RUN_LENGTH + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) ? ip_end : ip + MAX_ZERO_RUN_LENGTH + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) defined(LZO_FAST_64BIT_MEMORY_ACCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u64 dv64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) for (; (ir + 32) <= limit; ir += 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) dv64 = get_unaligned((u64 *)ir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) dv64 |= get_unaligned((u64 *)ir + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) dv64 |= get_unaligned((u64 *)ir + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) dv64 |= get_unaligned((u64 *)ir + 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (dv64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) for (; (ir + 8) <= limit; ir += 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) dv64 = get_unaligned((u64 *)ir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (dv64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) # if defined(__LITTLE_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) ir += __builtin_ctzll(dv64) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) # elif defined(__BIG_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ir += __builtin_clzll(dv64) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) # else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) # error "missing endian definition"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) # endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) while ((ir < (const unsigned char *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ALIGN((uintptr_t)ir, 4)) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) (ir < limit) && (*ir == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) ir++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (IS_ALIGNED((uintptr_t)ir, 4)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) for (; (ir + 4) <= limit; ir += 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) dv = *((u32 *)ir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (dv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) # if defined(__LITTLE_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) ir += __builtin_ctz(dv) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) # elif defined(__BIG_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) ir += __builtin_clz(dv) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) # else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) # error "missing endian definition"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) # endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) while (likely(ir < limit) && unlikely(*ir == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) ir++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) run_length = ir - ip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (run_length > MAX_ZERO_RUN_LENGTH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) run_length = MAX_ZERO_RUN_LENGTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) t = ((dv * 0x1824429d) >> (32 - D_BITS)) & D_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) m_pos = in + dict[t];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) dict[t] = (lzo_dict_t) (ip - in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (unlikely(dv != get_unaligned_le32(m_pos)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) goto literal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) ii -= ti;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) ti = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) t = ip - ii;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (t != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (t <= 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) op[*state_offset] |= t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) COPY4(op, ii);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) op += t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) } else if (t <= 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) *op++ = (t - 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) COPY8(op, ii);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) COPY8(op + 8, ii + 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) op += t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (t <= 18) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) *op++ = (t - 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) size_t tt = t - 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) *op++ = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) while (unlikely(tt > 255)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) tt -= 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) *op++ = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) *op++ = tt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) COPY8(op, ii);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) COPY8(op + 8, ii + 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) op += 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ii += 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) t -= 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) } while (t >= 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (t > 0) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) *op++ = *ii++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) } while (--t > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (unlikely(run_length)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) ip += run_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) run_length -= MIN_ZERO_RUN_LENGTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) put_unaligned_le32((run_length << 21) | 0xfffc18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) | (run_length & 0x7), op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) op += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) run_length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) *state_offset = -3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) goto finished_writing_instruction;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) m_len = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) u64 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) v = get_unaligned((const u64 *) (ip + m_len)) ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) get_unaligned((const u64 *) (m_pos + m_len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (unlikely(v == 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) m_len += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) v = get_unaligned((const u64 *) (ip + m_len)) ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) get_unaligned((const u64 *) (m_pos + m_len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (unlikely(ip + m_len >= ip_end))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) goto m_len_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) } while (v == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) # if defined(__LITTLE_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) m_len += (unsigned) __builtin_ctzll(v) / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) # elif defined(__BIG_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) m_len += (unsigned) __builtin_clzll(v) / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) # else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) # error "missing endian definition"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) # endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) #elif defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) v = get_unaligned((const u32 *) (ip + m_len)) ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) get_unaligned((const u32 *) (m_pos + m_len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (unlikely(v == 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) m_len += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) v = get_unaligned((const u32 *) (ip + m_len)) ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) get_unaligned((const u32 *) (m_pos + m_len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (v != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) m_len += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) v = get_unaligned((const u32 *) (ip + m_len)) ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) get_unaligned((const u32 *) (m_pos + m_len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (unlikely(ip + m_len >= ip_end))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) goto m_len_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) } while (v == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) # if defined(__LITTLE_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) m_len += (unsigned) __builtin_ctz(v) / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) # elif defined(__BIG_ENDIAN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) m_len += (unsigned) __builtin_clz(v) / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) # else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) # error "missing endian definition"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) # endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (unlikely(ip[m_len] == m_pos[m_len])) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) m_len += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (ip[m_len] != m_pos[m_len])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) m_len += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (ip[m_len] != m_pos[m_len])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) m_len += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (ip[m_len] != m_pos[m_len])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) m_len += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (ip[m_len] != m_pos[m_len])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) m_len += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (ip[m_len] != m_pos[m_len])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) m_len += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (ip[m_len] != m_pos[m_len])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) m_len += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (ip[m_len] != m_pos[m_len])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) m_len += 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) if (unlikely(ip + m_len >= ip_end))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) goto m_len_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) } while (ip[m_len] == m_pos[m_len]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) m_len_done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) m_off = ip - m_pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) ip += m_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) m_off -= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) *op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) *op++ = (m_off >> 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) } else if (m_off <= M3_MAX_OFFSET) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) m_off -= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (m_len <= M3_MAX_LEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) *op++ = (M3_MARKER | (m_len - 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) m_len -= M3_MAX_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) *op++ = M3_MARKER | 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) while (unlikely(m_len > 255)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) m_len -= 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) *op++ = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) *op++ = (m_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) *op++ = (m_off << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) *op++ = (m_off >> 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) m_off -= 0x4000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (m_len <= M4_MAX_LEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) *op++ = (M4_MARKER | ((m_off >> 11) & 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) | (m_len - 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (unlikely(((m_off & 0x403f) == 0x403f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) && (m_len >= 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) && (m_len <= 264))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) && likely(bitstream_version)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) // Under lzo-rle, block copies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) // for 261 <= length <= 264 and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) // (distance & 0x80f3) == 0x80f3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) // can result in ambiguous
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) // output. Adjust length
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) // to 260 to prevent ambiguity.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) ip -= m_len - 260;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) m_len = 260;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) m_len -= M4_MAX_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) *op++ = (M4_MARKER | ((m_off >> 11) & 8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) while (unlikely(m_len > 255)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) m_len -= 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) *op++ = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) *op++ = (m_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) *op++ = (m_off << 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) *op++ = (m_off >> 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) *state_offset = -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) finished_writing_instruction:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) ii = ip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) goto next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) *out_len = op - out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return in_end - (ii - ti);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) unsigned char *out, size_t *out_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) void *wrkmem, const unsigned char bitstream_version)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) const unsigned char *ip = in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) unsigned char *op = out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) unsigned char *data_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) size_t l = in_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) size_t t = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) signed char state_offset = -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) unsigned int m4_max_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) // LZO v0 will never write 17 as first byte (except for zero-length
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) // input), so this is used to version the bitstream
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (bitstream_version > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) *op++ = 17;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) *op++ = bitstream_version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) m4_max_offset = M4_MAX_OFFSET_V1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) m4_max_offset = M4_MAX_OFFSET_V0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) data_start = op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) while (l > 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) size_t ll = l <= (m4_max_offset + 1) ? l : (m4_max_offset + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) uintptr_t ll_end = (uintptr_t) ip + ll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if ((ll_end + ((t + ll) >> 5)) <= ll_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) &state_offset, bitstream_version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) ip += ll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) op += *out_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) l -= ll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) t += l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) if (t > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) const unsigned char *ii = in + in_len - t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (op == data_start && t <= 238) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) *op++ = (17 + t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) } else if (t <= 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) op[state_offset] |= t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) } else if (t <= 18) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) *op++ = (t - 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) size_t tt = t - 18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) *op++ = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) while (tt > 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) tt -= 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) *op++ = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) *op++ = tt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (t >= 16) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) COPY8(op, ii);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) COPY8(op + 8, ii + 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) op += 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) ii += 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) t -= 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) } while (t >= 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (t > 0) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) *op++ = *ii++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) } while (--t > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) *op++ = M4_MARKER | 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) *op++ = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) *op++ = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) *out_len = op - out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return LZO_E_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) int lzo1x_1_compress(const unsigned char *in, size_t in_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) unsigned char *out, size_t *out_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) void *wrkmem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return lzogeneric1x_1_compress(in, in_len, out, out_len, wrkmem, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) int lzorle1x_1_compress(const unsigned char *in, size_t in_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) unsigned char *out, size_t *out_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) void *wrkmem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) return lzogeneric1x_1_compress(in, in_len, out, out_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) wrkmem, LZO_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) EXPORT_SYMBOL_GPL(lzo1x_1_compress);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) EXPORT_SYMBOL_GPL(lzorle1x_1_compress);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) MODULE_DESCRIPTION("LZO1X-1 Compressor");