18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  LZO1X Compressor from LZO
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  The full LZO package can be found at:
88c2ecf20Sopenharmony_ci *  http://www.oberhumer.com/opensource/lzo/
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  Changed for Linux kernel use by:
118c2ecf20Sopenharmony_ci *  Nitin Gupta <nitingupta910@gmail.com>
128c2ecf20Sopenharmony_ci *  Richard Purdie <rpurdie@openedhand.com>
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
188c2ecf20Sopenharmony_ci#include <linux/lzo.h>
198c2ecf20Sopenharmony_ci#include "lzodefs.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic noinline size_t
228c2ecf20Sopenharmony_cilzo1x_1_do_compress(const unsigned char *in, size_t in_len,
238c2ecf20Sopenharmony_ci		    unsigned char *out, size_t *out_len,
248c2ecf20Sopenharmony_ci		    size_t ti, void *wrkmem, signed char *state_offset,
258c2ecf20Sopenharmony_ci		    const unsigned char bitstream_version)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	const unsigned char *ip;
288c2ecf20Sopenharmony_ci	unsigned char *op;
298c2ecf20Sopenharmony_ci	const unsigned char * const in_end = in + in_len;
308c2ecf20Sopenharmony_ci	const unsigned char * const ip_end = in + in_len - 20;
318c2ecf20Sopenharmony_ci	const unsigned char *ii;
328c2ecf20Sopenharmony_ci	lzo_dict_t * const dict = (lzo_dict_t *) wrkmem;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	op = out;
358c2ecf20Sopenharmony_ci	ip = in;
368c2ecf20Sopenharmony_ci	ii = ip;
378c2ecf20Sopenharmony_ci	ip += ti < 4 ? 4 - ti : 0;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	for (;;) {
408c2ecf20Sopenharmony_ci		const unsigned char *m_pos = NULL;
418c2ecf20Sopenharmony_ci		size_t t, m_len, m_off;
428c2ecf20Sopenharmony_ci		u32 dv;
438c2ecf20Sopenharmony_ci		u32 run_length = 0;
448c2ecf20Sopenharmony_ciliteral:
458c2ecf20Sopenharmony_ci		ip += 1 + ((ip - ii) >> 5);
468c2ecf20Sopenharmony_cinext:
478c2ecf20Sopenharmony_ci		if (unlikely(ip >= ip_end))
488c2ecf20Sopenharmony_ci			break;
498c2ecf20Sopenharmony_ci		dv = get_unaligned_le32(ip);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci		if (dv == 0 && bitstream_version) {
528c2ecf20Sopenharmony_ci			const unsigned char *ir = ip + 4;
538c2ecf20Sopenharmony_ci			const unsigned char *limit = ip_end
548c2ecf20Sopenharmony_ci				< (ip + MAX_ZERO_RUN_LENGTH + 1)
558c2ecf20Sopenharmony_ci				? ip_end : ip + MAX_ZERO_RUN_LENGTH + 1;
568c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && \
578c2ecf20Sopenharmony_ci	defined(LZO_FAST_64BIT_MEMORY_ACCESS)
588c2ecf20Sopenharmony_ci			u64 dv64;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci			for (; (ir + 32) <= limit; ir += 32) {
618c2ecf20Sopenharmony_ci				dv64 = get_unaligned((u64 *)ir);
628c2ecf20Sopenharmony_ci				dv64 |= get_unaligned((u64 *)ir + 1);
638c2ecf20Sopenharmony_ci				dv64 |= get_unaligned((u64 *)ir + 2);
648c2ecf20Sopenharmony_ci				dv64 |= get_unaligned((u64 *)ir + 3);
658c2ecf20Sopenharmony_ci				if (dv64)
668c2ecf20Sopenharmony_ci					break;
678c2ecf20Sopenharmony_ci			}
688c2ecf20Sopenharmony_ci			for (; (ir + 8) <= limit; ir += 8) {
698c2ecf20Sopenharmony_ci				dv64 = get_unaligned((u64 *)ir);
708c2ecf20Sopenharmony_ci				if (dv64) {
718c2ecf20Sopenharmony_ci#  if defined(__LITTLE_ENDIAN)
728c2ecf20Sopenharmony_ci					ir += __builtin_ctzll(dv64) >> 3;
738c2ecf20Sopenharmony_ci#  elif defined(__BIG_ENDIAN)
748c2ecf20Sopenharmony_ci					ir += __builtin_clzll(dv64) >> 3;
758c2ecf20Sopenharmony_ci#  else
768c2ecf20Sopenharmony_ci#    error "missing endian definition"
778c2ecf20Sopenharmony_ci#  endif
788c2ecf20Sopenharmony_ci					break;
798c2ecf20Sopenharmony_ci				}
808c2ecf20Sopenharmony_ci			}
818c2ecf20Sopenharmony_ci#else
828c2ecf20Sopenharmony_ci			while ((ir < (const unsigned char *)
838c2ecf20Sopenharmony_ci					ALIGN((uintptr_t)ir, 4)) &&
848c2ecf20Sopenharmony_ci					(ir < limit) && (*ir == 0))
858c2ecf20Sopenharmony_ci				ir++;
868c2ecf20Sopenharmony_ci			if (IS_ALIGNED((uintptr_t)ir, 4)) {
878c2ecf20Sopenharmony_ci				for (; (ir + 4) <= limit; ir += 4) {
888c2ecf20Sopenharmony_ci					dv = *((u32 *)ir);
898c2ecf20Sopenharmony_ci					if (dv) {
908c2ecf20Sopenharmony_ci#  if defined(__LITTLE_ENDIAN)
918c2ecf20Sopenharmony_ci						ir += __builtin_ctz(dv) >> 3;
928c2ecf20Sopenharmony_ci#  elif defined(__BIG_ENDIAN)
938c2ecf20Sopenharmony_ci						ir += __builtin_clz(dv) >> 3;
948c2ecf20Sopenharmony_ci#  else
958c2ecf20Sopenharmony_ci#    error "missing endian definition"
968c2ecf20Sopenharmony_ci#  endif
978c2ecf20Sopenharmony_ci						break;
988c2ecf20Sopenharmony_ci					}
998c2ecf20Sopenharmony_ci				}
1008c2ecf20Sopenharmony_ci			}
1018c2ecf20Sopenharmony_ci#endif
1028c2ecf20Sopenharmony_ci			while (likely(ir < limit) && unlikely(*ir == 0))
1038c2ecf20Sopenharmony_ci				ir++;
1048c2ecf20Sopenharmony_ci			run_length = ir - ip;
1058c2ecf20Sopenharmony_ci			if (run_length > MAX_ZERO_RUN_LENGTH)
1068c2ecf20Sopenharmony_ci				run_length = MAX_ZERO_RUN_LENGTH;
1078c2ecf20Sopenharmony_ci		} else {
1088c2ecf20Sopenharmony_ci			t = ((dv * 0x1824429d) >> (32 - D_BITS)) & D_MASK;
1098c2ecf20Sopenharmony_ci			m_pos = in + dict[t];
1108c2ecf20Sopenharmony_ci			dict[t] = (lzo_dict_t) (ip - in);
1118c2ecf20Sopenharmony_ci			if (unlikely(dv != get_unaligned_le32(m_pos)))
1128c2ecf20Sopenharmony_ci				goto literal;
1138c2ecf20Sopenharmony_ci		}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci		ii -= ti;
1168c2ecf20Sopenharmony_ci		ti = 0;
1178c2ecf20Sopenharmony_ci		t = ip - ii;
1188c2ecf20Sopenharmony_ci		if (t != 0) {
1198c2ecf20Sopenharmony_ci			if (t <= 3) {
1208c2ecf20Sopenharmony_ci				op[*state_offset] |= t;
1218c2ecf20Sopenharmony_ci				COPY4(op, ii);
1228c2ecf20Sopenharmony_ci				op += t;
1238c2ecf20Sopenharmony_ci			} else if (t <= 16) {
1248c2ecf20Sopenharmony_ci				*op++ = (t - 3);
1258c2ecf20Sopenharmony_ci				COPY8(op, ii);
1268c2ecf20Sopenharmony_ci				COPY8(op + 8, ii + 8);
1278c2ecf20Sopenharmony_ci				op += t;
1288c2ecf20Sopenharmony_ci			} else {
1298c2ecf20Sopenharmony_ci				if (t <= 18) {
1308c2ecf20Sopenharmony_ci					*op++ = (t - 3);
1318c2ecf20Sopenharmony_ci				} else {
1328c2ecf20Sopenharmony_ci					size_t tt = t - 18;
1338c2ecf20Sopenharmony_ci					*op++ = 0;
1348c2ecf20Sopenharmony_ci					while (unlikely(tt > 255)) {
1358c2ecf20Sopenharmony_ci						tt -= 255;
1368c2ecf20Sopenharmony_ci						*op++ = 0;
1378c2ecf20Sopenharmony_ci					}
1388c2ecf20Sopenharmony_ci					*op++ = tt;
1398c2ecf20Sopenharmony_ci				}
1408c2ecf20Sopenharmony_ci				do {
1418c2ecf20Sopenharmony_ci					COPY8(op, ii);
1428c2ecf20Sopenharmony_ci					COPY8(op + 8, ii + 8);
1438c2ecf20Sopenharmony_ci					op += 16;
1448c2ecf20Sopenharmony_ci					ii += 16;
1458c2ecf20Sopenharmony_ci					t -= 16;
1468c2ecf20Sopenharmony_ci				} while (t >= 16);
1478c2ecf20Sopenharmony_ci				if (t > 0) do {
1488c2ecf20Sopenharmony_ci					*op++ = *ii++;
1498c2ecf20Sopenharmony_ci				} while (--t > 0);
1508c2ecf20Sopenharmony_ci			}
1518c2ecf20Sopenharmony_ci		}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci		if (unlikely(run_length)) {
1548c2ecf20Sopenharmony_ci			ip += run_length;
1558c2ecf20Sopenharmony_ci			run_length -= MIN_ZERO_RUN_LENGTH;
1568c2ecf20Sopenharmony_ci			put_unaligned_le32((run_length << 21) | 0xfffc18
1578c2ecf20Sopenharmony_ci					   | (run_length & 0x7), op);
1588c2ecf20Sopenharmony_ci			op += 4;
1598c2ecf20Sopenharmony_ci			run_length = 0;
1608c2ecf20Sopenharmony_ci			*state_offset = -3;
1618c2ecf20Sopenharmony_ci			goto finished_writing_instruction;
1628c2ecf20Sopenharmony_ci		}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci		m_len = 4;
1658c2ecf20Sopenharmony_ci		{
1668c2ecf20Sopenharmony_ci#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ64)
1678c2ecf20Sopenharmony_ci		u64 v;
1688c2ecf20Sopenharmony_ci		v = get_unaligned((const u64 *) (ip + m_len)) ^
1698c2ecf20Sopenharmony_ci		    get_unaligned((const u64 *) (m_pos + m_len));
1708c2ecf20Sopenharmony_ci		if (unlikely(v == 0)) {
1718c2ecf20Sopenharmony_ci			do {
1728c2ecf20Sopenharmony_ci				m_len += 8;
1738c2ecf20Sopenharmony_ci				v = get_unaligned((const u64 *) (ip + m_len)) ^
1748c2ecf20Sopenharmony_ci				    get_unaligned((const u64 *) (m_pos + m_len));
1758c2ecf20Sopenharmony_ci				if (unlikely(ip + m_len >= ip_end))
1768c2ecf20Sopenharmony_ci					goto m_len_done;
1778c2ecf20Sopenharmony_ci			} while (v == 0);
1788c2ecf20Sopenharmony_ci		}
1798c2ecf20Sopenharmony_ci#  if defined(__LITTLE_ENDIAN)
1808c2ecf20Sopenharmony_ci		m_len += (unsigned) __builtin_ctzll(v) / 8;
1818c2ecf20Sopenharmony_ci#  elif defined(__BIG_ENDIAN)
1828c2ecf20Sopenharmony_ci		m_len += (unsigned) __builtin_clzll(v) / 8;
1838c2ecf20Sopenharmony_ci#  else
1848c2ecf20Sopenharmony_ci#    error "missing endian definition"
1858c2ecf20Sopenharmony_ci#  endif
1868c2ecf20Sopenharmony_ci#elif defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ32)
1878c2ecf20Sopenharmony_ci		u32 v;
1888c2ecf20Sopenharmony_ci		v = get_unaligned((const u32 *) (ip + m_len)) ^
1898c2ecf20Sopenharmony_ci		    get_unaligned((const u32 *) (m_pos + m_len));
1908c2ecf20Sopenharmony_ci		if (unlikely(v == 0)) {
1918c2ecf20Sopenharmony_ci			do {
1928c2ecf20Sopenharmony_ci				m_len += 4;
1938c2ecf20Sopenharmony_ci				v = get_unaligned((const u32 *) (ip + m_len)) ^
1948c2ecf20Sopenharmony_ci				    get_unaligned((const u32 *) (m_pos + m_len));
1958c2ecf20Sopenharmony_ci				if (v != 0)
1968c2ecf20Sopenharmony_ci					break;
1978c2ecf20Sopenharmony_ci				m_len += 4;
1988c2ecf20Sopenharmony_ci				v = get_unaligned((const u32 *) (ip + m_len)) ^
1998c2ecf20Sopenharmony_ci				    get_unaligned((const u32 *) (m_pos + m_len));
2008c2ecf20Sopenharmony_ci				if (unlikely(ip + m_len >= ip_end))
2018c2ecf20Sopenharmony_ci					goto m_len_done;
2028c2ecf20Sopenharmony_ci			} while (v == 0);
2038c2ecf20Sopenharmony_ci		}
2048c2ecf20Sopenharmony_ci#  if defined(__LITTLE_ENDIAN)
2058c2ecf20Sopenharmony_ci		m_len += (unsigned) __builtin_ctz(v) / 8;
2068c2ecf20Sopenharmony_ci#  elif defined(__BIG_ENDIAN)
2078c2ecf20Sopenharmony_ci		m_len += (unsigned) __builtin_clz(v) / 8;
2088c2ecf20Sopenharmony_ci#  else
2098c2ecf20Sopenharmony_ci#    error "missing endian definition"
2108c2ecf20Sopenharmony_ci#  endif
2118c2ecf20Sopenharmony_ci#else
2128c2ecf20Sopenharmony_ci		if (unlikely(ip[m_len] == m_pos[m_len])) {
2138c2ecf20Sopenharmony_ci			do {
2148c2ecf20Sopenharmony_ci				m_len += 1;
2158c2ecf20Sopenharmony_ci				if (ip[m_len] != m_pos[m_len])
2168c2ecf20Sopenharmony_ci					break;
2178c2ecf20Sopenharmony_ci				m_len += 1;
2188c2ecf20Sopenharmony_ci				if (ip[m_len] != m_pos[m_len])
2198c2ecf20Sopenharmony_ci					break;
2208c2ecf20Sopenharmony_ci				m_len += 1;
2218c2ecf20Sopenharmony_ci				if (ip[m_len] != m_pos[m_len])
2228c2ecf20Sopenharmony_ci					break;
2238c2ecf20Sopenharmony_ci				m_len += 1;
2248c2ecf20Sopenharmony_ci				if (ip[m_len] != m_pos[m_len])
2258c2ecf20Sopenharmony_ci					break;
2268c2ecf20Sopenharmony_ci				m_len += 1;
2278c2ecf20Sopenharmony_ci				if (ip[m_len] != m_pos[m_len])
2288c2ecf20Sopenharmony_ci					break;
2298c2ecf20Sopenharmony_ci				m_len += 1;
2308c2ecf20Sopenharmony_ci				if (ip[m_len] != m_pos[m_len])
2318c2ecf20Sopenharmony_ci					break;
2328c2ecf20Sopenharmony_ci				m_len += 1;
2338c2ecf20Sopenharmony_ci				if (ip[m_len] != m_pos[m_len])
2348c2ecf20Sopenharmony_ci					break;
2358c2ecf20Sopenharmony_ci				m_len += 1;
2368c2ecf20Sopenharmony_ci				if (unlikely(ip + m_len >= ip_end))
2378c2ecf20Sopenharmony_ci					goto m_len_done;
2388c2ecf20Sopenharmony_ci			} while (ip[m_len] == m_pos[m_len]);
2398c2ecf20Sopenharmony_ci		}
2408c2ecf20Sopenharmony_ci#endif
2418c2ecf20Sopenharmony_ci		}
2428c2ecf20Sopenharmony_cim_len_done:
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		m_off = ip - m_pos;
2458c2ecf20Sopenharmony_ci		ip += m_len;
2468c2ecf20Sopenharmony_ci		if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
2478c2ecf20Sopenharmony_ci			m_off -= 1;
2488c2ecf20Sopenharmony_ci			*op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2));
2498c2ecf20Sopenharmony_ci			*op++ = (m_off >> 3);
2508c2ecf20Sopenharmony_ci		} else if (m_off <= M3_MAX_OFFSET) {
2518c2ecf20Sopenharmony_ci			m_off -= 1;
2528c2ecf20Sopenharmony_ci			if (m_len <= M3_MAX_LEN)
2538c2ecf20Sopenharmony_ci				*op++ = (M3_MARKER | (m_len - 2));
2548c2ecf20Sopenharmony_ci			else {
2558c2ecf20Sopenharmony_ci				m_len -= M3_MAX_LEN;
2568c2ecf20Sopenharmony_ci				*op++ = M3_MARKER | 0;
2578c2ecf20Sopenharmony_ci				while (unlikely(m_len > 255)) {
2588c2ecf20Sopenharmony_ci					m_len -= 255;
2598c2ecf20Sopenharmony_ci					*op++ = 0;
2608c2ecf20Sopenharmony_ci				}
2618c2ecf20Sopenharmony_ci				*op++ = (m_len);
2628c2ecf20Sopenharmony_ci			}
2638c2ecf20Sopenharmony_ci			*op++ = (m_off << 2);
2648c2ecf20Sopenharmony_ci			*op++ = (m_off >> 6);
2658c2ecf20Sopenharmony_ci		} else {
2668c2ecf20Sopenharmony_ci			m_off -= 0x4000;
2678c2ecf20Sopenharmony_ci			if (m_len <= M4_MAX_LEN)
2688c2ecf20Sopenharmony_ci				*op++ = (M4_MARKER | ((m_off >> 11) & 8)
2698c2ecf20Sopenharmony_ci						| (m_len - 2));
2708c2ecf20Sopenharmony_ci			else {
2718c2ecf20Sopenharmony_ci				if (unlikely(((m_off & 0x403f) == 0x403f)
2728c2ecf20Sopenharmony_ci						&& (m_len >= 261)
2738c2ecf20Sopenharmony_ci						&& (m_len <= 264))
2748c2ecf20Sopenharmony_ci						&& likely(bitstream_version)) {
2758c2ecf20Sopenharmony_ci					// Under lzo-rle, block copies
2768c2ecf20Sopenharmony_ci					// for 261 <= length <= 264 and
2778c2ecf20Sopenharmony_ci					// (distance & 0x80f3) == 0x80f3
2788c2ecf20Sopenharmony_ci					// can result in ambiguous
2798c2ecf20Sopenharmony_ci					// output. Adjust length
2808c2ecf20Sopenharmony_ci					// to 260 to prevent ambiguity.
2818c2ecf20Sopenharmony_ci					ip -= m_len - 260;
2828c2ecf20Sopenharmony_ci					m_len = 260;
2838c2ecf20Sopenharmony_ci				}
2848c2ecf20Sopenharmony_ci				m_len -= M4_MAX_LEN;
2858c2ecf20Sopenharmony_ci				*op++ = (M4_MARKER | ((m_off >> 11) & 8));
2868c2ecf20Sopenharmony_ci				while (unlikely(m_len > 255)) {
2878c2ecf20Sopenharmony_ci					m_len -= 255;
2888c2ecf20Sopenharmony_ci					*op++ = 0;
2898c2ecf20Sopenharmony_ci				}
2908c2ecf20Sopenharmony_ci				*op++ = (m_len);
2918c2ecf20Sopenharmony_ci			}
2928c2ecf20Sopenharmony_ci			*op++ = (m_off << 2);
2938c2ecf20Sopenharmony_ci			*op++ = (m_off >> 6);
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci		*state_offset = -2;
2968c2ecf20Sopenharmony_cifinished_writing_instruction:
2978c2ecf20Sopenharmony_ci		ii = ip;
2988c2ecf20Sopenharmony_ci		goto next;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci	*out_len = op - out;
3018c2ecf20Sopenharmony_ci	return in_end - (ii - ti);
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ciint lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
3058c2ecf20Sopenharmony_ci		     unsigned char *out, size_t *out_len,
3068c2ecf20Sopenharmony_ci		     void *wrkmem, const unsigned char bitstream_version)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	const unsigned char *ip = in;
3098c2ecf20Sopenharmony_ci	unsigned char *op = out;
3108c2ecf20Sopenharmony_ci	unsigned char *data_start;
3118c2ecf20Sopenharmony_ci	size_t l = in_len;
3128c2ecf20Sopenharmony_ci	size_t t = 0;
3138c2ecf20Sopenharmony_ci	signed char state_offset = -2;
3148c2ecf20Sopenharmony_ci	unsigned int m4_max_offset;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	// LZO v0 will never write 17 as first byte (except for zero-length
3178c2ecf20Sopenharmony_ci	// input), so this is used to version the bitstream
3188c2ecf20Sopenharmony_ci	if (bitstream_version > 0) {
3198c2ecf20Sopenharmony_ci		*op++ = 17;
3208c2ecf20Sopenharmony_ci		*op++ = bitstream_version;
3218c2ecf20Sopenharmony_ci		m4_max_offset = M4_MAX_OFFSET_V1;
3228c2ecf20Sopenharmony_ci	} else {
3238c2ecf20Sopenharmony_ci		m4_max_offset = M4_MAX_OFFSET_V0;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	data_start = op;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	while (l > 20) {
3298c2ecf20Sopenharmony_ci		size_t ll = l <= (m4_max_offset + 1) ? l : (m4_max_offset + 1);
3308c2ecf20Sopenharmony_ci		uintptr_t ll_end = (uintptr_t) ip + ll;
3318c2ecf20Sopenharmony_ci		if ((ll_end + ((t + ll) >> 5)) <= ll_end)
3328c2ecf20Sopenharmony_ci			break;
3338c2ecf20Sopenharmony_ci		BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS);
3348c2ecf20Sopenharmony_ci		memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t));
3358c2ecf20Sopenharmony_ci		t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem,
3368c2ecf20Sopenharmony_ci					&state_offset, bitstream_version);
3378c2ecf20Sopenharmony_ci		ip += ll;
3388c2ecf20Sopenharmony_ci		op += *out_len;
3398c2ecf20Sopenharmony_ci		l  -= ll;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci	t += l;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (t > 0) {
3448c2ecf20Sopenharmony_ci		const unsigned char *ii = in + in_len - t;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		if (op == data_start && t <= 238) {
3478c2ecf20Sopenharmony_ci			*op++ = (17 + t);
3488c2ecf20Sopenharmony_ci		} else if (t <= 3) {
3498c2ecf20Sopenharmony_ci			op[state_offset] |= t;
3508c2ecf20Sopenharmony_ci		} else if (t <= 18) {
3518c2ecf20Sopenharmony_ci			*op++ = (t - 3);
3528c2ecf20Sopenharmony_ci		} else {
3538c2ecf20Sopenharmony_ci			size_t tt = t - 18;
3548c2ecf20Sopenharmony_ci			*op++ = 0;
3558c2ecf20Sopenharmony_ci			while (tt > 255) {
3568c2ecf20Sopenharmony_ci				tt -= 255;
3578c2ecf20Sopenharmony_ci				*op++ = 0;
3588c2ecf20Sopenharmony_ci			}
3598c2ecf20Sopenharmony_ci			*op++ = tt;
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci		if (t >= 16) do {
3628c2ecf20Sopenharmony_ci			COPY8(op, ii);
3638c2ecf20Sopenharmony_ci			COPY8(op + 8, ii + 8);
3648c2ecf20Sopenharmony_ci			op += 16;
3658c2ecf20Sopenharmony_ci			ii += 16;
3668c2ecf20Sopenharmony_ci			t -= 16;
3678c2ecf20Sopenharmony_ci		} while (t >= 16);
3688c2ecf20Sopenharmony_ci		if (t > 0) do {
3698c2ecf20Sopenharmony_ci			*op++ = *ii++;
3708c2ecf20Sopenharmony_ci		} while (--t > 0);
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	*op++ = M4_MARKER | 1;
3748c2ecf20Sopenharmony_ci	*op++ = 0;
3758c2ecf20Sopenharmony_ci	*op++ = 0;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	*out_len = op - out;
3788c2ecf20Sopenharmony_ci	return LZO_E_OK;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ciint lzo1x_1_compress(const unsigned char *in, size_t in_len,
3828c2ecf20Sopenharmony_ci		     unsigned char *out, size_t *out_len,
3838c2ecf20Sopenharmony_ci		     void *wrkmem)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	return lzogeneric1x_1_compress(in, in_len, out, out_len, wrkmem, 0);
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ciint lzorle1x_1_compress(const unsigned char *in, size_t in_len,
3898c2ecf20Sopenharmony_ci		     unsigned char *out, size_t *out_len,
3908c2ecf20Sopenharmony_ci		     void *wrkmem)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	return lzogeneric1x_1_compress(in, in_len, out, out_len,
3938c2ecf20Sopenharmony_ci				       wrkmem, LZO_VERSION);
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lzo1x_1_compress);
3978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lzorle1x_1_compress);
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
4008c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LZO1X-1 Compressor");
401