//The context compressor, author M.Smirnov. //The source also can be found at //http://compression.graphicon.ru/ //usage: //c infile outfile //encoding //d infile outfile //decoding #include #include #include class DFile { FILE *f; public: int ReadSymbol (void) { return getc(f); }; int WriteSymbol (int c) { return putc(c, f); }; FILE* GetFile (void) { return f; } void SetFile (FILE *file) { f = file; } } DataFile, CompressedFile; typedef unsigned int uint; #define DO(n) for (int _=0; _>24)!=0xFF ) { putc ( Cache + (low>>32), f ); int c = 0xFF+(low>>32); while ( FFNum ) putc(c, f), FFNum--; Cache = uint(low)>>24; } else FFNum++; low = uint(low)<<8; } uint get_freq (uint totFreq) { return code / (range/= totFreq); } void decode_update (uint cumFreq, uint freq, uint totFreq) { code -= cumFreq*range; range *= freq; while( rangecount[c]) { int CumFreqUnder = 0; for (int i = 0; i < c; i++) CumFreqUnder += CM->count[i]; AC.encode (CumFreqUnder, CM->count[c], CM->TotFr + CM->esc); return 1; } else { if (CM->esc) { AC.encode (CM->TotFr, CM->esc, CM->TotFr + CM->esc); } return 0; } } int decode_sym (ContextModel *CM, int *c) { stack [SP++] = CM; if (!CM->esc) return 0; int cum_freq = AC.get_freq (CM->TotFr + CM->esc); if (cum_freq < CM->TotFr) { int CumFreqUnder = 0; int i = 0; for (;;) { if ( (CumFreqUnder + CM->count[i]) <= cum_freq) CumFreqUnder += CM->count[i]; else break; i++; } AC.decode_update (CumFreqUnder, CM->count[i], CM->TotFr + CM->esc); *c = i; return 1; } else { AC.decode_update (CM->TotFr, CM->esc, CM->TotFr + CM->esc); return 0; } } void rescale (ContextModel *CM) { CM->TotFr = 0; for (int i = 0; i < 256; i++) { CM->count[i] -= CM->count[i] >> 1; CM->TotFr += CM->count[i]; } } void update_model (int c) { while (SP) { SP--; if (stack[SP]->TotFr >= MAX_TotFr) rescale (stack[SP]); stack[SP]->TotFr += 1; if (!stack[SP]->count[c]) stack[SP]->esc += 1; stack[SP]->count[c] += 1; } } void encode (void){ int c, success; init_model (); AC.StartEncode (CompressedFile.GetFile()); while (( c = DataFile.ReadSymbol() ) != EOF) { success = encode_sym (&cm[context[0]], c); if (!success) encode_sym (&cm[256], c); update_model (c); context [0] = c; } AC.encode (cm[context[0]].TotFr, cm[context[0]].esc, cm[context[0]].TotFr + cm[context[0]].esc); AC.encode (cm[256].TotFr, cm[256].esc, cm[256].TotFr + cm[256].esc); AC.FinishEncode(); } void decode (void){ int c, success; init_model (); AC.StartDecode (CompressedFile.GetFile()); for (;;) { success = decode_sym (&cm[context[0]], &c); if (!success){ success = decode_sym (&cm[256], &c); if (!success) break; } update_model (c); context [0] = c; DataFile.WriteSymbol (c); } } int getFileSize(char* fileName) { FILE* f; if ((f = fopen(fileName, "rb")) == NULL) return -1; fseek(f, 0, SEEK_END); int bytes = ftell(f); fclose(f); return bytes; } void main (int argc, char* argv[]){ if (argc != 4) { printf("Context compressor, author M.Smirnov.\n"); printf("Usage for compression : c infile outfile\n"); printf("Usage for decompression: d infile outfile\n"); exit(0); } FILE *inf, *outf; if (argv[1][0] == 'c') { clock_t start_encoding = clock(); inf = fopen (argv[2], "rb"); outf = fopen (argv[3], "wb"); DataFile.SetFile (inf); CompressedFile.SetFile (outf); encode (); fclose (inf); fclose (outf); int data_size = getFileSize(argv[2]); int result_size = getFileSize(argv[3]); printf("Original size %10d bytes\n", data_size); printf("Actual encoded size %10d bytes\n\n", result_size); clock_t end_encoding = clock(); printf("Time for encoding %2.3f sec.\n", (double)(end_encoding - start_encoding)/CLOCKS_PER_SEC); double ratio = (double)result_size; ratio /= (double)data_size; printf("Compression ratio %2.3f of original size.\n\n", ratio); } else if (argv[1][0] == 'd') { int data_size = getFileSize(argv[2]); printf("Compressed file size %10d bytes\n", data_size); clock_t start_decoding = clock(); inf = fopen (argv[2], "rb"); outf = fopen (argv[3], "wb"); CompressedFile.SetFile (inf); DataFile.SetFile (outf); decode (); fclose (inf); fclose (outf); clock_t end_decoding = clock(); printf("Decompression is ended, time is %2.3f sec.\n\n", (double)(end_decoding - start_decoding)/CLOCKS_PER_SEC); } else { printf("Misformatted command.\n\n"); } }