Compressed LZO File Format: Difference between revisions
Jump to navigation
Jump to search
mNo edit summary |
Lou Montana (talk | contribs) m (Text replacement - "y[ _]*\|[ _]*(arma[0-9]+)[ _]*\|[ _]+" to "y|$1|") |
||
(3 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
{{ | {{Feature|UnsupportedDoc}} | ||
This is LZO as defined by oberhumer - http://www.oberhumer.com/opensource/lzo/ | |||
This is LZO as defined by oberhumer | |||
there are 3 sources to the LZO code: | |||
* minilzo (on above site) | |||
* lzo version 2 (ditto) | |||
* lzo version 1 (http://sourceforge.net/project/showfiles.php?group_id=102072&package_id=110218&release_id=221836) | |||
== Source Code == | |||
<syntaxhighlight lang="cpp"> | |||
// some of the includes are for compression only (not listed here) | // some of the includes are for compression only (not listed here) | ||
int lzo::lzo1x_decompress_safe ( const byte* in , byte* out, unsigned OutLen) | int lzo::lzo1x_decompress_safe (const byte* in, byte* out, unsigned OutLen) | ||
// returns length of consumed input bytes ,or | // 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 | // Outlen is the desired output 'block size' this function will return neg status if the output buffer is not completely filled | ||
// example call | // example call | ||
byte Array=(byte)malloc(Outlen); // no zero clearing is necessary | byte Array = (byte)malloc(Outlen); // no zero clearing is necessary | ||
int status_or_len=lzo->lzo1x_decompress_safe (input, Array,OutLen);#include "minilzo.h" | int status_or_len = lzo->lzo1x_decompress_safe (input, Array, OutLen);#include "minilzo.h" | ||
#include <limits.h> | #include <limits.h> | ||
Line 32: | Line 31: | ||
#include <malloc.h> | #include <malloc.h> | ||
#define assert(val) if (!(val)) return LZO_E_ERROR | #define assert(val) if (!(val)) return LZO_E_ERROR | ||
#define M2_MAX_OFFSET | #define M2_MAX_OFFSET 0x0800 | ||
#define NEED_OP(x) | #define NEED_OP(x) if ((unsigned)(op_end - op) < (unsigned)(x)) return LZO_E_OUTPUT_OVERRUN; | ||
#define TEST_LB() | #define TEST_LB() if (m_pos < out || m_pos >= op) return LZO_E_LOOKBEHIND_OVERRUN; | ||
#define COPY4(dst,src) | #define COPY4(dst, src) * (unsigned *)(dst) = * (const unsigned *)(src) | ||
int lzo::lzo1x_decompress_safe ( const byte* in , byte* out, unsigned OutLen) | int lzo::lzo1x_decompress_safe (const byte* in, byte* out, unsigned OutLen) | ||
{ | { | ||
register byte* op; | register byte* op; | ||
register const byte* ip; | register const byte* ip; | ||
register size_t t; | register size_t t; | ||
register const byte* m_pos; | register const byte* m_pos; | ||
byte* const op_end = out + OutLen; | 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: | 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: | 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: | copy_match: | ||
*op++ = *m_pos++; *op++ = *m_pos++; | |||
do *op++ = *m_pos++; while (--t > 0); | |||
} | |||
match_done: | match_done: | ||
t = ip[-2] & 3; | |||
if (t == 0) break; | |||
match_next: | 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 | |||
} | |||
</syntaxhighlight> | |||
== See Also == | |||
* [[BIS File Formats#3D Model File Formats|Model File Formats]] | |||
[[ | [[Category:BIS File Formats]] | ||
{{GameCategory|arma1|File Formats}} | |||
Latest revision as of 13:11, 22 June 2021
This is LZO as defined by oberhumer - http://www.oberhumer.com/opensource/lzo/
there are 3 sources to the LZO code:
- minilzo (on above site)
- lzo version 2 (ditto)
- lzo version 1 (http://sourceforge.net/project/showfiles.php?group_id=102072&package_id=110218&release_id=221836)
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
}