usaa24/sk1/compressor.c

141 lines
3.2 KiB
C

#include <stdio.h>
#include <stdlib.h>
#define WSIZE 250
#define BSIZE 50
typedef struct {
unsigned char pos;
unsigned char n;
char symb;
} LZ77Token;
int compress_1(const char* input_file, const char* output_file)
{
int compr_size = 0;
FILE* input = fopen(input_file, "rb");
FILE* output = fopen(output_file, "wb");
if (!input || !output)
{
exit(-1);
}
char window[WSIZE] = { 0 };
char buffer[BSIZE] = { 0 };
int w_start = 0;
int w_end = 0;
while (!feof(input))
{
int blen = fread(buffer, 1, BSIZE, input);
for (int bpos = 0; bpos < blen; ++bpos)
{
int best_pos = 0;
int best_n = 0;
for (int spos = w_start; spos < w_end; ++spos)
{
int mlength = 0;
while (mlength < blen - bpos &&
mlength < WSIZE &&
(spos + mlength) < w_end &&
window[(spos + mlength) % WSIZE] == buffer[bpos + mlength])
{
++mlength;
}
if (mlength > best_n)
{
best_pos = w_end - spos;
best_n = mlength;
}
}
LZ77Token token;
token.pos = best_pos;
token.n = best_n;
if (bpos + best_n < blen)
{
token.symb = buffer[bpos + best_n];
}
else
{
token.symb = '\0';
}
sz=fwrite(&token, sizeof(LZ77Token), 1, output);
compr_size += sizeof(LZ77Token) * sz;
for (int j = 0; j <= best_n && bpos < blen; ++j)
{
if (bpos + j < blen)
{
window[w_end % WSIZE] = buffer[bpos + j];
w_end++;
if (w_end - w_start > WSIZE)
{
w_start++;
}
}
}
bpos += best_n;
}
}
fclose(input);
fclose(output);
return compr_size;
}
int decompress_1(const char* input_file, const char* output_file)
{
int compr_size = 0, sz = 0;
FILE* input = fopen(input_file, "rb");
FILE* output = fopen(output_file, "wb");
if (!input || !output)
{
exit(-1);
}
char window[WSIZE] = { 0 };
int window_end = 0;
LZ77Token token;
while (fread(&token, sizeof(LZ77Token), 1, input))
{
if (token.pos == 0 && token.n == 0 && token.symb == '\0')
{
continue;
}
int start_index = (window_end - token.pos + WSIZE) % WSIZE;
for (int i = 0; i < token.n; ++i)
{
char ch = window[(start_index + i) % WSIZE];
compr_size += fwrite(&ch, 1, 1, output);
window[window_end % WSIZE] = ch;
window_end = (window_end + 1) % WSIZE;
}
if (token.symb != '\0')
{
compr_size += fwrite(&token.symb, 1, 1, output);
window[window_end % WSIZE] = token.symb;
window_end = (window_end + 1) % WSIZE;
}
}
fclose(input);
fclose(output);
return compr_size;
}