1 /***********************************************************************
2 * This file is part of HA, a general purpose file archiver.
3 * Copyright (C) 1995 Harri Hirvola
4 * Modified by Ketmar // Invisible Vector
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ***********************************************************************/
20 module iv
.oldpakerz
.hapack
/*is aliced*/;
25 // ////////////////////////////////////////////////////////////////////////// //
26 alias libha_read_fn
= int delegate (void *buf
, int buf_len
); // return number of bytes read; 0: EOF; <0: error; can be less than buf_len
27 alias libha_write_fn
= int delegate (const(void)* buf
, int buf_len
); // result != buf_len: error
30 // ////////////////////////////////////////////////////////////////////////// //
31 public alias libha_t
= libha_s
*;
34 // ////////////////////////////////////////////////////////////////////////// //
36 // ////////////////////////////////////////////////////////////////////////// //
38 enum POSCODES
= 31200; // also, dictionary buffer len for SWD
43 enum LLMASK
= LLLEN
-1;
44 enum LENCODES
= SLCODES
+LLCODES
*LLLEN
;
45 enum LTCODES
= SLCODES
+LLCODES
;
49 enum MAXLT
= 750*LTSTEP
;
51 enum MAXCT
= 1000*CTSTEP
;
53 enum MAXPT
= 250*PTSTEP
;
55 enum MAXTT
= 150*TTSTEP
;
57 enum TTOMASK
= TTORD
-1;
58 enum LCUTOFF
= 3*LTSTEP
;
59 enum CCUTOFF
= 3*CTSTEP
;
62 enum MINLENLIM
= 4096;
65 // Minimum possible match lenght for this implementation
71 enum MAXFLEN
= LENCODES
+MINLEN
-1; // max len to be found
72 enum MAXDLEN
= POSCODES
+MAXFLEN
; // reserved bytes for dict; POSCODES+2*MAXFLEN-1<32768 !!!
74 enum HASH(string p
) = "((swd.b["~p
~"]^((swd.b["~p
~"+1]^(swd.b["~p
~"+2]<<HSHIFT))<<HSHIFT))&(HSIZE-1))";
77 // ////////////////////////////////////////////////////////////////////////// //
80 libha_write_fn bwrite
;
93 // ////////////////////////////////////////////////////////////////////////// //
94 int get_byte (io_t
*io
) {
95 if (io
.bufin_pos
>= io
.bufin_max
) {
96 if (io
.bufin_pos
< io
.bufin_size
+1) {
98 io
.bufin_max
= io
.bread(io
.bufin
, io
.bufin_size
);
99 if (io
.bufin_max
< 0) throw new Exception("read error");
100 if (io
.bufin_max
== 0) { io
.bufin_pos
= io
.bufin_size
+42; return -1; } // EOF
105 return io
.bufin
[io
.bufin_pos
++];
109 void put_byte (io_t
*io
, int c
) {
110 if (io
.bufout_pos
>= io
.bufout_size
) {
111 int res
= io
.bwrite(io
.bufout
, io
.bufout_pos
);
112 if (res
!= io
.bufout_pos
) throw new Exception("write error");
115 io
.bufout
[io
.bufout_pos
++] = c
&0xff;
119 void flush (io_t
*io
) {
120 if (io
.bufout_pos
> 0) {
121 int res
= io
.bwrite(io
.bufout
, io
.bufout_pos
);
122 if (res
!= io
.bufout_pos
) throw new Exception("write error");
128 // ////////////////////////////////////////////////////////////////////////// //
130 ushort swd_bpos
, swd_mlf
;
133 ushort bbf
, bbl
, inptr
;
137 ushort[MAXDLEN
] best
;
138 ubyte[MAXDLEN
+MAXFLEN
] b
; // was:-1
144 void swd_init (swd_t
*swd
) {
145 import core
.stdc
.string
: memset
;
146 memset(swd
.ccnt
.ptr
, 0, swd
.ccnt
.sizeof
);
147 memset(swd
.ll
.ptr
, 0, swd
.ll
.sizeof
);
148 memset(swd
.cr
.ptr
, 0, swd
.cr
.sizeof
);
149 memset(swd
.best
.ptr
, 0, swd
.best
.sizeof
);
150 memset(swd
.b
.ptr
, 0, swd
.b
.sizeof
);
151 swd
.binb
= swd
.bbf
= swd
.bbl
= swd
.inptr
= 0;
152 swd
.swd_mlf
= MINLEN
-1;
156 // return -1 on EOF or 0
157 int swd_first_bytes (swd_t
*swd
) {
158 while (swd
.bbl
< MAXFLEN
) {
159 int b
= get_byte(swd
.io
);
160 if (b
< 0) return -1;
161 swd
.b
[swd
.inptr
++] = cast(ubyte)b
;
168 void swd_accept (swd_t
*swd
) {
169 short j
= cast(short)(swd
.swd_mlf
-2);
170 // relies on non changed swd.swd_mlf !!!
173 if (swd
.binb
== POSCODES
) --swd
.ccnt
[mixin(HASH
!"swd.inptr")]; else ++swd
.binb
;
174 i
= mixin(HASH
!"swd.bbf");
175 swd
.ll
[swd
.bbf
] = swd
.cr
[i
];
177 swd
.best
[swd
.bbf
] = 30000;
179 if (++swd
.bbf
== MAXDLEN
) swd
.bbf
= 0;
180 if ((i
= cast(short)get_byte(swd
.io
)) < 0) {
182 if (++swd
.inptr
== MAXDLEN
) swd
.inptr
= 0;
185 if (swd
.inptr
< MAXFLEN
-1) {
186 swd
.b
[swd
.inptr
+MAXDLEN
] = swd
.b
[swd
.inptr
] = cast(ubyte)i
;
189 swd
.b
[swd
.inptr
] = cast(ubyte)i
;
190 if (++swd
.inptr
== MAXDLEN
) swd
.inptr
= 0;
193 swd
.swd_mlf
= MINLEN
-1;
197 void swd_findbest (swd_t
*swd
) {
198 ushort ref_
, ptr
, start_len
;
200 ushort i
= mixin(HASH
!"swd.bbf");
201 ushort cnt
= swd
.ccnt
[i
];
203 if (cnt
> MAXCNT
) cnt
= MAXCNT
;
204 ptr
= swd
.ll
[swd
.bbf
] = swd
.cr
[i
];
206 swd
.swd_char
= swd
.b
[swd
.bbf
];
207 if ((start_len
= swd
.swd_mlf
) >= swd
.bbl
) {
208 if (swd
.bbl
== 0) swd
.swd_char
= -1;
209 swd
.best
[swd
.bbf
] = 30000;
211 for (ref_
= swd
.b
[swd
.bbf
+swd
.swd_mlf
-1]; cnt
--; ptr
= swd
.ll
[ptr
]) {
212 if (swd
.b
[ptr
+swd
.swd_mlf
-1] == ref_
&& swd
.b
[ptr
] == swd
.b
[swd
.bbf
] && swd
.b
[ptr
+1] == swd
.b
[swd
.bbf
+1]) {
213 ubyte *p1
= swd
.b
.ptr
+ptr
+3;
214 ubyte *p2
= swd
.b
.ptr
+swd
.bbf
+3;
215 for (i
= 3; i
< swd
.bbl
; ++i
) if (*p1
++ != *p2
++) break;
216 if (i
<= swd
.swd_mlf
) continue;
218 if ((swd
.swd_mlf
= i
) == swd
.bbl || swd
.best
[ptr
] < i
) break;
219 ref_
= swd
.b
[swd
.bbf
+swd
.swd_mlf
-1];
222 swd
.best
[swd
.bbf
] = swd
.swd_mlf
;
223 if (swd
.swd_mlf
> start_len
) {
224 if (swd
.swd_bpos
< swd
.bbf
) {
225 swd
.swd_bpos
= cast(ushort)(swd
.bbf
-swd
.swd_bpos
-1);
227 swd
.swd_bpos
= cast(ushort)(MAXDLEN
-1-swd
.swd_bpos
+swd
.bbf
);
231 if (swd
.binb
== POSCODES
) --swd
.ccnt
[mixin(HASH
!"swd.inptr")]; else ++swd
.binb
;
232 if (++swd
.bbf
== MAXDLEN
) swd
.bbf
= 0;
233 if ((ch
= get_byte(swd
.io
)) < 0) {
235 if (++swd
.inptr
== MAXDLEN
) swd
.inptr
= 0;
238 if (swd
.inptr
< MAXFLEN
-1) {
239 swd
.b
[swd
.inptr
+MAXDLEN
] = swd
.b
[swd
.inptr
] = cast(ubyte)ch
;
242 swd
.b
[swd
.inptr
] = cast(ubyte)ch
;
243 if (++swd
.inptr
== MAXDLEN
) swd
.inptr
= 0;
248 // ////////////////////////////////////////////////////////////////////////// //
257 // ////////////////////////////////////////////////////////////////////////// //
259 enum putbit(string b
) = "{
261 if ("~b
~") ari.ppat |= 1;
262 if (ari.ppat&0x100) {
263 put_byte(ari.io, ari.ppat&0xff);
269 // ////////////////////////////////////////////////////////////////////////// //
270 // Arithmetic encoding
271 void ac_out (ari_t
*ari
, ushort low
, ushort high
, ushort tot
) {
273 if (tot
== 0) throw new Exception("data error");
274 r
= cast(uint)(ari
.h
-ari
.l
)+1;
275 ari
.h
= cast(ushort)(cast(ushort)(r
*high
/tot
-1)+ari
.l
);
276 ari
.l
+= cast(ushort)(r
*low
/tot
);
277 if (!((ari
.h^ari
.l
)&0x8000)) {
278 mixin(putbit
!"ari.l&0x8000");
281 mixin(putbit
!"~ari.l&0x8000");
286 while (!((ari
.h^ari
.l
)&0x8000)) {
287 mixin(putbit
!"ari.l&0x8000");
293 while ((ari
.l
&0x4000) && !(ari
.h
&0x4000)) {
303 void ac_init_encode (ari_t
*ari
) {
310 void ac_end_encode (ari_t
*ari
) {
312 mixin(putbit
!"ari.l&0x4000");
314 mixin(putbit
!"~ari.l&0x4000");
320 while (!(ari
.ppat
&0x100)) ari
.ppat
<<= 1;
321 put_byte(ari
.io
, ari
.ppat
&0xff);
326 // ////////////////////////////////////////////////////////////////////////// //
327 enum BUFIN_SIZE
= 1024;
328 enum BUFOUT_SIZE
= 1024;
332 ushort[2*LTCODES
] ltab
;
333 ushort[2*LTCODES
] eltab
;
334 ushort[2*PTCODES
] ptab
;
335 ushort[2*CTCODES
] ctab
;
336 ushort[2*CTCODES
] ectab
;
337 ushort[2][TTORD
] ttab
;
338 ushort accnt
, pmax
, npt
;
345 ubyte[BUFIN_SIZE
] bufin
;
346 ubyte[BUFOUT_SIZE
] bufout
;
349 ushort fldOmlf
, fldObpos
;
350 int phase
; // 0: not initialized; 1: in progress; <0: error
352 version(oldpack_sizes
) pragma(msg
, libha_s
.sizeof
); // ~200 KB, wow!
355 void setup_buffers (libha_t asc
) {
356 asc
.io
.bufin
= asc
.bufin
.ptr
;
357 asc
.io
.bufin_size
= asc
.bufin
.sizeof
;
358 asc
.io
.bufin_pos
= 0;
359 asc
.io
.bufin_max
= 0;
360 asc
.io
.bufout
= asc
.bufout
.ptr
;
361 asc
.io
.bufout_size
= asc
.bufout
.sizeof
;
362 asc
.io
.bufout_pos
= 0;
366 void tabinit (ushort[] t
, ushort tl
, ushort ival
) {
368 for (i
= tl
; i
< 2*tl
; ++i
) t
[i
] = ival
;
369 for (i
= tl
-1, j
= (tl
<<1)-2; i
; --i
, j
-= 2) t
[i
] = cast(ushort)(t
[j
]+t
[j
+1]);
373 void tscale (ushort[] t
, ushort tl
) {
375 for (i
= (tl
<<1)-1; i
>= tl
; --i
) if (t
[i
] > 1) t
[i
] >>= 1;
376 for (i
= tl
-1, j
= (tl
<<1)-2; i
; --i
, j
-= 2) t
[i
] = cast(ushort)(t
[j
]+t
[j
+1]);
380 void tupd (ushort[] t
, ushort tl
, ushort maxt
, ushort step
, ushort p
) {
382 for (i
= p
+tl
; i
; i
>>= 1) t
[i
] += step
;
383 if (t
[1] >= maxt
) tscale(t
, tl
);
387 void tzero (ushort[] t
, ushort tl
, ushort p
) {
390 for (i
= p
+tl
, step
= t
[i
]; i
; i
>>= 1) t
[i
] -= step
;
394 void model_init (libha_t asc
) {
400 asc
.npt
= asc
.pmax
= 1;
401 for (i
= 0; i
< TTORD
; ++i
) asc
.ttab
[i
][0] = asc
.ttab
[i
][1] = TTSTEP
;
402 tabinit(asc
.ltab
, LTCODES
, 0);
403 tabinit(asc
.eltab
, LTCODES
, 1);
404 tabinit(asc
.ctab
, CTCODES
, 0);
405 tabinit(asc
.ectab
, CTCODES
, 1);
406 tabinit(asc
.ptab
, PTCODES
, 0);
407 tupd(asc
.ptab
, PTCODES
, MAXPT
, PTSTEP
, 0);
411 void pack_init (libha_t asc
) {
413 ac_init_encode(&asc
.ari
);
417 void ttscale (libha_t asc
, ushort con
) {
418 asc
.ttab
[con
][0] >>= 1;
419 if (asc
.ttab
[con
][0] == 0) asc
.ttab
[con
][0] = 1;
420 asc
.ttab
[con
][1] >>= 1;
421 if (asc
.ttab
[con
][1] == 0) asc
.ttab
[con
][1] = 1;
425 void codepair (libha_t asc
, short l
, short p
) {
426 ushort i
, j
, lt
, k
, cf
, tot
;
427 i
= cast(ushort)(asc
.ttab
[asc
.ttcon
][0]+asc
.ttab
[asc
.ttcon
][1]);
428 ac_out(&asc
.ari
, asc
.ttab
[asc
.ttcon
][0], i
, cast(ushort)(i
+1)); // writes
429 asc
.ttab
[asc
.ttcon
][1] += TTSTEP
;
430 if (i
>= MAXTT
) ttscale(asc
, asc
.ttcon
);
431 asc
.ttcon
= ((asc
.ttcon
<<1)|
1)&TTOMASK
;
432 while (asc
.accnt
> asc
.pmax
) {
433 tupd(asc
.ptab
, PTCODES
, MAXPT
, PTSTEP
, asc
.npt
++);
436 for (i
= p
, j
= 0; i
; ++j
, i
>>= 1) {}
437 cf
= asc
.ptab
[PTCODES
+j
];
439 for (lt
= 0, i
= cast(ushort)(PTCODES
+j
); i
; i
>>= 1) {
440 if (i
&1) lt
+= asc
.ptab
[i
-1];
441 asc
.ptab
[i
] += PTSTEP
;
443 if (asc
.ptab
[1] >= MAXPT
) tscale(asc
.ptab
, PTCODES
);
444 ac_out(&asc
.ari
, lt
, cast(ushort)(lt
+cf
), tot
); // writes
446 for (i
= 0x8000U
; !(p
&i
); i
>>= 1) {}
448 if (i
!= (asc
.pmax
>>1)) {
449 ac_out(&asc
.ari
, j
, cast(ushort)(j
+1), i
); // writes
451 ac_out(&asc
.ari
, j
, cast(ushort)(j
+1), cast(ushort)(asc
.accnt
-(asc
.pmax
>>1))); // writes
454 i
= cast(ushort)(l
-MINLEN
);
455 if (i
== LENCODES
-1) {
456 i
= SLCODES
-1, j
= 0xffff;
457 } else if (i
< SLCODES
-1) {
460 j
= (i
-SLCODES
+1)&LLMASK
;
461 i
= ((i
-SLCODES
+1)>>LLBITS
)+SLCODES
;
463 if ((cf
= asc
.ltab
[LTCODES
+i
]) == 0) {
464 ac_out(&asc
.ari
, asc
.ltab
[1], cast(ushort)(asc
.ltab
[1]+asc
.les), cast(ushort)(asc
.ltab
[1]+asc
.les)); // writes
465 for (lt
= 0, k
= cast(ushort)(LTCODES
+i
); k
; k
>>= 1) {
466 if (k
&1) lt
+= asc
.eltab
[k
-1];
467 asc
.ltab
[k
] += LTSTEP
;
469 if (asc
.ltab
[1] >= MAXLT
) tscale(asc
.ltab
, LTCODES
);
470 ac_out(&asc
.ari
, lt
, cast(ushort)(lt
+asc
.eltab
[LTCODES
+i
]), asc
.eltab
[1]); // writes
471 tzero(asc
.eltab
, LTCODES
, i
);
472 if (asc
.eltab
[1] != 0) asc
.les += LTSTEP
; else asc
.les = 0;
473 for (k
= cast(ushort)(i
<= LPLEN ?
0 : i
-LPLEN
); k
< (i
+LPLEN
>= LTCODES
-1 ? LTCODES
-1 : i
+LPLEN
); ++k
) {
474 if (asc
.eltab
[LTCODES
+k
]) tupd(asc
.eltab
, LTCODES
, MAXLT
, 1, k
);
477 tot
= cast(ushort)(asc
.ltab
[1]+asc
.les);
478 for (lt
= 0, k
= cast(ushort)(LTCODES
+i
); k
; k
>>= 1) {
479 if (k
&1) lt
+= asc
.ltab
[k
-1];
480 asc
.ltab
[k
] += LTSTEP
;
482 if (asc
.ltab
[1] >= MAXLT
) tscale(asc
.ltab
, LTCODES
);
483 ac_out(&asc
.ari
, lt
, cast(ushort)(lt
+cf
), tot
); // writes
485 if (asc
.ltab
[LTCODES
+i
] == LCUTOFF
) asc
.les -= (LTSTEP
< asc
.les ? LTSTEP
: asc
.les-1);
486 if (j
!= 0xffff) ac_out(&asc
.ari
, j
, cast(ushort)(j
+1), LLLEN
); // writes
487 if (asc
.accnt
< POSCODES
) {
489 if (asc
.accnt
> POSCODES
) asc
.accnt
= POSCODES
;
494 void codechar (libha_t asc
, short c
) {
495 ushort i
, lt
, tot
, cf
;
496 i
= cast(ushort)(asc
.ttab
[asc
.ttcon
][0]+asc
.ttab
[asc
.ttcon
][1]);
497 ac_out(&asc
.ari
, 0, asc
.ttab
[asc
.ttcon
][0], cast(ushort)(i
+1)); // writes
498 asc
.ttab
[asc
.ttcon
][0] += TTSTEP
;
499 if (i
>= MAXTT
) ttscale(asc
, asc
.ttcon
);
500 asc
.ttcon
= (asc
.ttcon
<<1)&TTOMASK
;
501 if ((cf
= asc
.ctab
[CTCODES
+c
]) == 0) {
502 ac_out(&asc
.ari
, asc
.ctab
[1], cast(ushort)(asc
.ctab
[1]+asc
.ces
), cast(ushort)(asc
.ctab
[1]+asc
.ces
)); // writes
503 for (lt
= 0, i
= cast(ushort)(CTCODES
+c
); i
; i
>>= 1) {
504 if (i
&1) lt
+= asc
.ectab
[i
-1];
505 asc
.ctab
[i
] += CTSTEP
;
507 if (asc
.ctab
[1] >= MAXCT
) tscale(asc
.ctab
, CTCODES
);
508 ac_out(&asc
.ari
, lt
, cast(ushort)(lt
+asc
.ectab
[CTCODES
+c
]), asc
.ectab
[1]); // writes
509 tzero(asc
.ectab
, CTCODES
, c
);
510 if (asc
.ectab
[1] != 0) asc
.ces
+= CTSTEP
; else asc
.ces
= 0;
511 for (i
= cast(ushort)(c
<= CPLEN ?
0 : c
-CPLEN
); i
< (c
+CPLEN
>= CTCODES
-1 ? CTCODES
-1 : c
+CPLEN
); ++i
) {
512 if (asc
.ectab
[CTCODES
+i
]) tupd(asc
.ectab
, CTCODES
, MAXCT
, 1, i
);
515 tot
= cast(ushort)(asc
.ctab
[1]+asc
.ces
);
516 for (lt
= 0, i
= cast(ushort)(CTCODES
+c
); i
; i
>>= 1) {
517 if (i
&1) lt
+= asc
.ctab
[i
-1];
518 asc
.ctab
[i
] += CTSTEP
;
520 if (asc
.ctab
[1] >= MAXCT
) tscale(asc
.ctab
, CTCODES
);
521 ac_out(&asc
.ari
, lt
, cast(ushort)(lt
+cf
), tot
); // writes
523 if (asc
.ctab
[CTCODES
+c
] == CCUTOFF
) asc
.ces
-= (CTSTEP
< asc
.ces ? CTSTEP
: asc
.ces
-1);
524 if (asc
.accnt
< POSCODES
) ++asc
.accnt
;
528 // ////////////////////////////////////////////////////////////////////////// //
529 public libha_t
libha_create () {
530 import core
.stdc
.stdlib
: calloc
;
531 return cast(libha_t
)calloc(1, libha_s
.sizeof
);
535 public void libha_free (libha_t asc
) {
536 import core
.stdc
.stdlib
: free
;
537 if (asc
!= null) free(asc
);
541 public void libha_reset (libha_t asc
) {
543 import core
.stdc
.string
: memset
;
544 memset(asc
, 0, (*asc
).sizeof
);
549 // return `false` when finished, or `true` if packer needs more steps
550 public bool libha_pack_step (libha_t asc
, libha_read_fn rd
, libha_write_fn wr
) {
551 //swd_findbest(): reads
552 if (asc
is null || asc
.phase
< 0 || rd
is null || wr
is null) throw new Exception("hapack error");
555 asc
.swd
.io
= asc
.ari
.io
= &asc
.io
;
558 asc
.io
.bwrite
= null;
559 asc
.swd
.io
= asc
.ari
.io
= null;
562 if (asc
.phase
== 0) {
563 asc
.phase
= -1; // so throw will end up in error
566 swd_first_bytes(&asc
.swd
); // reads MAXFLEN bytes
568 swd_findbest(&asc
.swd
);
571 assert(asc
.phase
== 1);
572 if (asc
.swd
.swd_char
< 0) {
574 asc
.phase
= -1; // so next call will end up in error
575 ac_out(&asc
.ari
, cast(ushort)(asc
.ttab
[asc
.ttcon
][0]+asc
.ttab
[asc
.ttcon
][1]), cast(ushort)(asc
.ttab
[asc
.ttcon
][0]+asc
.ttab
[asc
.ttcon
][1]+1), cast(ushort)(asc
.ttab
[asc
.ttcon
][0]+asc
.ttab
[asc
.ttcon
][1]+1));
576 ac_end_encode(&asc
.ari
);
579 if (asc
.swd
.swd_mlf
> MINLEN ||
(asc
.swd
.swd_mlf
== MINLEN
&& asc
.swd
.swd_bpos
< MINLENLIM
)) {
580 asc
.fldOmlf
= asc
.swd
.swd_mlf
;
581 asc
.fldObpos
= asc
.swd
.swd_bpos
;
582 asc
.fldOc
= asc
.swd
.swd_char
;
583 swd_findbest(&asc
.swd
); // reads
584 if (asc
.swd
.swd_mlf
> asc
.fldOmlf
) {
585 codechar(asc
, asc
.fldOc
);
587 swd_accept(&asc
.swd
); // reads
588 codepair(asc
, asc
.fldOmlf
, asc
.fldObpos
);
589 swd_findbest(&asc
.swd
); // reads
592 asc
.swd
.swd_mlf
= MINLEN
-1;
593 codechar(asc
, asc
.swd
.swd_char
);
594 swd_findbest(&asc
.swd
); // reads
596 asc
.phase
= 1; // go on