146 lines
3.8 KiB
C
146 lines
3.8 KiB
C
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
typedef unsigned char data_type;
|
||
|
|
||
|
struct Uncompressor {
|
||
|
unsigned char* compressedData;
|
||
|
int dataPosition;
|
||
|
int varPosition;
|
||
|
int bitForVarPosition;
|
||
|
};
|
||
|
|
||
|
data_type getByte(struct Uncompressor* uncompressor)
|
||
|
{
|
||
|
return uncompressor->compressedData[uncompressor->dataPosition++];
|
||
|
}
|
||
|
|
||
|
data_type getBit(struct Uncompressor* uncompressor)
|
||
|
{
|
||
|
if (uncompressor->bitForVarPosition == 7)
|
||
|
{
|
||
|
uncompressor->varPosition = uncompressor->dataPosition;
|
||
|
uncompressor->dataPosition = uncompressor->varPosition + 1;
|
||
|
}
|
||
|
|
||
|
data_type bit = (uncompressor->compressedData[uncompressor->varPosition] >> uncompressor->bitForVarPosition) & 1;
|
||
|
uncompressor->bitForVarPosition--;
|
||
|
|
||
|
if (uncompressor->bitForVarPosition == -1)
|
||
|
{
|
||
|
uncompressor->bitForVarPosition = 7;
|
||
|
}
|
||
|
return bit;
|
||
|
}
|
||
|
|
||
|
data_type getInterlacedEliasGamma(struct Uncompressor* uncompressor)
|
||
|
{
|
||
|
data_type value = 1;
|
||
|
while (getBit(uncompressor))
|
||
|
{
|
||
|
value = (value << 1) | getBit(uncompressor);
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
void uncompress(struct Uncompressor* uncompressor, size_t in_data_length)
|
||
|
{
|
||
|
unsigned char* output = (unsigned char*) malloc(in_data_length * 3);// * 3 is an arbitrary number...
|
||
|
size_t output_position = 0;
|
||
|
|
||
|
int q_value = (getBit(uncompressor) << 2 | getBit(uncompressor) << 1 | getBit(uncompressor)) + 1;
|
||
|
|
||
|
data_type first_byte = getByte(uncompressor);
|
||
|
output[output_position++] = first_byte;
|
||
|
|
||
|
while (uncompressor->dataPosition < in_data_length)
|
||
|
{
|
||
|
if (getBit(uncompressor))
|
||
|
{
|
||
|
data_type length = getInterlacedEliasGamma(uncompressor) + 1;
|
||
|
|
||
|
if (length == 255)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
int offset = getByte(uncompressor);
|
||
|
if (offset & 0x80)
|
||
|
{
|
||
|
offset = offset & 0x7F;
|
||
|
switch (q_value)
|
||
|
{
|
||
|
case 6:
|
||
|
offset = offset | (getBit(uncompressor) << 12);
|
||
|
case 5:
|
||
|
offset = offset | (getBit(uncompressor) << 11);
|
||
|
case 4:
|
||
|
offset = offset | (getBit(uncompressor) << 10);
|
||
|
case 3:
|
||
|
offset = offset | (getBit(uncompressor) << 9);
|
||
|
case 2:
|
||
|
offset = offset | (getBit(uncompressor) << 8);
|
||
|
offset = offset | (getBit(uncompressor) << 7);
|
||
|
case 1:
|
||
|
break;
|
||
|
default:
|
||
|
printf("Invalid mode: %d\n", q_value);
|
||
|
break;
|
||
|
}
|
||
|
offset += 128;
|
||
|
}
|
||
|
offset += 1;
|
||
|
|
||
|
for (int i = 0; i < length; i++)
|
||
|
{
|
||
|
output[output_position] = output[output_position - offset];
|
||
|
output_position += 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
output[output_position++] = getByte(uncompressor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < output_position; i++)
|
||
|
{
|
||
|
printf("%c", output[i]);
|
||
|
}
|
||
|
free(output);
|
||
|
}
|
||
|
|
||
|
int main(int argc, char* argv[])
|
||
|
{
|
||
|
if (argc < 2)
|
||
|
{
|
||
|
printf("Usage: %s <compressed file>\n", argv[0]);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
FILE* file = fopen(argv[1], "rb");
|
||
|
if (!file)
|
||
|
{
|
||
|
printf("Error reading file!\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
fseek(file, 0, SEEK_END);
|
||
|
long length = ftell(file);
|
||
|
fseek(file, 0, SEEK_SET);
|
||
|
|
||
|
unsigned char* compressedData = (unsigned char*) malloc(length);
|
||
|
if (!fread(compressedData, length, 1, file))
|
||
|
{
|
||
|
printf("Error reading file!\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
struct Uncompressor uncompressor = {compressedData, 0, 0, 7};
|
||
|
uncompress(&uncompressor, length);
|
||
|
|
||
|
free(compressedData);
|
||
|
fclose(file);
|
||
|
|
||
|
return 0;
|
||
|
}
|