#include #include 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 \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; }