Created
March 2, 2015 15:56
-
-
Save robert-nix/c045e192c9123f71220e to your computer and use it in GitHub Desktop.
lzo decompressor (lzo1x) with the crap stripped out ("crap" includes sanity checks, so this will crash on invalid bitstream)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef assert | |
| #define assert(x) ((void)0); | |
| #endif | |
| #define LZO_E_OK 0 | |
| #define LZO_E_ERROR (-1) | |
| #define LZO_E_INPUT_OVERRUN (-4) | |
| #define LZO_E_OUTPUT_OVERRUN (-5) | |
| #define LZO_E_LOOKBEHIND_OVERRUN (-6) | |
| #define LZO_E_EOF_NOT_FOUND (-7) | |
| #define LZO_E_INPUT_NOT_CONSUMED (-8) | |
| static int lzo1x_decompress(u8 *in, u32 in_len, u8 *out, u32 *out_len) { | |
| u8 *op; | |
| u8 *ip; | |
| u32 t; | |
| u8 *m_pos; | |
| u8 *ip_end = in + in_len; | |
| u8 *op_end = out + *out_len; | |
| *out_len = 0; | |
| op = out; | |
| ip = in; | |
| if (*ip > 17) { | |
| t = *ip++ - 17; | |
| if (t < 4) | |
| goto match_next; | |
| assert(t > 0); | |
| do | |
| *op++ = *ip++; | |
| while (--t > 0); | |
| goto first_literal_run; | |
| } | |
| while (ip < ip_end && op < op_end) { | |
| t = *ip++; | |
| if (t >= 16) | |
| goto match; | |
| /* a literal run */ | |
| if (t == 0) { | |
| while (*ip == 0) { | |
| t += 255; | |
| ip++; | |
| } | |
| t += 15 + *ip++; | |
| } | |
| /* copy literals */ | |
| assert(t > 0); | |
| *op++ = *ip++; | |
| *op++ = *ip++; | |
| *op++ = *ip++; | |
| do | |
| *op++ = *ip++; | |
| while (--t > 0); | |
| first_literal_run: | |
| t = *ip++; | |
| if (t >= 16) | |
| goto match; | |
| m_pos = op - (1 + 0x0800); | |
| m_pos -= t >> 2; | |
| m_pos -= *ip++ << 2; | |
| *op++ = *m_pos++; | |
| *op++ = *m_pos++; | |
| *op++ = *m_pos; | |
| goto match_done; | |
| /* handle matches */ | |
| do { | |
| match: | |
| if (t >= 64) /* a M2 match */ | |
| { | |
| m_pos = op - 1; | |
| m_pos -= (t >> 2) & 7; | |
| m_pos -= *ip++ << 3; | |
| t = (t >> 5) - 1; | |
| assert(t > 0); | |
| goto copy_match; | |
| } else if (t >= 32) /* a M3 match */ | |
| { | |
| 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) /* a M4 match */ | |
| { | |
| 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; | |
| if (m_pos == op) | |
| goto eof_found; | |
| m_pos -= 0x4000; | |
| } else /* a M1 match */ | |
| { | |
| m_pos = op - 1; | |
| m_pos -= t >> 2; | |
| m_pos -= *ip++ << 2; | |
| *op++ = *m_pos++; | |
| *op++ = *m_pos; | |
| goto match_done; | |
| } | |
| /* copy match */ | |
| assert(t > 0); | |
| 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; | |
| /* copy literals */ | |
| match_next: | |
| assert(t > 0); | |
| assert(t < 4); | |
| *op++ = *ip++; | |
| if (t > 1) { | |
| *op++ = *ip++; | |
| if (t > 2) { | |
| *op++ = *ip++; | |
| } | |
| } | |
| t = *ip++; | |
| } while (ip < ip_end && op < op_end); | |
| } | |
| /* no EOF code was found */ | |
| *out_len = (u32)(op - out); | |
| return LZO_E_EOF_NOT_FOUND; | |
| eof_found: | |
| assert(t == 1); | |
| *out_len = (u32)(op - out); | |
| return (ip == ip_end ? LZO_E_OK : (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED | |
| : LZO_E_INPUT_OVERRUN)); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment