Compressed LZO File Format

From Bohemia Interactive Community
Revision as of 13:11, 22 June 2021 by Lou Montana (talk | contribs) (Text replacement - "y[ _]*\|[ _]*(arma[0-9]+)[ _]*\|[ _]+" to "y|$1|")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
bi symbol white.png
Disclaimer: This page describes internal undocumented structures of Bohemia Interactive software.

This page contains unofficial information.

Some usage of this information may constitute a violation of the rights of Bohemia Interactive and is in no way endorsed or recommended by Bohemia Interactive.
Bohemia Interactive is not willing to tolerate use of such tools if it contravenes any general licenses granted to end users of this community wiki or BI products.

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