-
Notifications
You must be signed in to change notification settings - Fork 105
Expand file tree
/
Copy pathArithmeticCompress.cpp
More file actions
85 lines (75 loc) · 2.41 KB
/
ArithmeticCompress.cpp
File metadata and controls
85 lines (75 loc) · 2.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
* Compression application using static arithmetic coding
*
* Usage: ArithmeticCompress InputFile OutputFile
* Then use the corresponding "ArithmeticDecompress" application to recreate the original input file.
* Note that the application uses an alphabet of 257 symbols - 256 symbols for the byte
* values and 1 symbol for the EOF marker. The compressed file format starts with a list
* of 256 symbol frequencies, and then followed by the arithmetic-coded data.
*
* Copyright (c) Project Nayuki
* MIT License. See readme file.
* https://www.nayuki.io/page/reference-arithmetic-coding
*/
#include <cstdint>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include "ArithmeticCoder.hpp"
#include "BitIoStream.hpp"
#include "FrequencyTable.hpp"
using std::uint32_t;
int main(int argc, char *argv[]) {
// Handle command line arguments
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " InputFile OutputFile" << std::endl;
return EXIT_FAILURE;
}
const char *inputFile = argv[1];
const char *outputFile = argv[2];
// Read input file once to compute symbol frequencies
std::ifstream in(inputFile, std::ios::binary);
SimpleFrequencyTable freqs(std::vector<uint32_t>(257, 0));
freqs.increment(256); // EOF symbol gets a frequency of 1
while (true) {
int b = in.get();
if (b == std::char_traits<char>::eof())
break;
if (b < 0 || b > 255)
throw std::logic_error("Assertion error");
freqs.increment(static_cast<uint32_t>(b));
}
// Read input file again, compress with arithmetic coding, and write output file
in.clear();
in.seekg(0);
std::ofstream out(outputFile, std::ios::binary);
BitOutputStream bout(out);
try {
// Write frequency table
for (uint32_t i = 0; i < 256; i++) {
uint32_t freq = freqs.get(i);
for (int j = 31; j >= 0; j--)
bout.write(static_cast<int>((freq >> j) & 1)); // Big endian
}
ArithmeticEncoder enc(32, bout);
while (true) {
// Read and encode one byte
int symbol = in.get();
if (symbol == std::char_traits<char>::eof())
break;
if (!(0 <= symbol && symbol <= 255))
throw std::logic_error("Assertion error");
enc.write(freqs, static_cast<uint32_t>(symbol));
}
enc.write(freqs, 256); // EOF
enc.finish(); // Flush remaining code bits
bout.finish();
return EXIT_SUCCESS;
} catch (const char *msg) {
std::cerr << msg << std::endl;
return EXIT_FAILURE;
}
}