diff options
author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2021-12-27 00:00:00 +0000 |
---|---|---|
committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2022-03-18 15:35:13 +0500 |
commit | f19f813537c7aea1c20749c914e756b54a9c3cf5 (patch) | |
tree | 816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /C/Ppmd8Enc.c | |
parent | 98e06a519b63b81986abe76d28887f6984a7732b (diff) | |
download | 7zip-21.07.tar.gz 7zip-21.07.tar.bz2 7zip-21.07.zip |
'21.07'21.07
Diffstat (limited to 'C/Ppmd8Enc.c')
-rw-r--r-- | C/Ppmd8Enc.c | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/C/Ppmd8Enc.c b/C/Ppmd8Enc.c new file mode 100644 index 0000000..32ff805 --- /dev/null +++ b/C/Ppmd8Enc.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /* Ppmd8Enc.c -- Ppmd8 (PPMdI) Encoder | ||
2 | 2021-04-13 : Igor Pavlov : Public domain | ||
3 | This code is based on: | ||
4 | PPMd var.I (2002): Dmitry Shkarin : Public domain | ||
5 | Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ | ||
6 | |||
7 | #include "Precomp.h" | ||
8 | |||
9 | #include "Ppmd8.h" | ||
10 | |||
11 | #define kTop (1 << 24) | ||
12 | #define kBot (1 << 15) | ||
13 | |||
14 | #define WRITE_BYTE(p) IByteOut_Write(p->Stream.Out, (Byte)(p->Low >> 24)) | ||
15 | |||
16 | void Ppmd8_Flush_RangeEnc(CPpmd8 *p) | ||
17 | { | ||
18 | unsigned i; | ||
19 | for (i = 0; i < 4; i++, p->Low <<= 8 ) | ||
20 | WRITE_BYTE(p); | ||
21 | } | ||
22 | |||
23 | |||
24 | |||
25 | |||
26 | |||
27 | |||
28 | #define RC_NORM(p) \ | ||
29 | while ((p->Low ^ (p->Low + p->Range)) < kTop \ | ||
30 | || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) \ | ||
31 | { WRITE_BYTE(p); p->Range <<= 8; p->Low <<= 8; } | ||
32 | |||
33 | |||
34 | |||
35 | |||
36 | |||
37 | |||
38 | |||
39 | |||
40 | |||
41 | |||
42 | |||
43 | |||
44 | |||
45 | // we must use only one type of Normalization from two: LOCAL or REMOTE | ||
46 | #define RC_NORM_LOCAL(p) // RC_NORM(p) | ||
47 | #define RC_NORM_REMOTE(p) RC_NORM(p) | ||
48 | |||
49 | // #define RC_PRE(total) p->Range /= total; | ||
50 | // #define RC_PRE(total) | ||
51 | |||
52 | #define R p | ||
53 | |||
54 | |||
55 | |||
56 | |||
57 | MY_FORCE_INLINE | ||
58 | // MY_NO_INLINE | ||
59 | static void RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total) | ||
60 | { | ||
61 | R->Low += start * (R->Range /= total); | ||
62 | R->Range *= size; | ||
63 | RC_NORM_LOCAL(R); | ||
64 | } | ||
65 | |||
66 | |||
67 | |||
68 | |||
69 | |||
70 | |||
71 | |||
72 | |||
73 | |||
74 | |||
75 | #define RC_Encode(start, size, total) RangeEnc_Encode(p, start, size, total); | ||
76 | #define RC_EncodeFinal(start, size, total) RC_Encode(start, size, total); RC_NORM_REMOTE(p); | ||
77 | |||
78 | #define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) | ||
79 | |||
80 | typedef CPpmd8_Context * CTX_PTR; | ||
81 | #define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p) | ||
82 | |||
83 | void Ppmd8_UpdateModel(CPpmd8 *p); | ||
84 | |||
85 | #define MASK(sym) ((unsigned char *)charMask)[sym] | ||
86 | |||
87 | // MY_FORCE_INLINE | ||
88 | // static | ||
89 | void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol) | ||
90 | { | ||
91 | size_t charMask[256 / sizeof(size_t)]; | ||
92 | |||
93 | if (p->MinContext->NumStats != 0) | ||
94 | { | ||
95 | CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); | ||
96 | UInt32 sum; | ||
97 | unsigned i; | ||
98 | UInt32 summFreq = p->MinContext->Union2.SummFreq; | ||
99 | |||
100 | PPMD8_CORRECT_SUM_RANGE(p, summFreq) | ||
101 | |||
102 | // RC_PRE(summFreq); | ||
103 | |||
104 | if (s->Symbol == symbol) | ||
105 | { | ||
106 | |||
107 | RC_EncodeFinal(0, s->Freq, summFreq); | ||
108 | p->FoundState = s; | ||
109 | Ppmd8_Update1_0(p); | ||
110 | return; | ||
111 | } | ||
112 | p->PrevSuccess = 0; | ||
113 | sum = s->Freq; | ||
114 | i = p->MinContext->NumStats; | ||
115 | do | ||
116 | { | ||
117 | if ((++s)->Symbol == symbol) | ||
118 | { | ||
119 | |||
120 | RC_EncodeFinal(sum, s->Freq, summFreq); | ||
121 | p->FoundState = s; | ||
122 | Ppmd8_Update1(p); | ||
123 | return; | ||
124 | } | ||
125 | sum += s->Freq; | ||
126 | } | ||
127 | while (--i); | ||
128 | |||
129 | |||
130 | RC_Encode(sum, summFreq - sum, summFreq); | ||
131 | |||
132 | |||
133 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
134 | // MASK(s->Symbol) = 0; | ||
135 | // i = p->MinContext->NumStats; | ||
136 | // do { MASK((--s)->Symbol) = 0; } while (--i); | ||
137 | { | ||
138 | CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); | ||
139 | MASK(s->Symbol) = 0; | ||
140 | do | ||
141 | { | ||
142 | unsigned sym0 = s2[0].Symbol; | ||
143 | unsigned sym1 = s2[1].Symbol; | ||
144 | s2 += 2; | ||
145 | MASK(sym0) = 0; | ||
146 | MASK(sym1) = 0; | ||
147 | } | ||
148 | while (s2 < s); | ||
149 | } | ||
150 | } | ||
151 | else | ||
152 | { | ||
153 | UInt16 *prob = Ppmd8_GetBinSumm(p); | ||
154 | CPpmd_State *s = Ppmd8Context_OneState(p->MinContext); | ||
155 | UInt32 pr = *prob; | ||
156 | UInt32 bound = (R->Range >> 14) * pr; | ||
157 | pr = PPMD_UPDATE_PROB_1(pr); | ||
158 | if (s->Symbol == symbol) | ||
159 | { | ||
160 | *prob = (UInt16)(pr + (1 << PPMD_INT_BITS)); | ||
161 | // RangeEnc_EncodeBit_0(p, bound); | ||
162 | R->Range = bound; | ||
163 | RC_NORM(R); | ||
164 | |||
165 | // p->FoundState = s; | ||
166 | // Ppmd8_UpdateBin(p); | ||
167 | { | ||
168 | unsigned freq = s->Freq; | ||
169 | CTX_PTR c = CTX(SUCCESSOR(s)); | ||
170 | p->FoundState = s; | ||
171 | p->PrevSuccess = 1; | ||
172 | p->RunLength++; | ||
173 | s->Freq = (Byte)(freq + (freq < 196)); // Ppmd8 (196) | ||
174 | // NextContext(p); | ||
175 | if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart) | ||
176 | p->MaxContext = p->MinContext = c; | ||
177 | else | ||
178 | Ppmd8_UpdateModel(p); | ||
179 | } | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | *prob = (UInt16)pr; | ||
184 | p->InitEsc = p->ExpEscape[pr >> 10]; | ||
185 | // RangeEnc_EncodeBit_1(p, bound); | ||
186 | R->Low += bound; | ||
187 | R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - bound; | ||
188 | RC_NORM_LOCAL(R) | ||
189 | |||
190 | PPMD_SetAllBitsIn256Bytes(charMask); | ||
191 | MASK(s->Symbol) = 0; | ||
192 | p->PrevSuccess = 0; | ||
193 | } | ||
194 | |||
195 | for (;;) | ||
196 | { | ||
197 | CPpmd_See *see; | ||
198 | CPpmd_State *s; | ||
199 | UInt32 sum, escFreq; | ||
200 | CPpmd8_Context *mc; | ||
201 | unsigned i, numMasked; | ||
202 | |||
203 | RC_NORM_REMOTE(p) | ||
204 | |||
205 | mc = p->MinContext; | ||
206 | numMasked = mc->NumStats; | ||
207 | |||
208 | do | ||
209 | { | ||
210 | p->OrderFall++; | ||
211 | if (!mc->Suffix) | ||
212 | return; /* EndMarker (symbol = -1) */ | ||
213 | mc = Ppmd8_GetContext(p, mc->Suffix); | ||
214 | |||
215 | } | ||
216 | while (mc->NumStats == numMasked); | ||
217 | |||
218 | p->MinContext = mc; | ||
219 | |||
220 | see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq); | ||
221 | |||
222 | |||
223 | |||
224 | |||
225 | |||
226 | |||
227 | |||
228 | |||
229 | |||
230 | |||
231 | |||
232 | |||
233 | |||
234 | |||
235 | |||
236 | |||
237 | |||
238 | |||
239 | |||
240 | |||
241 | |||
242 | |||
243 | |||
244 | |||
245 | s = Ppmd8_GetStats(p, p->MinContext); | ||
246 | sum = 0; | ||
247 | i = (unsigned)p->MinContext->NumStats + 1; | ||
248 | |||
249 | do | ||
250 | { | ||
251 | unsigned cur = s->Symbol; | ||
252 | if ((int)cur == symbol) | ||
253 | { | ||
254 | UInt32 low = sum; | ||
255 | UInt32 freq = s->Freq; | ||
256 | unsigned num2; | ||
257 | |||
258 | Ppmd_See_Update(see); | ||
259 | p->FoundState = s; | ||
260 | sum += escFreq; | ||
261 | |||
262 | num2 = i / 2; | ||
263 | i &= 1; | ||
264 | sum += freq & (0 - (UInt32)i); | ||
265 | if (num2 != 0) | ||
266 | { | ||
267 | s += i; | ||
268 | for (;;) | ||
269 | { | ||
270 | unsigned sym0 = s[0].Symbol; | ||
271 | unsigned sym1 = s[1].Symbol; | ||
272 | s += 2; | ||
273 | sum += (s[-2].Freq & (unsigned)(MASK(sym0))); | ||
274 | sum += (s[-1].Freq & (unsigned)(MASK(sym1))); | ||
275 | if (--num2 == 0) | ||
276 | break; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | PPMD8_CORRECT_SUM_RANGE(p, sum); | ||
281 | |||
282 | RC_EncodeFinal(low, freq, sum); | ||
283 | Ppmd8_Update2(p); | ||
284 | return; | ||
285 | } | ||
286 | sum += (s->Freq & (unsigned)(MASK(cur))); | ||
287 | s++; | ||
288 | } | ||
289 | while (--i); | ||
290 | |||
291 | { | ||
292 | UInt32 total = sum + escFreq; | ||
293 | see->Summ = (UInt16)(see->Summ + total); | ||
294 | PPMD8_CORRECT_SUM_RANGE(p, total); | ||
295 | |||
296 | RC_Encode(sum, total - sum, total); | ||
297 | } | ||
298 | |||
299 | { | ||
300 | CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext); | ||
301 | s--; | ||
302 | MASK(s->Symbol) = 0; | ||
303 | do | ||
304 | { | ||
305 | unsigned sym0 = s2[0].Symbol; | ||
306 | unsigned sym1 = s2[1].Symbol; | ||
307 | s2 += 2; | ||
308 | MASK(sym0) = 0; | ||
309 | MASK(sym1) = 0; | ||
310 | } | ||
311 | while (s2 < s); | ||
312 | } | ||
313 | } | ||
314 | } | ||