// This is free and unencumbered software released into the public domain. // // Anyone is free to copy, modify, publish, use, compile, sell, or // distribute this software, either in source code form or as a compiled // binary, for any purpose, commercial or non-commercial, and by any // means. #include #include #include #include #include #include #include int verbose = 0; static void push_int_bits(std::vector &outbits, int value, int bits) { while (bits-- > 0) outbits.push_back((value >> bits) & 1); } static void push_zero_bits(std::vector &outbits, int bits) { while (bits-- > 0) outbits.push_back(false); } static int decode_int_from_bits(const std::vector &inbits, int &cursor, int bits) { int ret = 0; while (bits-- > 0) if (inbits.at(cursor++)) ret |= 1 << bits; return ret; } void ice_compress(std::vector &outbits, const std::vector &inbits) { int opcode_stats_d4 = 0; int opcode_stats_d32 = 0; int opcode_stats_d256 = 0; int opcode_stats_raw = 0; int opcode_stats_d8M = 0; int opcode_stats_end = 0; std::vector deltas; int numzeros = 0; for (auto bit : inbits) { if (bit) { deltas.push_back(numzeros); numzeros = 0; } else { numzeros++; } } for (int i = 0; i < int(deltas.size()); i++) { int raw_len = 0; int compr_len = 0; int best_compr_raw_diff = -1; int best_compr_raw_idx = -1; int best_compr_raw_len = -1; for (int j = 0; j+i < int(deltas.size()); j++) { int delta = deltas.at(i + j); raw_len += delta + 1; if (delta < 4) compr_len += 3; else if (delta < 32) compr_len += 7; else if (delta < 256) compr_len += 11; else compr_len += 26; if (compr_len - raw_len < std::max(best_compr_raw_diff - 4, 0) || raw_len > 64) break; if (compr_len - raw_len > best_compr_raw_diff) { best_compr_raw_diff = compr_len - raw_len; best_compr_raw_idx = j; best_compr_raw_len = raw_len; } } if (best_compr_raw_diff > 9) { opcode_stats_raw++; outbits.push_back(false); outbits.push_back(false); outbits.push_back(false); outbits.push_back(true); push_int_bits(outbits, best_compr_raw_len-1, 6); for (int j = 0; j <= best_compr_raw_idx; j++) { int delta = deltas.at(i + j); for (int k = 0; k < delta; k++) outbits.push_back(false); if (j < best_compr_raw_idx) outbits.push_back(true); } i += best_compr_raw_idx; continue; } int delta = deltas.at(i); if (delta < 4) { opcode_stats_d4++; outbits.push_back(true); push_int_bits(outbits, delta, 2); } else if (delta < 32) { opcode_stats_d32++; outbits.push_back(false); outbits.push_back(true); push_int_bits(outbits, delta, 5); } else if (delta < 256) { opcode_stats_d256++; outbits.push_back(false); outbits.push_back(false); outbits.push_back(true); push_int_bits(outbits, delta, 8); } else { opcode_stats_d8M++; outbits.push_back(false); outbits.push_back(false); outbits.push_back(false); outbits.push_back(false); outbits.push_back(true); push_int_bits(outbits, delta, 23); } } opcode_stats_end++; outbits.push_back(false); outbits.push_back(false); outbits.push_back(false); outbits.push_back(false); outbits.push_back(false); push_int_bits(outbits, numzeros, 23); if (verbose > 1) { fprintf(stderr, "opcode d4 %5d\n", opcode_stats_d4); fprintf(stderr, "opcode d32 %5d\n", opcode_stats_d32); fprintf(stderr, "opcode d256 %5d\n", opcode_stats_d256); fprintf(stderr, "opcode raw %5d\n", opcode_stats_raw); fprintf(stderr, "opcode d8M %5d\n", opcode_stats_d8M); fprintf(stderr, "opcode end %5d\n", opcode_stats_end); } } void ice_uncompress(std::vector &outbits, const std::vector &inbits) { int cursor = 0; while (cursor < int(inbits.size())) { if (inbits.at(cursor++)) { int zeros = decode_int_from_bits(inbits, cursor, 2); push_zero_bits(outbits, zeros); outbits.push_back(true); } else if (inbits.at(cursor++)) { int zeros = decode_int_from_bits(inbits, cursor, 5); push_zero_bits(outbits, zeros); outbits.push_back(true); } else if (inbits.at(cursor++)) { int zeros = decode_int_from_bits(inbits, cursor, 8); push_zero_bits(outbits, zeros); outbits.push_back(true); } else if (inbits.at(cursor++)) { int raw_len = decode_int_from_bits(inbits, cursor, 6); while (raw_len--) outbits.push_back(inbits.at(cursor++)); outbits.push_back(true); } else if (inbits.at(cursor++)) { int zeros = decode_int_from_bits(inbits, cursor, 23); push_zero_bits(outbits, zeros); outbits.push_back(true); } else { int zeros = decode_int_from_bits(inbits, cursor, 23); push_zero_bits(outbits, zeros); } } } void help() { printf("\n"); printf("Usage: icecompr [-v] [input-file [output-file]]\n"); printf("\n"); exit(1); } int main(int argc, char **argv) { FILE *input_file = stdin; FILE *output_file = stdout; int opt; while ((opt = getopt(argc, argv, "v")) != -1) { switch (opt) { case 'v': verbose++; break; default: help(); } } if (optind < argc) { input_file = fopen(argv[optind], "rb"); if (input_file == NULL) { fprintf(stderr, "Failed to open input file `%s': %s\n", argv[optind], strerror(errno)); return 1; } optind++; } if (optind < argc) { output_file = fopen(argv[optind], "wb"); if (output_file == NULL) { fprintf(stderr, "Failed to open output file `%s': %s\n", argv[optind], strerror(errno)); return 1; } optind++; } if (optind != argc) help(); std::vector original_bits; int count_set_bits = 0; while (1) { int byte = fgetc(input_file); if (byte < 0) break; // MSB first for (int i = 7; i >= 0; i--) { bool bit = (byte >> i) & 1; if (bit) count_set_bits++; original_bits.push_back(bit); } } int uncompressed_size = original_bits.size(); if (verbose > 0) { fprintf(stderr, "Percentage of set bits: %.2f%%\n", (100.0*count_set_bits) / uncompressed_size); fprintf(stderr, "Uncompressed size: %8d bits\n", uncompressed_size); } std::vector compressed_bits; ice_compress(compressed_bits, original_bits); int compressed_size = compressed_bits.size(); if (verbose > 0) { fprintf(stderr, "Compressed size: %8d bits\n", compressed_size); fprintf(stderr, "Space savings: %.2f%%\n", 100 - (100.0*compressed_size) / uncompressed_size); } std::vector uncompressed_bits; ice_uncompress(uncompressed_bits, compressed_bits); bool check_ok = original_bits == uncompressed_bits; if (verbose > 0 || !check_ok) { fprintf(stderr, "Integrity check: %s\n", check_ok ? "OK" : "ERROR"); if (!check_ok) return 1; } fprintf(output_file, "ICECOMPR"); for (int i = 0; i < int(compressed_bits.size()); i += 8) { int value = 0; for (int j = 0; j < 8 && i+j < int(compressed_bits.size()); j++) if (compressed_bits.at(i+j)) value |= 1 << (7-j); fputc(value, output_file); } return 0; }