2 * original code: WDOSX-Pack v1.07, (c) 1999-2001 by Joergen Ibsen / Jibz
3 * for data and executable compression software: http://www.ibsensoftware.com/
5 module iv
.oldpakerz
.wdx
/*is aliced*/;
10 // ////////////////////////////////////////////////////////////////////////// //
11 enum WDXUNPACK_LEN2_LIMIT
= 1920;
14 public usize
wdx_packbuf_size (usize size_in
) {
15 if (size_in
< 1) return 0;
16 return size_in
+((size_in
+7)/8)+2;
30 uint *back_tbl
; /* back-table, array */
31 const(ubyte)* bufin
, srcofs
, backptr
;
33 uint *lookup
; /* lookup-table [256][256] */
41 void wdxi_adv_tag_byte (pack_state_t
*ps
, uint bit
) {
42 /* check bitcount and then decrement */
43 if (ps
.bit_count
-- == 0) {
44 if (ps
.size_out
-- == 0) throw new Exception("wdx error");
46 ps
.tag_byte
= ps
.bufout
++;
51 *ps
.tag_byte
= cast(ubyte)(((*ps
.tag_byte
)<<1)|
(bit ?
1 : 0));
55 /* output Gamma2-code for val in range [2..?] ... */
56 void wdxi_out_gamma (pack_state_t
*ps
, uint val
) {
57 uint invertlen
= 0, invert
= 0;
58 /* rotate bits into invert (except last) */
60 invert
= (invert
<<1)|
(val
&0x01);
62 val
= (val
>>1)&0x7FFFFFFF;
64 /* output Gamma2-encoded bits */
65 for (--invertlen
; invertlen
> 0; --invertlen
) {
66 wdxi_adv_tag_byte(ps
, invert
&0x01);
67 wdxi_adv_tag_byte(ps
, 1);
70 wdxi_adv_tag_byte(ps
, invert
&0x01);
71 wdxi_adv_tag_byte(ps
, 0);
75 void wdxi_out_lit (pack_state_t
*ps
, ubyte lit
) {
76 ps
.last_was_match
= 0;
77 wdxi_adv_tag_byte(ps
, 0); /* 0 indicates a literal */
78 if (ps
.size_out
-- == 0) throw new Exception("wdx error");
79 *ps
.bufout
++ = lit
; /* output the literal */
84 void wdxi_out_pair (pack_state_t
*ps
, uint pos
, uint len
, const ubyte *buffer
) {
85 /* if we just had a match, don't use ps.last_match_pos */
86 if (ps
.last_was_match
) {
87 /* if a short match is too far away, encode it as two literals instead */
88 if (pos
> WDXUNPACK_LEN2_LIMIT
&& len
== 2) {
89 wdxi_out_lit(ps
, buffer
[0]);
90 wdxi_out_lit(ps
, buffer
[1]);
92 wdxi_adv_tag_byte(ps
, 1); /* 1 indicates a match */
93 /* a match more than WDXUNPACK_LEN2_LIMIT bytes back will be longer than 2 */
94 if (pos
> WDXUNPACK_LEN2_LIMIT
) --len
;
95 wdxi_out_gamma(ps
, len
); /* output length */
96 ps
.last_match_pos
= pos
--;
98 wdxi_out_gamma(ps
, ((pos
>>6)&0x3FFFFFFF)+2); /* output high part of position */
99 /* output low 6 bits of position */
100 wdxi_adv_tag_byte(ps
, pos
&0x20);
101 wdxi_adv_tag_byte(ps
, pos
&0x10);
102 wdxi_adv_tag_byte(ps
, pos
&0x08);
103 wdxi_adv_tag_byte(ps
, pos
&0x04);
104 wdxi_adv_tag_byte(ps
, pos
&0x02);
105 wdxi_adv_tag_byte(ps
, pos
&0x01);
108 ps
.last_was_match
= 1;
109 /* if a short match is too far away, encode it as two literals instead */
110 if (pos
> WDXUNPACK_LEN2_LIMIT
&& len
== 2 && pos
!= ps
.last_match_pos
) {
111 wdxi_out_lit(ps
, buffer
[0]);
112 wdxi_out_lit(ps
, buffer
[1]);
114 wdxi_adv_tag_byte(ps
, 1); /* 1 indicates a match */
115 /* a match more than WDXUNPACK_LEN2_LIMIT bytes back will be longer than 2 */
116 if (pos
> WDXUNPACK_LEN2_LIMIT
&& pos
!= ps
.last_match_pos
) --len
;
117 wdxi_out_gamma(ps
, len
); /* output length */
118 /* output position */
119 if (pos
== ps
.last_match_pos
) {
120 /* a match with position 0 means use last position */
121 wdxi_adv_tag_byte(ps
, 0);
122 wdxi_adv_tag_byte(ps
, 0);
124 ps
.last_match_pos
= pos
--;
125 /*assert(pos >= 0);*/
126 wdxi_out_gamma(ps
, ((pos
>>6)&0x3FFFFFFF)+3); /* output high part of position */
127 /* output low 6 bits of position */
128 wdxi_adv_tag_byte(ps
, pos
&0x20);
129 wdxi_adv_tag_byte(ps
, pos
&0x10);
130 wdxi_adv_tag_byte(ps
, pos
&0x08);
131 wdxi_adv_tag_byte(ps
, pos
&0x04);
132 wdxi_adv_tag_byte(ps
, pos
&0x02);
133 wdxi_adv_tag_byte(ps
, pos
&0x01);
140 void wdxi_find_match (pack_state_t
*ps
, match_t
*thematch
, const ubyte *buffer
, uint lookback
, uint lookforward
) {
141 uint back_pos
, match_len
, best_match_len
, best_match_pos
;
144 /* temporary variables to avoid indirect addressing into the match */
147 /* update ps.lookup- and backtable up to current position */
148 while (ps
.backptr
< buffer
) {
149 idx0
= ps
.backptr
[0];
150 idx1
= ps
.backptr
[1];
151 ps
.back_tbl
[ps
.next_back_entry
] = ps
.lookup
[idx0
*256+idx1
];
152 ps
.lookup
[idx0
*256+idx1
] = ps
.next_back_entry
;
153 ++ps
.next_back_entry
;
156 /* get position by looking up next two bytes */
157 back_pos
= ps
.lookup
[buffer
[0]*256+buffer
[1]];
158 if (back_pos
!= 0 && lookforward
> 1) {
159 ptr
= back_pos
+ps
.srcofs
;
160 /* go backwards until before buffer */
161 while (ptr
>= buffer
&& back_pos
!= 0) {
162 /*back_pos := PInt(Integer(ps.back_tbl)+back_pos*4)^;*/
163 back_pos
= ps
.back_tbl
[back_pos
];
164 ptr
= back_pos
+ps
.srcofs
;
166 /* search through table entries */
167 while (back_pos
!= 0 && buffer
-ptr
<= lookback
) {
169 /* if this position has a chance to be better */
170 if (*(ptr
+best_match_len
) == *(buffer
+best_match_len
)) {
172 while (match_len
< lookforward
&& *(ptr
+match_len
) == *(buffer
+match_len
)) ++match_len
;
174 if (match_len
+(buffer
-ptr
== ps
.last_match_pos
) > best_match_len
+(best_match_pos
== ps
.last_match_pos
)) {
175 best_match_len
= match_len
;
176 if (best_match_len
== lookforward
) back_pos
= 0;
177 best_match_pos
= buffer
-ptr
;
180 /* move backwards to next position */
181 back_pos
= ps
.back_tbl
[back_pos
];
182 ptr
= back_pos
+ps
.srcofs
;
185 /* forget match if too far away */
186 if (best_match_pos
> WDXUNPACK_LEN2_LIMIT
&& best_match_len
== 2 && best_match_pos
!= ps
.last_match_pos
) {
190 /* update the match with best match */
191 thematch
.len
= best_match_len
;
192 thematch
.pos
= best_match_pos
;
196 // ////////////////////////////////////////////////////////////////////////// //
197 public ssize
wdx_pack (void *buf_out
, usize size_out
, const(void)* buf_in
, usize size_in
) {
198 import core
.stdc
.stdlib
: malloc
, free
;
199 import core
.stdc
.string
: memset
;
200 /* global variables */
202 match_t match
, nextmatch
, literalmatch
, testmatch
;
203 uint pos
, lastpos
, literalCount
;
206 if (size_in
< 1) return 0;
207 if (size_out
< 2) return -1;
209 ps
.bufin
= cast(const(ubyte)*)buf_in
;
210 ps
.bufout
= cast(ubyte*)buf_out
;
211 ps
.lookup
= null; /* lookup-table [256][256] */
212 ps
.last_match_pos
= 0;
213 ps
.last_was_match
= 0;
215 ps
.size_out
= size_out
;
217 if ((ps
.back_tbl
= cast(uint*)malloc((size_in
+4)*4)) is null) return -2; /* out of memory */
218 if ((ps
.lookup
= cast(uint*)malloc(256*256*4)) is null) { free(ps
.back_tbl
); return -2; } /* out of memory */
224 memset(&match
, 0, match
.sizeof
);
225 memset(&nextmatch
, 0, nextmatch
.sizeof
);
226 memset(&literalmatch
, 0, literalmatch
.sizeof
);
227 memset(&testmatch
, 0, testmatch
.sizeof
);
228 literalmatch
.pos
= literalmatch
.len
= 0;
229 ps
.srcofs
= ps
.bufin
-1;
230 /* init ps.lookup- and backtable */
231 memset(ps
.lookup
, 0, 256*256*4);
232 memset(ps
.back_tbl
, 0, (size_in
+4)*4);
233 ps
.backptr
= ps
.bufin
;
235 ps
.next_back_entry
= 1;
237 ps
.last_match_pos
= -1;
238 ps
.last_was_match
= 0;
240 /* the first byte is sent verbatim */
241 *ps
.bufout
++ = *ps
.bufin
++;
246 *(ps
.tag_byte
= ps
.bufout
++) = 0;
251 while (pos
< size_in
) {
252 /* find best match at current position (if not already found) */
253 if (pos
== lastpos
) {
254 match
.len
= nextmatch
.len
;
255 match
.pos
= nextmatch
.pos
;
257 wdxi_find_match(&ps
, &match
, ps
.bufin
, pos
, size_in
-pos
);
259 /* if we found a match, find the best match at the next position */
260 if (match
.len
!= 0) {
261 wdxi_find_match(&ps
, &nextmatch
, ps
.bufin
+1, pos
+1, size_in
-(pos
+1));
266 /* decide if we should output a match or a literal */
267 i0
= (match
.pos
==ps
.last_match_pos ?
1 : 0);
268 i1
= (nextmatch
.pos
==ps
.last_match_pos ?
1 : 0);
269 if (match
.len
!= 0 && match
.len
+i0
>= nextmatch
.len
+i1
) {
270 /* output any pending literals */
271 if (literalCount
!= 0) {
272 if (literalCount
== 1) {
273 wdxi_out_lit(&ps
, ps
.bufin
[-1]);
275 /* check if there is a closer match with the required length */
276 wdxi_find_match(&ps
, &testmatch
, ps
.bufin
-literalCount
, literalmatch
.pos
, literalCount
);
277 if (testmatch
.len
>= literalCount
) {
278 wdxi_out_pair(&ps
, testmatch
.pos
, literalCount
, ps
.bufin
-literalCount
);
280 wdxi_out_pair(&ps
, literalmatch
.pos
, literalCount
, ps
.bufin
-literalCount
);
286 wdxi_out_pair(&ps
, match
.pos
, match
.len
, ps
.bufin
);
287 ps
.bufin
+= match
.len
;
290 /* check if we are allready collecting literals */
291 if (literalCount
!= 0) {
292 /* if so, continue.. */
294 /* have we collected as many as possible? */
295 if (literalCount
== literalmatch
.len
) {
296 wdxi_out_pair(&ps
, literalmatch
.pos
, literalCount
, ps
.bufin
-literalCount
+1);
300 /* if we had a match which was not good enough, then save it.. */
301 if (match
.len
!= 0) {
302 literalmatch
.len
= match
.len
;
303 literalmatch
.pos
= match
.pos
;
306 /* if not, we have to output the literal now */
307 wdxi_out_lit(&ps
, ps
.bufin
[0]);
314 /* output any remaining literal bytes */
315 if (literalCount
!= 0) {
316 if (literalCount
== 1) {
317 wdxi_out_lit(&ps
, ps
.bufin
[-1]);
319 wdxi_out_pair(&ps
, literalmatch
.pos
, literalCount
, ps
.bufin
-literalCount
);
322 /* switch last ps.tag_byte into position */
323 if (ps
.bit_count
!= 8) *ps
.tag_byte
<<= ps
.bit_count
;
329 // ////////////////////////////////////////////////////////////////////////// //
330 public ssize
wdx_unpack (void *buf_out
, usize size_out
, const(void)* buf_in
, usize size_in
) {
331 int len
, pos
, b
, itsOk
;
333 const(ubyte)* src
= cast(const ubyte *)buf_in
;
334 ubyte *dest
= cast(ubyte*)buf_out
;
336 int last_match_pos
= 0, last_was_match
= 0, bCount
= 0, origOutSz
= size_out
;
338 if (size_out
< 1) return 0;
339 if (size_in
< 1) return -1; /* out of input data */
341 auto WDXU_GET_BIT () {
344 if (size_in
< 1) throw new Exception("wdx error");
349 res
= (fbyte
&0x80 ?
1 : 0);
350 fbyte
= (fbyte
&0x7f)<<1;
355 auto WDXU_GET_GAMMA () {
358 res
= (res
<<1)|
WDXU_GET_BIT();
359 } while (WDXU_GET_BIT() == 1);
363 /* get 6 low bits of position */
364 auto WDXU_GET_LO_POS (int _pos
) {
366 for (int f
= 0; f
< 6; ++f
) ps
= (ps
<<1)|
WDXU_GET_BIT();
370 /* the first byte was sent verbatim */
374 while (size_out
> 0) {
380 if (size_in
< 1) break;
381 if (size_out
== 0) return -1;
388 len
= WDXU_GET_GAMMA();
389 if (last_was_match
) {
390 pos
= WDXU_GET_GAMMA()-2;
391 pos
= WDXU_GET_LO_POS(pos
)+1;
392 last_match_pos
= pos
;
393 if (pos
> WDXUNPACK_LEN2_LIMIT
) ++len
;
396 pos
= WDXU_GET_GAMMA()-2;
397 /* same position as last match? */
399 pos
= last_match_pos
;
401 pos
= WDXU_GET_LO_POS(pos
-1)+1;
402 last_match_pos
= pos
;
403 if (pos
> WDXUNPACK_LEN2_LIMIT
) ++len
;
409 if (cast(void*)pp
< cast(void*)buf_out
) return -1; /* shit! */
410 if (size_out
< len
) return -1;
411 for (; len
> 0 && size_out
> 0; --size_out
, --len
) *dest
++ = *pp
++;
414 return origOutSz
-size_out
;
416 /* decompressing error */
417 if (!itsOk
) return -1;
418 return origOutSz
-size_out
;