Blame |
Last modification |
View Log
| Download
| RSS feed
#include <stdio.h>
#include <stdlib.h>
#include "mhmt-types.h"
#include "mhmt-globals.h"
#include "mhmt-pack.h"
#include "mhmt-hash.h"
#include "mhmt-tb.h"
#include "mhmt-lz.h"
#include "mhmt-optimal.h"
#include "mhmt-emit.h"
// entry function to pack data
// returns zero if any error
ULONG pack
(void)
{
ULONG
(*get_lz_price
)(OFFSET position
, struct lzcode
* lzcode
) = NULL
; // generates correct bitlen (price) of code
ULONG
(*emit
)(struct optchain
* optch
, ULONG actual_len
) = NULL
; // emits lzcode to the output bit/byte stream
ULONG success
=1;
ULONG actual_len
; // actual length of packing (to account for ZX headers containing last unpacked bytes)
UBYTE
* hash
;
struct optchain
* optch
=NULL
;
static struct lzcode codes
[MAX_CODES_SIZE
]; // generate codes here; static to ensure it's not on the stack
UBYTE curr_byte
, last_byte
;
UWORD index
;
OFFSET position
;
// some preparations
//
if( wrk.
packtype==PK_MLZ
)
{
get_lz_price
= &get_lz_price_megalz
;
emit
= &emit_megalz
;
}
else if( wrk.
packtype==PK_HRM
)
{
get_lz_price
= &get_lz_price_hrum
;
emit
= &emit_hrum
;
}
else if( wrk.
packtype==PK_HST
)
{
get_lz_price
= &get_lz_price_hrust
;
emit
= &emit_hrust
;
}
else if( wrk.
packtype==PK_ZX7
)
{
get_lz_price
= &get_lz_price_zx7
;
emit
= &emit_zx7
;
}
else
{
printf("mhmt-pack.c:pack() - format unsupported!\n");
return 0;
}
actual_len
= wrk.
inlen;
if( wrk.
zxheader )
{
if( wrk.
packtype==PK_HRM
)
{
actual_len
-= 5;
}
else if( wrk.
packtype==PK_HST
)
{
actual_len
-= 6;
}
else
{
printf("mhmt-pack.c:pack() - there must be no zxheader for anything except hrust or hrum!\n");
return 0;
}
}
// initializations and preparations
init_tb
();
hash
= build_hash
(wrk.
indata, actual_len
, wrk.
prelen);
if( !hash
)
{
printf("mhmt-pack.c:pack() - build_hash() failed!\n");
success
= 0;
}
if( success
)
{
optch
= make_optch
(actual_len
);
if( !optch
)
{
printf("mhmt-pack.c:pack() - can't make optchain array!\n");
success
= 0;
}
}
// go packing!
if( success
)
{
// fill TBs with prebinary date
if( wrk.
prebin )
{
curr_byte
=wrk.
indata[0LL
-wrk.
prelen];
//
for(position
=(1LL
-wrk.
prelen);position
<=0;position
++)
{
last_byte
= curr_byte
;
curr_byte
= wrk.
indata[position
];
index
= (last_byte
<<8) + curr_byte
;
if( !add_tb
(index
,position
) )
{
printf("mhmt-pack.c:pack() - add_tb() failed!\n");
success
= 0;
goto ERROR
;
}
}
}
if( !wrk.
greedy ) // default optimal coding
{
// go generating lzcodes byte-by-byte
//
curr_byte
= wrk.
indata[0];
//
for(position
=1;position
<(OFFSET
)actual_len
;position
++)
{
last_byte
= curr_byte
;
curr_byte
= wrk.
indata[position
];
// add current two-byter to the chains
index
= (last_byte
<<8) + curr_byte
;
if( !add_tb
(index
,position
) )
{
printf("mhmt-pack.c:pack() - add_tb() failed!\n");
success
= 0;
goto ERROR
;
}
// search lzcodes for given position
make_lz_codes
(position
, actual_len
, hash
, codes
);
// update optimal chain with lzcodes
update_optch
(position
, codes
, get_lz_price
, optch
);
}
// all input bytes scanned, chain built, so now reverse it (prepare for scanning in output generation part)
reverse_optch
(optch
, actual_len
);
}
else // greedy coding
{
printf("mhmt-pack.c:pack() - greedy coding not supported!\n");
success
= 0;
}
// data built, now emit packed file
success
= success
&& (*emit
)(optch
, actual_len
);
}
ERROR
:
free_optch
(optch
);
destroy_hash
(hash
, wrk.
prelen);
return success
;
}