1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "bladerunner/decompress_lzo.h"
24 
25 namespace BladeRunner {
26 
decode_count(const uint8 ** pp)27 static inline uint32 decode_count(const uint8 **pp) {
28 	uint32 v = 0;
29 	for (; !**pp; ++(*pp))
30 		v += 255;
31 
32 	v += **pp;
33 	++(*pp);
34 
35 	return v;
36 }
37 
copy(uint8 ** dst,const uint8 ** src,int count)38 static inline void copy(uint8 **dst, const uint8 **src, int count) {
39 	assert(count > 0);
40 
41 	uint8 *d = *dst;
42 	const uint8 *s = *src;
43 
44 	*dst += count;
45 	*src += count;
46 
47 	do { *d++ = *s++; } while (--count);
48 }
49 
decompress_lzo1x(const uint8 * in,size_t inLen,uint8 * out,size_t * outLen)50 int decompress_lzo1x(const uint8 *in, size_t inLen, uint8 *out, size_t *outLen) {
51 	uint32 t;
52 	uint8 *op;
53 	const uint8 *ip, *m_pos;
54 	const uint8 * const ip_end = in + inLen;
55 
56 	*outLen = 0;
57 
58 	op = out;
59 	ip = in;
60 
61 	if (*ip > 17) {
62 		t = *ip++ - 17;
63 		if (t < 4)
64 			goto match_next;
65 		copy(&op, &ip, t);
66 		goto first_literal_run;
67 	}
68 
69 	for (;;) {
70 		t = *ip++;
71 		if (t >= 16)
72 			goto match;
73 
74 		if (t == 0)
75 			t = 15 + decode_count(&ip);
76 		copy(&op, &ip, t + 3);
77 
78 first_literal_run:
79 		t = *ip++;
80 		if (t >= 16)
81 			goto match;
82 		m_pos = op - 0x0801 - (t >> 2) - (*ip++ << 2);
83 		copy(&op, &m_pos, 3);
84 		goto match_done;
85 
86 		for (;;) {
87 match:
88 			if (t >= 64) {
89 				m_pos = op - 1 - ((t >> 2) & 7) - (*ip++ << 3);
90 				t = (t >> 5) - 1;
91 				goto copy_match;
92 			} else if (t >= 32) {
93 				t &= 31;
94 				if (t == 0)
95 					t = 31 + decode_count(&ip);
96 				m_pos = op - 1 - (ip[0] >> 2) - (ip[1] << 6);
97 				ip += 2;
98 			} else if (t >= 16) {
99 				m_pos = op - ((t & 8) << 11);
100 				t &= 7;
101 				if (t == 0)
102 					t = 7 + decode_count(&ip);
103 				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
104 				ip += 2;
105 				if (m_pos == op)
106 					goto eof_found;
107 				m_pos -= 0x4000;
108 			} else {
109 				m_pos = op - 1 - (t >> 2) - (*ip++ << 2);
110 				copy(&op, &m_pos, 2);
111 				goto match_done;
112 			}
113 
114 copy_match:
115 			copy(&op, &m_pos, t + 2);
116 
117 match_done:
118 			t = ip[-2] & 3;
119 			if (t == 0)
120 				break;
121 
122 match_next:
123  			assert(t > 0 && t <= 3);
124 			copy(&op, &ip, t);
125 			t = *ip++;
126 		}
127 	}
128 
129 eof_found:
130 	*outLen = op - out;
131 	return ip != ip_end;
132 }
133 
134 } // End of namespace BladeRunner
135