encode.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 949 行 · 第 1/2 页
C
949 行
int num;
byte runlen;
byte prevlen;
byte * lenptr;
num = 0;
prevlen = 0xFF;
lenptr = len;
runlen = 0;
for( index = 0; index < NUM_CHARS; index++ ) {
if( *lenptr > MAX_CODE_BITS ) {
WriteMsg( "horrible shannon code overflow\n" );
exit( 1 );
}
if( *lenptr != prevlen || (prevlen == 0 && runlen == 128)
|| (prevlen != 0 && runlen == 8)) {
prevlen = *lenptr;
num++;
runlen = 0;
}
runlen++;
lenptr++;
}
EncWriteByte( num - 1 );
codesize++;
lenptr = len;
prevlen = *lenptr;
num = 0;
for( index = 0; index < NUM_CHARS; index++ ) {
if( *lenptr != prevlen || (prevlen != 0 && num == 8)
|| (prevlen == 0 && num == 128) ) {
if( prevlen == 0 ) {
EncWriteByte( 0x80 + num - 1 );
} else {
EncWriteByte( ((num - 1) << 4) + prevlen - 1 );
}
codesize++;
prevlen = *lenptr;
num = 0;
}
lenptr++;
num++;
}
if( prevlen == 0 ) { // write out the last block
EncWriteByte( 0x80 + num - 1 );
} else {
EncWriteByte( ((num - 1) << 4) + prevlen - 1 );
}
codesize++;
}
static void DoSecondPass( bool doshannon )
/****************************************/
{
runlist * rlptr;
bool inliteral;
char * data;
int index;
int num;
unsigned c;
QSeek( RunHandle, 0, SEEK_SET );
rlptr = RunList;
while( rlptr != NULL ) {
num = MAX_COPYLIST_SIZE;
data = rlptr->data;
if( rlptr->next == NULL ) {
if( NumSpilled > 0 ) {
QRead( RunHandle, AltBuffer, MAX_COPYLIST_SIZE );
data = AltBuffer;
NumSpilled--;
} else {
num = LastRunLen;
rlptr = rlptr->next;
}
} else {
rlptr = rlptr->next;
}
while( num > 0 ) {
inliteral = !(*data & 0x80);
for( index = *data & 0x7F; index > 0; index-- ) {
c = EncReadByte();
if( inliteral ) {
if( doshannon ) {
Putcode( len[ c ], code[ c ] );
} else {
Putcode( 9, c << 7 ); /* 0 bit, then code word. */
}
} else {
if( doshannon ) {
c = 255 - THRESHOLD + c;
Putcode( len[ c ], code[ c ] );
} else {
Putcode( 7, (c + 0x40) << 9 ); /* 1, then length */
}
EncodePosition();
}
}
num--;
data++;
}
}
}
/* Compression */
static int DoEncode( arccmd *cmd )
/********************************/
{
int c, num, r, s, last_match_length;
int index;
unsigned currvalue;
unsigned * uptr;
unsigned long total;
bool inliteral;
bool doshannon;
codesize = 0;
WasLiteral = TRUE;
CurrRunLen = 0;
StartRunList();
QSeek( TmpHandle, 0, SEEK_SET );
QSeek( RunHandle, 0, SEEK_SET );
SwitchBuffer( TmpHandle, TRUE, AltBuffer );
memset( code, 0, NUM_CHARS * sizeof( unsigned ) );
InitTree();
s = 0;
r = N - F;
for (index = s; index < r; index++) {
text_buf[index] = ' ';
}
for (num = 0; num < F && (c = EncReadByte(),IOStatus == OK); num++) {
text_buf[r + num] = c;
}
if( IOStatus == IO_PROBLEM ) return( -1 );
for (index = 1; index <= F; index++) {
InsertNode(r - index);
}
InsertNode(r);
do {
if (match_length > num)
match_length = num;
if (match_length <= THRESHOLD) {
match_length = 1;
inliteral = TRUE;
currvalue = text_buf[r];
DecWriteByte( currvalue );
} else {
inliteral = FALSE;
currvalue = 255 - THRESHOLD + match_length;
DecWriteByte( match_length );
DecWriteByte( match_position >> 6 );
DecWriteByte( match_position & 0x3F );
}
WriteTmpByte( inliteral, currvalue );
last_match_length = match_length;
for (index = 0;
index < last_match_length && (c=EncReadByte(),IOStatus == OK);
index++ ) {
DeleteNode(s);
text_buf[s] = c;
if (s < F - 1)
text_buf[s + N] = c;
s = (s + 1) & (N - 1);
r = (r + 1) & (N - 1);
InsertNode(r);
}
if( IOStatus == IO_PROBLEM ) return( -1 );
while (index++ < last_match_length) {
DeleteNode(s);
s = (s + 1) & (N - 1);
r = (r + 1) & (N - 1);
if (--num) InsertNode(r);
}
} while (num > 0);
AddRunEntry();
FlushWrite();
RestoreBuffer( TRUE );
SwitchBuffer( TmpHandle, FALSE, NULL );
// now set up the compression stuff & do the second pass.
num = 0;
total = 0;
uptr = code;
for( index = 0; index < NUM_CHARS; index++ ) {
len[ index ] = 0;
if( *uptr != 0 ) {
total += *uptr;
indicies[ num ] = index;
num++;
}
uptr++;
}
QSeek( infile, 0, SEEK_SET );
CalcLengths( total, 0, num - 1, 0 );
doshannon = AssignCodes( num, cmd );
if( doshannon ) { // we have shannon codes,
WriteCodes(); // so write out file using these
}
DoSecondPass( doshannon );
EncodeEnd();
RestoreBuffer( FALSE );
FreeRunList();
return( !doshannon );
}
static void InitHeader( arc_header *header, arccmd *cmd )
/******************************************/
{
header->signature = SIGNATURE;
header->major_ver = MAJOR_VERSION;
header->minor_ver = MINOR_VERSION;
header->num_files = 0;
header->info_offset = 0;
header->info_len = 0;
if( cmd->flags & SECURE_PACK ) {
header->major_ver += cmd->internal;// so incompat. with previous vers
header->internal = cmd->internal;
}
}
static void WriteHeaders( arc_header *header, info_list *list, int numfiles,
int file )
/***************************************************************************/
{
info_list * info; // node of the info_list
int entrylen; // length of the file_info entry
while( numfiles > 0 ) { //NYI buffer this stuff.
entrylen = sizeof(file_info) + (list->i.namelen & NAMELEN_MASK) - 1;
QWrite( file, &list->i, entrylen );
header->info_len += entrylen;
info = list->next;
WPMemFree( list );
list = info;
numfiles--;
}
QSeek( file, 0L, SEEK_SET );
QWrite( file, header, sizeof( arc_header ) );
}
static void ReplaceExt( char * name, char * new_ext )
/***************************************************/
{
char p[ _MAX_DIR ];
char d[ _MAX_DRIVE ];
char n[ _MAX_FNAME ];
_splitpath( name, d, p, n, NULL );
_makepath( name, d, p, n, new_ext );
}
// this is used for keeping track of the different archives while multipacking
typedef struct arc_list {
struct arc_list * next;
info_list * info;
unsigned long length;
unsigned info_len;
int handle;
int num_files;
} arc_list;
static void MultiPack( arccmd *cmd, info_list *list )
/***************************************************/
{
arc_list * archead;
arc_list * currarc;
int numarcs;
unsigned long compressed;
unsigned long currspot;
unsigned entrylen;
unsigned long limit;
char extension[ 4 ];
char * arcfname;
info_list * nextfile;
arc_header header;
arcfname = alloca( strlen( cmd->arcname ) + 4 );
strcpy( arcfname, cmd->arcname );
limit = (unsigned long)cmd->u.limit << 10;
numarcs = 0;
archead = NULL;
QSeek( outfile, sizeof( arc_header ), SEEK_SET );
currspot = sizeof( arc_header );
while( list != NULL ) { // first get length of compressed file
entrylen = sizeof(file_info) + (list->i.namelen & NAMELEN_MASK) - 1;
nextfile = list->next;
if( nextfile == NULL ) {
compressed = QFileLen( outfile ) - currspot;
} else {
compressed = nextfile->i.disk_addr - currspot;
currspot = nextfile->i.disk_addr;
}
currarc = archead;
while( currarc != NULL ) { // find an archive to pack file in.
if( currarc->length + currarc->info_len + compressed
+ entrylen < limit ) break;
currarc = currarc->next;
}
if( currarc == NULL ) { // need to make a new archive
currarc = alloca( sizeof( arc_list ) );
if( currarc == NULL ) Error( -1, "insufficient stack space!" );
currarc->next = NULL;
currarc->info = NULL;
currarc->info_len = 0;
currarc->length = sizeof( arc_header );
currarc->num_files = 0;
numarcs++;
itoa( numarcs, extension, 36 );
ReplaceExt( arcfname, extension );
currarc->handle = QOpenW( arcfname );
if( currarc->handle < 0 ) PackExit();
QSeek( currarc->handle, sizeof( arc_header ), SEEK_SET );
LinkList( &archead, currarc );
}
currarc->num_files++; // update arc info & write data
list->i.disk_addr = currarc->length;
currarc->length += compressed;
currarc->info_len += entrylen;
LinkList( &currarc->info, list );
CopyInfo( currarc->handle, outfile, compressed );
list->next = NULL;
list = nextfile;
}
currarc = archead; // now fill in header information in archives
while( currarc != NULL ) {
InitHeader( &header, cmd );
header.num_files = currarc->num_files;
header.info_offset = currarc->length;
WriteHeaders( &header, currarc->info, currarc->num_files,
currarc->handle );
QClose( currarc->handle );
currarc = currarc->next;
}
QClose( outfile );
remove( cmd->arcname );
}
extern void Encode( arccmd *cmd )
/*******************************/
{
wpackfile * currname; // current file name being processed.
unsigned long length; // unencrypted length of the file.
unsigned long amtwrote; // amount wrote to archive files
unsigned long amtread; // amout read from all files.
char * name; // stored name of the file
char * temp;
unsigned numfiles; // number of files stored in archive
int namelen; // length of the filename
int result; // result of encoding the file.
info_list * info; // node of the info_list
info_list * liststart; // beginning of the info_list
arc_header header; // archive main header.
file_info ** filedata; // block of file infos from old archive.
char tmpfile[ L_tmpnam ]; // pass1 info temp file name;
char runfile[ L_tmpnam ]; // run length temp file name;
if( cmd->files == NULL || cmd->files->filename == NULL ) {
Error( -1, "No files to pack\n" );
}
filedata = ReadHeader( cmd, &header );
if( filedata != NULL ) { // there is an old file to add to.
QClose( infile );
if( cmd->flags & PACK_LIMIT ) {
Error( -1, "old archive already exists");
}
outfile = QOpenM( cmd->arcname );
if( outfile == -1 ) PackExit();
WriteSeek( header.info_offset );
amtwrote = header.info_offset;
} else {
outfile = QOpenW( cmd->arcname );
WriteFiller( sizeof( arc_header ) ); // reserve space for header.
amtwrote = sizeof( arc_header );
}
tmpnam( tmpfile );
TmpHandle = QOpenW( tmpfile );
tmpnam( runfile );
RunHandle = QOpenW( runfile );
if( TmpHandle < 0 || RunHandle < 0 ) {
Error( -1, "problem opening temporary files" );
}
AltBuffer = WPMemAlloc( MAX_COPYLIST_SIZE ); // must be >= WRITE_SIZE
liststart = NULL;
amtread = 0;
numfiles = 0;
for( currname = cmd->files; currname->filename != NULL; currname++ ) {
FlushRead();
if( !(cmd->flags & PRESERVE_FNAME_CASE) ) {
strlwr( currname->filename );
}
infile = QOpenR( currname->filename );
if( infile == -1 ) {
WriteMsg( "could not open file: " );
WriteMsg( currname->filename );
WriteMsg( "\n" );
} else {
numfiles++;
if( !(cmd->flags & BE_QUIET) ) {
WriteMsg( "packing file '" );
WriteMsg( currname->filename );
WriteMsg( "'\n" );
}
result = DoEncode( cmd );
if( result == -1 ) continue; // don't archive if error.
if( currname->packname != NULL ) {
name = currname->packname;
} else if( !(cmd->flags & KEEP_PATHNAME) ) { // search for actual file name
temp = currname->filename;
name = temp;
while( *temp != '\0' ) {
if( *temp == '\\' || *temp == ':' ) {
name = temp + 1;
}
temp++;
}
} else {
name = currname->filename;
}
length = QFileLen( infile );
amtread += length;
namelen = strlen( name );
info = WPMemAlloc( sizeof( info_list ) + namelen - 1);
info->i.length = length;
info->i.disk_addr = amtwrote;
amtwrote += codesize;
if( cmd->flags & USE_DATE_TIME ) {
info->i.stamp = cmd->time;
} else {
info->i.stamp = QGetDate( infile );
}
memcpy( info->i.name, name, namelen );
if( result ) {
namelen |= NO_SHANNON_CODE;
}
info->i.namelen = namelen;
info->i.crc = GetCRC();
info->next = NULL;
LinkList( &liststart, info );
QClose( infile );
} // end if
} // end for
QClose( TmpHandle );
QClose( RunHandle );
remove( tmpfile );
remove( runfile );
if( numfiles > 0 ) {
FlushWrite();
if( cmd->flags & PACK_LIMIT ) {
MultiPack( cmd, liststart );
} else { // add files to current archive
if( filedata == NULL ) {
InitHeader( &header, cmd );
} else { // write stuff in old header.
QWrite( outfile, *filedata, header.info_len );
}
header.num_files += numfiles;
header.info_offset = amtwrote;
WriteHeaders( &header, liststart, numfiles, outfile );
if( filedata == NULL ) {
amtwrote += header.info_len;
if( !(cmd->flags & BE_QUIET ) ) {
WriteNumeric( "uncompressed size: ", amtread );
WriteNumeric( "compressed size: ", amtwrote );
}
}
QClose( outfile ); // close the archive file.
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?