376 lines
10 KiB
C
376 lines
10 KiB
C
#include "CMP_Pub.h"
|
|
|
|
#if defined(D_CMP_DIFF)
|
|
|
|
#include <stdio.h>
|
|
#include "CMP_CPA.h"
|
|
#include "ErmCmp.h"
|
|
#include "CMP_File.h"
|
|
|
|
/**************************************************************************/
|
|
#define D_CMP_DIFF_CODED
|
|
/**************************************************************************/
|
|
#define C_CMP_DIFF_BLOCK_FACTOR 1
|
|
#define C_CMP_DIFF_BLOCK_SIZE (C_CMP_DIFF_BLOCK_FACTOR<<3)
|
|
#define C_CMP_DIFF_NB_BLOCKS 256
|
|
/**************************************************************************/
|
|
char *CMP_DIFF_g_szCompressionName = "Differential method";
|
|
char CMP_DIFF_g_aa_cBuffer[C_CMP_DIFF_NB_BLOCKS+1][C_CMP_DIFF_BLOCK_SIZE];
|
|
unsigned char CMP_DIFF_g_ucfinish=0;
|
|
/**************************************************************************/
|
|
/*#define D_CMP_DIFF_CODE_DEBUG*/
|
|
#define C_CMP_DIFF_INIT_CODE 0x53
|
|
#define C_CMP_DIFF_INIT_CODE1 0xB9
|
|
#define C_CMP_DIFF_INIT_CODE2 ((unsigned long) C_CMP_DIFF_INIT_CODE * 0x01010101 + 0x01020304)
|
|
unsigned char CMP_DIFF_g_ucCode=C_CMP_DIFF_INIT_CODE;
|
|
unsigned char CMP_DIFF_g_ucCheckSum;
|
|
long CMP_DIFF_g_lNbCodedBytes=0;
|
|
long CMP_DIFF_g_lNbBytes=0;
|
|
|
|
#if defined(D_CMP_DIFF_CODED)
|
|
/**************************************************************************/
|
|
unsigned char CMP_DIFF_fn_ucSwapCode(unsigned char code)
|
|
{
|
|
unsigned char i,newcode=0;
|
|
|
|
for (i=0;i<8;i++)
|
|
{
|
|
newcode |= (((code >> i) & 0x1) <<(7-i));
|
|
}
|
|
return newcode;
|
|
}
|
|
/**************************************************************************/
|
|
unsigned char CMP_DIFF_fn_ucGetCheckSum(FILE *input)
|
|
{
|
|
unsigned char chksum;
|
|
fread(&chksum,sizeof(chksum),1,input);
|
|
chksum ^= C_CMP_DIFF_INIT_CODE;
|
|
#ifdef D_CMP_DIFF_CODE_DEBUG
|
|
printf("get checksum = %d\n",(int) chksum);
|
|
#endif
|
|
return chksum;
|
|
}
|
|
/**************************************************************************/
|
|
void CMP_DIFF_fn_vSetCheckSum(unsigned char chksum,FILE *output)
|
|
{
|
|
fseek(output,0L,SEEK_SET);
|
|
#ifdef D_CMP_DIFF_CODE_DEBUG
|
|
printf("set checksum = %d\n",(int) chksum);
|
|
#endif
|
|
chksum ^= C_CMP_DIFF_INIT_CODE;
|
|
fwrite(&chksum,sizeof(chksum),1,output);
|
|
}
|
|
/**************************************************************************/
|
|
long CMP_DIFF_fn_lGetSize(FILE *input)
|
|
{
|
|
long size;
|
|
fread(&size,sizeof(size),1,input);
|
|
size ^= C_CMP_DIFF_INIT_CODE2;
|
|
#ifdef D_CMP_DIFF_CODE_DEBUG
|
|
printf("get size = %ld\n",(long) size);
|
|
#endif
|
|
return size;
|
|
}
|
|
/**************************************************************************/
|
|
void CMP_DIFF_fn_vSetSize(long size,FILE *output)
|
|
{
|
|
#ifdef D_CMP_DIFF_CODE_DEBUG
|
|
printf("set size = %ld\n",(long) size);
|
|
#endif
|
|
size ^= C_CMP_DIFF_INIT_CODE2;
|
|
fwrite(&size,sizeof(size),1,output);
|
|
}
|
|
/**************************************************************************/
|
|
long CMP_DIFF_fn_lUncodedGetc(FILE *input)
|
|
{
|
|
long dummy;
|
|
|
|
if ((dummy=getc(input))!=EOF) CMP_DIFF_g_lNbBytes++;
|
|
return dummy;
|
|
}
|
|
/**************************************************************************/
|
|
long CMP_DIFF_fn_lCodedPutc(int c,FILE *output)
|
|
{
|
|
long dummy;
|
|
|
|
dummy = c ^ ((int) ( CMP_DIFF_fn_ucSwapCode(CMP_DIFF_g_ucCode++) ^ C_CMP_DIFF_INIT_CODE1 ));
|
|
CMP_DIFF_g_ucCheckSum = (unsigned char)(CMP_DIFF_g_ucCheckSum + (unsigned char)c);
|
|
CMP_DIFF_g_lNbCodedBytes++;
|
|
dummy = putc(dummy,output);
|
|
|
|
#ifdef D_CMP_DIFF_CODE_DEBUG
|
|
printf("line %04d org %03d coded written %03d checksum %03d\n",(int) CMP_DIFF_g_lNbCodedBytes,(int) c,(int) dummy,(int) CMP_DIFF_g_ucCheckSum);
|
|
#endif
|
|
|
|
return dummy;
|
|
}
|
|
/**************************************************************************/
|
|
long CMP_DIFF_fn_lCodedGetc(FILE *input)
|
|
{
|
|
int dummy;
|
|
int c;
|
|
|
|
if ((dummy=c=getc(input))!=EOF)
|
|
{
|
|
dummy = c ^ ((int) ( CMP_DIFF_fn_ucSwapCode(CMP_DIFF_g_ucCode++) ^ C_CMP_DIFF_INIT_CODE1 ));
|
|
CMP_DIFF_g_ucCheckSum = (unsigned char)(CMP_DIFF_g_ucCheckSum - (unsigned char)dummy);
|
|
CMP_DIFF_g_lNbCodedBytes++;
|
|
|
|
#ifdef D_CMP_DIFF_CODE_DEBUG
|
|
printf("line %04d read %03d decoded fin %03d checksum %03d\n",(int) CMP_DIFF_g_lNbCodedBytes,(int) c,(int) dummy,(int) CMP_DIFF_g_ucCheckSum);
|
|
#endif
|
|
}
|
|
|
|
return dummy;
|
|
}
|
|
/**************************************************************************/
|
|
long CMP_DIFF_fn_lUncodedPutc(int c,FILE *output)
|
|
{
|
|
CMP_DIFF_g_lNbBytes--;
|
|
if (CMP_DIFF_g_lNbBytes<0) CMP_DIFF_g_ucfinish=1;
|
|
return putc(c,output);
|
|
}
|
|
/**************************************************************************/
|
|
#else /* D_CMP_DIFF_CODED */
|
|
/**************************************************************************/
|
|
long CMP_DIFF_fn_lUncodedGetc(FILE *input)
|
|
{
|
|
return getc(input);
|
|
}
|
|
/**************************************************************************/
|
|
long CMP_DIFF_fn_lUncodedPutc(int c,FILE *output)
|
|
{
|
|
return putc(c,output);
|
|
}
|
|
/**************************************************************************/
|
|
long CMP_DIFF_fn_lCodedGetc(FILE *input)
|
|
{
|
|
return getc(input);
|
|
}
|
|
/**************************************************************************/
|
|
long CMP_DIFF_fn_lCodedPutc(int c,FILE *output)
|
|
{
|
|
return putc(c,output);
|
|
}
|
|
/**************************************************************************/
|
|
#endif /* D_CMP_DIFF_CODED */
|
|
/**************************************************************************/
|
|
void CMP_DIFF_fn_vInitBuffer()
|
|
{
|
|
int i,j;
|
|
|
|
for(i=0;i<C_CMP_DIFF_NB_BLOCKS;i++)
|
|
{
|
|
for (j=0;j<C_CMP_DIFF_BLOCK_SIZE;j++)
|
|
{
|
|
CMP_DIFF_g_aa_cBuffer[i][j]=(char)i;
|
|
}
|
|
}
|
|
|
|
CMP_DIFF_g_lNbCodedBytes=CMP_DIFF_g_lNbBytes=0;
|
|
CMP_DIFF_g_ucfinish=0;
|
|
CMP_DIFF_g_ucCode=C_CMP_DIFF_INIT_CODE + 4;
|
|
}
|
|
/**************************************************************************/
|
|
void CMP_DIFF_fn_vCompressFile( FILE *input, FILE *output )
|
|
{
|
|
int i,j,currentsize;
|
|
int bestblock = 0;
|
|
int bestcount,matchcount;
|
|
int changeindex = 0,bitvalue;
|
|
|
|
CMP_DIFF_fn_vInitBuffer();
|
|
|
|
#if defined(D_CMP_DIFF_CODED)
|
|
CMP_DIFF_fn_vSetCheckSum(CMP_DIFF_g_ucCheckSum=0,output);
|
|
CMP_DIFF_fn_vSetSize(CMP_DIFF_g_lNbBytes=0,output);
|
|
#endif
|
|
|
|
while(!CMP_DIFF_g_ucfinish)
|
|
{
|
|
currentsize=C_CMP_DIFF_BLOCK_SIZE;
|
|
for(j=0;j<C_CMP_DIFF_BLOCK_SIZE;j++)
|
|
{
|
|
i=CMP_DIFF_fn_lUncodedGetc(input);
|
|
if (i==EOF)
|
|
{
|
|
currentsize=j;
|
|
break;
|
|
}
|
|
CMP_DIFF_g_aa_cBuffer[C_CMP_DIFF_NB_BLOCKS][j]=(char)i;
|
|
}
|
|
|
|
if (currentsize==0)
|
|
{
|
|
CMP_DIFF_g_ucfinish=1;
|
|
}
|
|
else
|
|
{
|
|
bestcount=-1;
|
|
for(i=0;i<C_CMP_DIFF_NB_BLOCKS;i++)
|
|
{
|
|
matchcount=0;
|
|
for(j=0;j<currentsize;j++)
|
|
{
|
|
if (CMP_DIFF_g_aa_cBuffer[i][j]==CMP_DIFF_g_aa_cBuffer[C_CMP_DIFF_NB_BLOCKS][j])
|
|
{
|
|
matchcount++;
|
|
}
|
|
}
|
|
|
|
if (matchcount>bestcount)
|
|
{
|
|
bestcount=matchcount;
|
|
bestblock=i;
|
|
if (bestcount==currentsize)
|
|
break;
|
|
}
|
|
}
|
|
|
|
CMP_DIFF_fn_lCodedPutc(bestblock,output);
|
|
|
|
for (i=0;i<C_CMP_DIFF_BLOCK_FACTOR;i++)
|
|
{
|
|
changeindex=0;
|
|
bitvalue=1;
|
|
for (j=i*8;j<i*8+8;j++)
|
|
{
|
|
if (j>=currentsize)
|
|
break;
|
|
|
|
if (CMP_DIFF_g_aa_cBuffer[bestblock][j] != CMP_DIFF_g_aa_cBuffer[C_CMP_DIFF_NB_BLOCKS][j])
|
|
{
|
|
changeindex += bitvalue;
|
|
}
|
|
bitvalue *= 2;
|
|
}
|
|
|
|
CMP_DIFF_fn_lCodedPutc(changeindex,output);
|
|
|
|
for (j=i*8;j<i*8+8;j++)
|
|
{
|
|
if (changeindex % 2 == 1)
|
|
{
|
|
CMP_DIFF_fn_lCodedPutc(CMP_DIFF_g_aa_cBuffer[C_CMP_DIFF_NB_BLOCKS][j],output);
|
|
}
|
|
changeindex /= 2;
|
|
}
|
|
|
|
if (currentsize<C_CMP_DIFF_BLOCK_SIZE)
|
|
{
|
|
CMP_DIFF_fn_lCodedPutc(currentsize,output);
|
|
CMP_DIFF_g_ucfinish=1;
|
|
}
|
|
else
|
|
{
|
|
for(j=0;j<C_CMP_DIFF_BLOCK_SIZE;j++)
|
|
{
|
|
CMP_DIFF_g_aa_cBuffer[bestblock][j]=CMP_DIFF_g_aa_cBuffer[C_CMP_DIFF_NB_BLOCKS][j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef D_CMP_DIFF_CODED
|
|
CMP_DIFF_fn_vSetCheckSum(CMP_DIFF_g_ucCheckSum,output);
|
|
CMP_DIFF_fn_vSetSize(CMP_DIFF_g_lNbBytes,output);
|
|
#endif
|
|
}
|
|
/**************************************************************************/
|
|
void CMP_DIFF_fn_vExpandFile( FILE *input, FILE *output )
|
|
{
|
|
int i,j;
|
|
int bestblock=-1;
|
|
int changeindex = 0;
|
|
|
|
CMP_DIFF_fn_vInitBuffer();
|
|
|
|
#ifdef D_CMP_DIFF_CODED
|
|
CMP_DIFF_g_ucCheckSum=CMP_DIFF_fn_ucGetCheckSum(input);
|
|
CMP_DIFF_g_lNbBytes=CMP_DIFF_fn_lGetSize(input);
|
|
#endif
|
|
|
|
while (!CMP_DIFF_g_ucfinish)
|
|
{
|
|
if (bestblock==-1)
|
|
{
|
|
bestblock=CMP_DIFF_fn_lCodedGetc(input);
|
|
if (bestblock==EOF)
|
|
{
|
|
CMP_DIFF_g_ucfinish=1;
|
|
}
|
|
else
|
|
{
|
|
changeindex=CMP_DIFF_fn_lCodedGetc(input);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bestblock=CMP_DIFF_fn_lCodedGetc(input);
|
|
if (bestblock==EOF)
|
|
{
|
|
for(j=0;j<C_CMP_DIFF_BLOCK_SIZE;j++)
|
|
{
|
|
CMP_DIFF_fn_lUncodedPutc(CMP_DIFF_g_aa_cBuffer[C_CMP_DIFF_NB_BLOCKS][j],output);
|
|
}
|
|
CMP_DIFF_g_ucfinish=1;
|
|
}
|
|
else
|
|
{
|
|
changeindex=CMP_DIFF_fn_lCodedGetc(input);
|
|
if (changeindex==EOF)
|
|
{
|
|
for(j=0;j<bestblock;j++)
|
|
{
|
|
CMP_DIFF_fn_lUncodedPutc(CMP_DIFF_g_aa_cBuffer[C_CMP_DIFF_NB_BLOCKS][j],output);
|
|
}
|
|
CMP_DIFF_g_ucfinish=1;
|
|
}
|
|
else
|
|
{
|
|
for(j=0;j<C_CMP_DIFF_BLOCK_SIZE;j++)
|
|
{
|
|
CMP_DIFF_fn_lUncodedPutc(CMP_DIFF_g_aa_cBuffer[C_CMP_DIFF_NB_BLOCKS][j],output);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!CMP_DIFF_g_ucfinish)
|
|
{
|
|
for (i=0;i<C_CMP_DIFF_BLOCK_FACTOR;i++)
|
|
{
|
|
if (i>0)
|
|
changeindex=CMP_DIFF_fn_lCodedGetc(input);
|
|
for(j=i*8;j<i*8+8;j++)
|
|
{
|
|
if (changeindex % 2 == 1)
|
|
{
|
|
CMP_DIFF_g_aa_cBuffer[bestblock][j]=(char)CMP_DIFF_fn_lCodedGetc(input);
|
|
}
|
|
|
|
CMP_DIFF_g_aa_cBuffer[C_CMP_DIFF_NB_BLOCKS][j]=CMP_DIFF_g_aa_cBuffer[bestblock][j];
|
|
changeindex /= 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef D_CMP_DIFF_CODED
|
|
if (CMP_DIFF_g_lNbBytes==0)
|
|
{
|
|
if (CMP_DIFF_g_ucCheckSum!=0)
|
|
M_CMPFatalError(E_uwCMPCheckSum);
|
|
}
|
|
else
|
|
{
|
|
M_CMPFatalError(E_uwCMPFileCorrupted);
|
|
}
|
|
#endif
|
|
}
|
|
/**************************************************************************/
|
|
|
|
#endif /* D_CMP_DIFF */
|