gates_of_skeldal/VIDEO/LZW.C
2025-01-24 18:27:22 +01:00

225 lines
4.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
#include <memman.h>
#define LZW_MAX_CODES 4096
typedef struct double_s
{
short group,chr,first,next;
}DOUBLE_S;
typedef DOUBLE_S CODE_TABLE[LZW_MAX_CODES];
DOUBLE_S *compress_dic;
int clear_code;
int end_code;
int free_code;
int nextgroup;
int bitsize,init_bitsize;
char old_value=0;
void do_clear_code()
{
int i;
old_value=0;
nextgroup=free_code;
bitsize=init_bitsize;
for(i=0;i<clear_code;i++)
{
DOUBLE_S *p;
p=&compress_dic[i];
p->group=i;p->chr=-1;p->next=-1;p->first=-1;
}
}
void reinit_lzw()
{
do_clear_code();
}
void init_lzw_compressor(int dic_size)
{
compress_dic=(CODE_TABLE *)getmem(sizeof(CODE_TABLE));
clear_code=1<<dic_size;
end_code=clear_code+1;
free_code=end_code+1;
nextgroup=free_code;
init_bitsize=bitsize=dic_size+1;
do_clear_code();
}
void done_lzw_compressor()
{
free(compress_dic);
}
long output_code(void *target,long bitepos,int bitsize,int data);
#pragma aux output_code parm [edi][edx][ebx][eax]=\
"mov ecx,edx"\
"shr ecx,3"\
"add edi,ecx"\
"mov ecx,edx"\
"and cl,7h"\
"shl eax,cl"\
"or [edi],eax"\
"add edx,ebx"\
value[edx] modify [ecx];
int input_code(void *source,long *bitepos,int bitsize,int mask);
#pragma aux input_code parm [esi][edi][ebx][edx]=\
"mov ecx,[edi]"\
"mov eax,ecx"\
"shr eax,3"\
"mov eax,[esi+eax]"\
"and cl,7"\
"shr eax,cl"\
"and eax,edx"\
"add [edi],ebx"\
value[eax] modify [ecx];
int find_code(DOUBLE_S *p)
{
int ps;
ps=p->group;
ps=compress_dic[ps].first;
while (ps!=-1)
{
if (compress_dic[ps].chr==p->chr) return ps;
ps=compress_dic[ps].next;
}
return -1;
}
void add_code(DOUBLE_S *p)
{
p->first=-1;p->next=compress_dic[p->group].first;
memcpy(&compress_dic[nextgroup],p,sizeof(DOUBLE_S));
compress_dic[p->group].first=nextgroup;
nextgroup++;
}
long lzw_encode(char *source,void *target,int size)
{
long bitpos=0;
DOUBLE_S p;
int f;
clear:
old_value=p.group=*source++;size--;
while (size-->0)
{
p.chr=(int)((char)(*source++-old_value));old_value+=p.chr;
f=find_code(&p);
if (f<0)
{
bitpos=output_code(target,bitpos,bitsize,p.group);
add_code(&p);
if (nextgroup==(1<<bitsize)) bitsize++;
p.group=p.chr;
if (nextgroup>=LZW_MAX_CODES)
{
bitpos=output_code(target,bitpos,bitsize,p.group);
bitpos=output_code(target,bitpos,bitsize,clear_code);
do_clear_code();
goto clear;
}
}
else
p.group=f;
}
bitpos=output_code(target,bitpos,bitsize,p.group);
bitpos=output_code(target,bitpos,bitsize,end_code);
return (bitpos+8)>>3;
}
void de_add_code(DOUBLE_S *p,int *mask)
{
DOUBLE_S *q;
q=&compress_dic[nextgroup];q->group=p->group;q->chr=p->chr;q->first=compress_dic[p->group].first+1;
nextgroup++;
if (nextgroup==*mask)
{
*mask=(*mask<<1)+1;
bitsize++;
}
}
int expand_code(int code,char **target)
{
static int first;
if (code>end_code)
{
expand_code(compress_dic[code].group,target);
**target=old_value=compress_dic[code].chr+old_value;
(*target)++;
}
else
{
**target=old_value=code+old_value;
(*target)++;
first=code;
}
return first;
}
char fast_expand_code(int code,char **target);
#pragma aux fast_expand_code parm[eax][edi] modify [esi ecx] value [bl]
void lzw_decode(void *source,char *target)
{
long bitpos=0;
int code,old,i;
DOUBLE_S p;
int old_first;
int mask=0xff;
for(i=0;i<LZW_MAX_CODES;i++) compress_dic[i].first=0;
clear:
old_value=0;
nextgroup=free_code;
bitsize=init_bitsize;
mask=(1<<bitsize)-1;
code=input_code(source,&bitpos,bitsize,mask);
old_first=fast_expand_code(code,&target);
old=code;
while ((code=input_code(source,&bitpos,bitsize,mask))!=end_code)
{
if (code==clear_code)
{
goto clear;
}
else if (code<nextgroup)
{
old_first=fast_expand_code(code,&target);
p.group=old;
p.chr=old_first;
de_add_code(&p,&mask);
old=code;
}
else
{
p.group=old;
p.chr=old_first;
de_add_code(&p,&mask);
old_first=fast_expand_code(code,&target);
old=code;
}
}
}