-
Notifications
You must be signed in to change notification settings - Fork 0
/
sm401_seg009.cpp
184 lines (150 loc) · 5.08 KB
/
sm401_seg009.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* Code from Heikki Orsila's amigadepack 0.02 to replace previous
* PowerPack depacker with license issues.
*
* You'll probably want to use ppcrack stand-alone to crack encrypted
* powerpack files once instead of using brute force at each replay.
*
* Modified for xmp by Claudio Matsuoka, 08/2007
* - merged mld's checks from the old depack sources. Original credits:
* - corrupt file and data detection
* (thanks to Don Adan and Dirk Stoecker for help and infos)
* - implemeted "efficiency" checks
* - further detection based on code by Georg Hoermann
*/
#include <stdlib.h>
#include <stdio.h>
#include "sm401_main.h"
#include "sm401_seg002.h"
#include "sm401_seg009.h"
static inline unsigned int val(const unsigned char *p) {
return (p[0]<<16 | p[1] << 8 | p[2]);
}
static unsigned long depackedlen(const unsigned char *p, unsigned long plen) {
/* DSA1/ROA1 doesn't use the first bytes as a signature "PP20".
* It's used instead for the lenght of the packed data. */
if (p[0] == 'P' && p[1] == 'P' && p[2] == '2' && p[3] == '0')
return val(p+plen-4);
if (readd((Bit8u*)p) == plen)
return val(p+plen-4);
if (readd((Bit8u*)p) + 8 == plen)
return val(p+plen-4);
return 0; /* not a powerpacker file */
}
typedef unsigned char uint8;
typedef unsigned int uint32;
#define PP_READ_BITS(nbits, var) do { \
bit_cnt = (nbits); \
while (bits_left < bit_cnt) { \
if (buf_src < src) return 0; /* out of source bits */ \
bit_buffer |= (*--buf_src << bits_left); \
bits_left += 8; \
} \
(var) = 0; \
bits_left -= bit_cnt; \
while (bit_cnt--) { \
(var) = ((var) << 1) | (bit_buffer & 1); \
bit_buffer >>= 1; \
} \
} while(0)
#define PP_BYTE_OUT(byte) do { \
if (out <= dest) return 0; /* output overflow */ \
*--out = (byte); \
written++; \
} while (0)
int ppDecrunch(uint8 *src, uint8 *dest, uint8 *offset_lens,
uint32 src_len, uint32 dest_len, uint8 skip_bits)
{
uint8 *buf_src, *out, *dest_end, bits_left = 0, bit_cnt;
uint32 bit_buffer = 0, x, todo, offbits, offset, written=0;
if (!NOT_NULL(src) || !NOT_NULL(dest) || offset_lens == NULL) return 0;
/* set up input and output pointers */
buf_src = src + src_len;
out = dest_end = dest + dest_len;
/* skip the first few bits */
PP_READ_BITS(skip_bits, x);
/* while there are input bits left */
while (written < dest_len) {
PP_READ_BITS(1, x);
if (x == 0) {
/* 1bit==0: literal, then match. 1bit==1: just match */
todo = 1; do { PP_READ_BITS(2, x); todo += x; } while (x == 3);
while (todo--) { PP_READ_BITS(8, x); PP_BYTE_OUT(x); }
/* should we end decoding on a literal, break out of the main loop */
if (written == dest_len) break;
}
/* match: read 2 bits for initial offset bitlength / match length */
PP_READ_BITS(2, x);
offbits = offset_lens[x];
todo = x+2;
if (x == 3) {
PP_READ_BITS(1, x);
if (x==0) offbits = 7;
PP_READ_BITS(offbits, offset);
do { PP_READ_BITS(3, x); todo += x; } while (x == 7);
}
else {
PP_READ_BITS(offbits, offset);
}
if ((out + offset) >= dest_end) return 0; /* match overflow */
while (todo--) { x = out[offset]; PP_BYTE_OUT(x); }
}
/* all output bytes written without error */
return 1;
/* return (src == buf_src) ? 1 : 0; */
}
void decomp_pp20(Bit8u *src, Bit8u *dst, Bit8u *p3, unsigned int plen) {
size_t unplen;
if (plen < 4)
fprintf(stderr,"PP20: Length argument is below 4\n");
unplen = depackedlen(src, plen);
if (unplen == 0) {
fprintf(stderr,"PP20: No PP20 file\n");
}
ppDecrunch(&src[8], dst, &src[4], plen - 12, unplen, src[plen -1]);
return;
}
void decomp_rle(unsigned short width, unsigned short height, Bit8u *dst,
Bit8u *src, Bit8u *tmp_buffer, unsigned short mode) {
Bit8u *my_dst;
unsigned short i,x;
unsigned char tmp;
unsigned char cnt;
/* select destination buffer */
if (mode == 5 || mode == 4)
my_dst = tmp_buffer;
else
my_dst = dst;
do {
/* decode one line */
x = width;
do {
tmp = *src++;
if (tmp == 0x7f) {
cnt = *src++;
tmp = *src++;
for (i = 0; i < cnt; i++)
*my_dst++ = tmp;
x -= cnt;
} else {
*my_dst++ = tmp;
x--;
}
} while (x);
/* reverse line */
if (mode == 5 || mode == 4) {
my_dst--;
for (i = width; i; i--)
*dst++ = *my_dst--;
}
/* set destination to next line */
switch (mode) {
case 5: break;
case 3: dst += width;
break;
case 2: dst += 320;
break;
case 4: dst += 320 - width;
break;
}
} while (--height);
}