forked from hxim/paq8px
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEncoder.cpp
122 lines (106 loc) · 2.76 KB
/
Encoder.cpp
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "Encoder.hpp"
Encoder::Encoder(Shared* const sh, Mode m, File *f) : shared(sh), predictor(sh), ari(f), mode(m), archive(f), alt(nullptr) {
if( mode == DECOMPRESS ) {
uint64_t start = size();
archive->setEnd();
uint64_t end = size();
if( end >= (1ULL << 31)) {
quit("Large archives not yet supported.");
}
setStatusRange(0.0, static_cast<float>(end));
archive->setpos(start);
}
if( shared->level > 0 && mode == DECOMPRESS ) { // x = first 4 bytes of archive
ari.prefetch();
}
}
auto Encoder::getMode() const -> Mode { return mode; }
auto Encoder::size() const -> uint64_t { return archive->curPos(); }
void Encoder::flush() {
if( mode == COMPRESS && shared->level > 0 ) {
ari.flush();
}
}
void Encoder::setFile(File *f) { alt = f; }
void Encoder::compressByte(uint8_t c) {
assert(mode == COMPRESS);
if( shared->level == 0 ) {
archive->putChar(c);
} else {
for( int i = 7; i >= 0; --i ) {
int p = predictor.p();
int y = (c >> i) & 1;
ari.encodeBit(p, y);
predictor.update(y);
}
}
}
auto Encoder::decompressByte() -> uint8_t {
if( mode == COMPRESS ) {
assert(alt);
return alt->getchar();
}
if( shared->level == 0 ) {
return archive->getchar();
} else {
uint8_t c = 0;
for( int i = 0; i < 8; ++i ) {
int p = predictor.p();
int y = ari.decodeBit(p);
c = c << 1 | y;
predictor.update(y);
}
return c;
}
}
void Encoder::encodeBlockSize(uint64_t blockSize) {
while( blockSize > 0x7FU ) {
compressByte(0x80 | (blockSize & 0x7FU));
blockSize >>= 7U;
}
compressByte(uint8_t(blockSize));
}
void Encoder::encodeBlockType(BlockType blocktype) {
compressByte(uint8_t(blocktype));
}
auto Encoder::decodeBlockType() -> BlockType {
uint8_t b = decompressByte();
return (BlockType)b;
}
auto Encoder::decodeBlockSize() -> uint64_t {
uint64_t blockSize = 0;
uint8_t b = 0;
int i = 0;
do {
b = decompressByte();
blockSize |= uint64_t((b & 0x7FU) << i);
i += 7;
} while((b >> 7U) > 0 );
return blockSize;
}
void Encoder::encodeInfo(int info) {
compressByte((info >> 24) & 0xFF);
compressByte((info >> 16) & 0xFF);
compressByte((info >> 8) & 0xFF);
compressByte((info) & 0xFF);
}
auto Encoder::decodeInfo() -> int {
int info = 0;
for (int j = 0; j < 4; ++j) {
info <<= 8;
info += decompressByte();
}
return info;
}
void Encoder::setStatusRange(float perc1, float perc2) {
p1 = perc1;
p2 = perc2;
}
void Encoder::printStatus(uint64_t n, uint64_t size) const {
fprintf(stderr, "%6.2f%%\b\b\b\b\b\b\b", (p1 + (p2 - p1) * n / (size + 1)) * 100);
fflush(stderr);
}
void Encoder::printStatus() const {
fprintf(stderr, "%6.2f%%\b\b\b\b\b\b\b", float(size()) / (p2 + 1) * 100);
fflush(stderr);
}