freearc/clibs/Compression/REP/C_REP.cpp

176 lines
6.9 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extern "C" {
#include "C_REP.h"
}
#define REP_LIBRARY
#include "rep.cpp"
/*-------------------------------------------------*/
/* Реализация класса REP_METHOD */
/*-------------------------------------------------*/
// Конструктор, присваивающий параметрам метода сжатия значения по умолчанию
REP_METHOD::REP_METHOD() {
BlockSize = 64 * mb;
MinCompression = 100;
ChunkSize = 0;
MinMatchLen = 512;
HashSizeLog = 0;
Barrier = INT_MAX;
SmallestLen = 512;
Amplifier = 1;
}
// Функция распаковки
int REP_METHOD::decompress(CALLBACK_FUNC *callback, void *auxdata) {
// Use faster function from DLL if possible
static FARPROC f = LoadFromDLL("rep_decompress");
if (!f)
f = (FARPROC)rep_decompress;
return ((int(__cdecl *)(MemSize, int, int, int, int, int, int, int,
CALLBACK_FUNC *, void *))f)(
BlockSize, MinCompression, ChunkSize, MinMatchLen, Barrier, SmallestLen,
HashSizeLog, Amplifier, callback, auxdata);
}
#ifndef FREEARC_DECOMPRESS_ONLY
// Функция упаковки
int REP_METHOD::compress(CALLBACK_FUNC *callback, void *auxdata) {
// Use faster function from DLL if possible
static FARPROC f = LoadFromDLL("rep_compress");
if (!f)
f = (FARPROC)rep_compress;
return ((int(__cdecl *)(MemSize, int, int, int, int, int, int, int,
CALLBACK_FUNC *, void *))f)(
BlockSize, MinCompression, ChunkSize, MinMatchLen, Barrier, SmallestLen,
HashSizeLog, Amplifier, callback, auxdata);
}
// Посчитать, сколько памяти требуется для упаковки заданным методом
MemSize REP_METHOD::GetCompressionMem(void) {
int L; // Размер блоков, КС которых заносится в хеш
int HashSize = CalcHashSize(HashSizeLog, BlockSize, SmallestLen, MinMatchLen,
ChunkSize, Amplifier, &L);
return BlockSize + HashSize * sizeof(int);
}
// Modifies compression method to use specified amount of memory
void REP_METHOD::SetCompressionMem(MemSize mem) {
if (mem > 0) {
int L; // Размер блоков, КС которых заносится в хеш
int HashSize = CalcHashSize(HashSizeLog, mem / 5 * 4, SmallestLen,
MinMatchLen, ChunkSize, Amplifier, &L);
BlockSize = mem - HashSize * sizeof(int);
}
}
#endif // !defined (FREEARC_DECOMPRESS_ONLY)
// Записать в buf[MAX_METHOD_STRLEN] строку, описывающую метод сжатия и его
// параметры (функция, обратная к parse_REP)
void REP_METHOD::ShowCompressionMethod(char *buf, bool purify) {
REP_METHOD defaults;
char BlockSizeStr[100], MinCompressionStr[100], BarrierTempStr[100],
BarrierStr[100], SmallestLenStr[100], HashSizeLogStr[100],
AmplifierStr[100], ChunkSizeStr[100], MinMatchLenStr[100];
showMem(BlockSize, BlockSizeStr);
showMem(Barrier, BarrierTempStr);
sprintf(MinCompressionStr,
MinCompression != defaults.MinCompression ? ":%d%%" : "",
MinCompression);
sprintf(MinMatchLenStr, MinMatchLen != defaults.MinMatchLen ? ":%d" : "",
MinMatchLen);
sprintf(ChunkSizeStr, ChunkSize != defaults.ChunkSize ? ":c%d" : "",
ChunkSize);
sprintf(BarrierStr, Barrier != defaults.Barrier ? ":d%s" : "",
BarrierTempStr);
sprintf(SmallestLenStr, SmallestLen != defaults.SmallestLen ? ":s%d" : "",
SmallestLen);
sprintf(AmplifierStr, Amplifier != defaults.Amplifier ? ":a%d" : "",
Amplifier);
sprintf(HashSizeLogStr, HashSizeLog != defaults.HashSizeLog ? ":h%d" : "",
HashSizeLog);
sprintf(buf, "rep:%s%s%s%s%s%s%s%s", BlockSizeStr, MinCompressionStr,
MinMatchLenStr, purify ? "" : ChunkSizeStr, BarrierStr,
SmallestLenStr, HashSizeLogStr, AmplifierStr);
}
// Конструирует объект типа REP_METHOD с заданными параметрами упаковки
// или возвращает NULL, если это другой метод сжатия или допущена ошибка в
// параметрах
COMPRESSION_METHOD *parse_REP(char **parameters) {
if (strcmp(parameters[0], "rep") == 0) {
// Если название метода (нулевой параметр) - "rep", то разберём остальные
// параметры
REP_METHOD *p = new REP_METHOD;
int error = 0; // Признак того, что при разборе параметров произошла ошибка
// Переберём все параметры метода (или выйдем раньше при возникновении
// ошибки при разборе очередного параметра)
while (*++parameters && !error) {
char *param = *parameters;
if (strequ(param, "max")) {
p->Amplifier = 99;
continue;
}
switch (*param) { // Параметры, содержащие значения
case 'b':
p->BlockSize = parseMem(param + 1, &error);
continue;
case 'l':
p->MinMatchLen = parseInt(param + 1, &error);
continue;
case 'c':
p->ChunkSize = parseInt(param + 1, &error);
continue;
case 'd':
p->Barrier = parseMem(param + 1, &error);
continue;
case 's':
p->SmallestLen = parseInt(param + 1, &error);
continue;
case 'h':
p->HashSizeLog = parseInt(param + 1, &error);
continue;
case 'a':
p->Amplifier = parseInt(param + 1, &error);
continue;
}
// Если параметр заканчивается знаком процента. то попробуем распарсить
// его как "N%"
if (last_char(param) == '%') {
char str[100];
strcpy(str, param);
last_char(str) = '\0';
int n = parseInt(str, &error);
if (!error) {
p->MinCompression = n;
continue;
}
error = 0;
}
// Сюда мы попадаем, если в параметре не указано его название
// Если этот параметр удастся разобрать как целое число (т.е. в нём -
// только цифры), то присвоим его значение полю MinMatchLen, иначе
// попробуем разобрать его как BlockSize
int n = parseInt(param, &error);
if (!error)
p->MinMatchLen = n;
else
error = 0, p->BlockSize = parseMem(param, &error);
}
if (error) {
delete p;
return NULL;
} // Ошибка при парсинге параметров метода
return p;
} else
return NULL; // Это не метод REP
}
static int REP_x =
AddCompressionMethod(parse_REP); // Зарегистрируем парсер метода REP