Compressed LZO File Format: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
m (Some wiki formatting)
m (Text replacement - "\[\[[Cc]ategory:ArmA:[ _]?([^|]+)\]\]" to "{{GameCategory|arma1|$1}}")
Line 226: Line 226:


[[Category:BIS File Formats]]
[[Category:BIS File Formats]]
[[Category:ArmA: File Formats]]
{{GameCategory|arma1| File Formats}}

Revision as of 15:00, 6 January 2021

Template:unsupported-doc This is LZO as defined by oberhumer - http://www.oberhumer.com/opensource/lzo/

there are 3 sources to the LZO code:


Source Code

// some of the includes are for compression only (not listed here)

int lzo::lzo1x_decompress_safe (const byte* in, byte* out, unsigned OutLen)

// returns length of consumed input bytes, or negative status
// Outlen is the desired output 'block size' this function will return neg status if the output buffer is not completely filled

// example call

byte Array = (byte)malloc(Outlen); // no zero clearing is necessary
int status_or_len = lzo->lzo1x_decompress_safe (input, Array, OutLen);#include "minilzo.h"

#include <limits.h>
#include <stddef.h>
#include <limits.h>
#include <stddef.h>
#include <string.h>
#include <malloc.h>

#define assert(val)		if (!(val)) return LZO_E_ERROR
#define M2_MAX_OFFSET	0x0800

#define NEED_OP(x)	if ((unsigned)(op_end - op) < (unsigned)(x)) return LZO_E_OUTPUT_OVERRUN;
#define TEST_LB()	if (m_pos < out || m_pos >= op) return LZO_E_LOOKBEHIND_OVERRUN;

#define COPY4(dst, src) * (unsigned *)(dst) = * (const unsigned *)(src)

int lzo::lzo1x_decompress_safe (const byte* in, byte* out, unsigned OutLen)
{
	register byte* op;
	register const byte* ip;
	register size_t t;
	register const byte* m_pos;

	byte* const op_end = out + OutLen;

	OutLen = 0;
	op = out;
	ip = in;

	if (*ip > 17)
	{
		t = *ip++ - 17;
		if (t < 4) goto match_next;
		assert(t > 0);// return LZO_E_ERROR;
		NEED_OP(t);
		do *op++ = *ip++; while (--t > 0);
		goto first_literal_run;
	}

	while (1)
	{
		t = *ip++;
		if (t >= 16) goto match;
		if (t == 0)
		{
			while (*ip == 0)
			{
				t += 255;
				ip++;
			}
			t += 15 + *ip++;
		}
		assert(t > 0); NEED_OP(t+3);

		COPY4(op, ip);
		op += 4; ip += 4;
		if (--t > 0)
		{
			if (t >= 4)
			{
				do {
					COPY4(op, ip);
					op += 4; ip += 4; t -= 4;
				} while (t >= 4);
				if (t > 0) do *op++ = *ip++; while (--t > 0);
			}
			else
				do *op++ = *ip++; while (--t > 0);
		}

first_literal_run:

		t = *ip++;
		if (t >= 16) goto match;

		m_pos = op - (1 + M2_MAX_OFFSET);
		m_pos -= t >> 2;
		m_pos -= *ip++ << 2;

		TEST_LB();
		NEED_OP(3);
		*op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;

		goto match_done;

		do {
match:
			if (t >= 64)
			{

				m_pos = op - 1;
				m_pos -= (t >> 2) & 7;
				m_pos -= *ip++ << 3;
				t = (t >> 5) - 1;
				TEST_LB(); assert(t > 0); NEED_OP(t+3-1);
				goto copy_match;
			}
			else if (t >= 32)
			{
				t &= 31;
				if (t == 0)
				{
					while (*ip == 0)
					{
						t += 255;
						ip++;
					}
					t += 31 + *ip++;
				}

				m_pos = op - 1;
				m_pos -= (ip[0] >> 2) + (ip[1] << 6);

				ip += 2;
			}
			else if (t >= 16)
			{

				m_pos = op;
				m_pos -= (t & 8) << 11;

				t &= 7;
				if (t == 0)
				{
					while (*ip == 0)
					{
						t += 255;
						ip++;
					}
					t += 7 + *ip++;
				}

				m_pos -= (ip[0] >> 2) + (ip[1] << 6);

				ip += 2;
				////// done
				if (m_pos == op)
				{
					assert(t == 1);
					if (m_pos != op_end)
						return LZO_E_LOOKBEHIND_UNDERRUN;
					return ip-in;
				}
				m_pos -= 0x4000;
			}
			else
			{
				m_pos = op - 1;
				m_pos -= t >> 2;
				m_pos -= *ip++ << 2;

				TEST_LB();
				NEED_OP(2);
				*op++ = *m_pos++; *op++ = *m_pos;
				goto match_done;
			}

			TEST_LB();
			assert(t > 0);
			NEED_OP(t+3-1);

			if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
			{
				COPY4(op, m_pos);
				op += 4; m_pos += 4; t -= 4 - (3 - 1);
				do {
					COPY4(op, m_pos);
					op += 4; m_pos += 4; t -= 4;
				} while (t >= 4);
				if (t > 0) do *op++ = *m_pos++; while (--t > 0);
			}
			else
			{
copy_match:
				*op++ = *m_pos++; *op++ = *m_pos++;

				do *op++ = *m_pos++; while (--t > 0);
			}

match_done:
			t = ip[-2] & 3;
			if (t == 0) break;

match_next:
			assert(t > 0); assert(t < 4); NEED_OP(t);
			*op++ = *ip++;
			if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }

			t = *ip++;
		} while (1);
	}

	// return LZO_E_EOF_NOT_FOUND; // never gets here
}


See Also