/src/CMake/Utilities/cmlibarchive/libarchive/archive_ppmd8.c
Line | Count | Source |
1 | | /* Ppmd8.c -- PPMdI codec |
2 | | 2016-05-21 : Igor Pavlov : Public domain |
3 | | This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ |
4 | | |
5 | | #include "archive_platform.h" |
6 | | |
7 | | #ifdef __clang_analyzer__ |
8 | | #include <assert.h> |
9 | | #endif |
10 | | |
11 | | #include <string.h> |
12 | | |
13 | | #include "archive_ppmd8_private.h" |
14 | | |
15 | | const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; |
16 | | static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; |
17 | | |
18 | 109k | #define MAX_FREQ 124 |
19 | 59.7k | #define UNIT_SIZE 12 |
20 | | |
21 | 17.5k | #define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) |
22 | 7.81k | #define U2I(nu) (p->Units2Indx[(nu) - 1]) |
23 | 4.06k | #define I2U(indx) (p->Indx2Units[indx]) |
24 | | |
25 | | #ifdef PPMD_32BIT |
26 | | #define REF(ptr) (ptr) |
27 | | #else |
28 | 175k | #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) |
29 | | #endif |
30 | | |
31 | 3.77k | #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) |
32 | | |
33 | 1.36M | #define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) |
34 | 48.8k | #define STATS(ctx) Ppmd8_GetStats(p, ctx) |
35 | 88.6k | #define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) |
36 | 93.3k | #define SUFFIX(ctx) CTX((ctx)->Suffix) |
37 | | |
38 | 2.52M | #define kTop (1 << 24) |
39 | 2.48M | #define kBot (1 << 15) |
40 | | |
41 | | typedef CPpmd8_Context * CTX_PTR; |
42 | | |
43 | | struct CPpmd8_Node_; |
44 | | |
45 | | typedef |
46 | | #ifdef PPMD_32BIT |
47 | | struct CPpmd8_Node_ * |
48 | | #else |
49 | | UInt32 |
50 | | #endif |
51 | | CPpmd8_Node_Ref; |
52 | | |
53 | | typedef struct CPpmd8_Node_ |
54 | | { |
55 | | UInt32 Stamp; |
56 | | CPpmd8_Node_Ref Next; |
57 | | UInt32 NU; |
58 | | } CPpmd8_Node; |
59 | | |
60 | | #ifdef PPMD_32BIT |
61 | | #define NODE(ptr) (ptr) |
62 | | #else |
63 | 2.58k | #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs))) |
64 | | #endif |
65 | | |
66 | 4.02k | #define EMPTY_NODE 0xFFFFFFFF |
67 | | |
68 | | void Ppmd8_Construct(CPpmd8 *p) |
69 | 1.62k | { |
70 | 1.62k | unsigned i, k, m; |
71 | | |
72 | 1.62k | p->Base = 0; |
73 | | |
74 | 63.4k | for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) |
75 | 61.7k | { |
76 | 61.7k | unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); |
77 | 208k | do { p->Units2Indx[k++] = (Byte)i; } while (--step); |
78 | 61.7k | p->Indx2Units[i] = (Byte)k; |
79 | 61.7k | } |
80 | | |
81 | 1.62k | p->NS2BSIndx[0] = (0 << 1); |
82 | 1.62k | p->NS2BSIndx[1] = (1 << 1); |
83 | 1.62k | memset(p->NS2BSIndx + 2, (2 << 1), 9); |
84 | 1.62k | memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); |
85 | | |
86 | 9.75k | for (i = 0; i < 5; i++) |
87 | 8.13k | p->NS2Indx[i] = (Byte)i; |
88 | 416k | for (m = i, k = 1; i < 260; i++) |
89 | 414k | { |
90 | 414k | p->NS2Indx[i] = (Byte)m; |
91 | 414k | if (--k == 0) |
92 | 35.7k | k = (++m) - 4; |
93 | 414k | } |
94 | 1.62k | } |
95 | | |
96 | | void Ppmd8_Free(CPpmd8 *p) |
97 | 3.22k | { |
98 | 3.22k | free(p->Base); |
99 | 3.22k | p->Size = 0; |
100 | 3.22k | p->Base = 0; |
101 | 3.22k | } |
102 | | |
103 | | Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size) |
104 | 1.61k | { |
105 | 1.61k | if (p->Base == 0 || p->Size != size) |
106 | 1.61k | { |
107 | 1.61k | Ppmd8_Free(p); |
108 | 1.61k | p->AlignOffset = |
109 | | #ifdef PPMD_32BIT |
110 | | (4 - size) & 3; |
111 | | #else |
112 | 1.61k | 4 - (size & 3); |
113 | 1.61k | #endif |
114 | 1.61k | if ((p->Base = malloc(p->AlignOffset + size)) == 0) |
115 | 0 | return False; |
116 | 1.61k | p->Size = size; |
117 | 1.61k | } |
118 | 1.61k | return True; |
119 | 1.61k | } |
120 | | |
121 | | static void InsertNode(CPpmd8 *p, void *node, unsigned indx) |
122 | 4.02k | { |
123 | 4.02k | ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; |
124 | 4.02k | ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; |
125 | 4.02k | ((CPpmd8_Node *)node)->NU = I2U(indx); |
126 | 4.02k | p->FreeList[indx] = REF(node); |
127 | 4.02k | p->Stamps[indx]++; |
128 | 4.02k | } |
129 | | |
130 | | static void *RemoveNode(CPpmd8 *p, unsigned indx) |
131 | 2.58k | { |
132 | 2.58k | CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); |
133 | 2.58k | p->FreeList[indx] = node->Next; |
134 | 2.58k | p->Stamps[indx]--; |
135 | 2.58k | return node; |
136 | 2.58k | } |
137 | | |
138 | | static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) |
139 | 14 | { |
140 | 14 | unsigned i, nu = I2U(oldIndx) - I2U(newIndx); |
141 | 14 | ptr = (Byte *)ptr + U2B(I2U(newIndx)); |
142 | 14 | if (I2U(i = U2I(nu)) != nu) |
143 | 0 | { |
144 | 0 | unsigned k = I2U(--i); |
145 | 0 | InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); |
146 | 0 | } |
147 | 14 | InsertNode(p, ptr, i); |
148 | 14 | } |
149 | | |
150 | | static void GlueFreeBlocks(CPpmd8 *p) |
151 | 0 | { |
152 | 0 | CPpmd8_Node_Ref head = 0; |
153 | 0 | CPpmd8_Node_Ref *prev = &head; |
154 | 0 | unsigned i; |
155 | |
|
156 | 0 | p->GlueCount = 1 << 13; |
157 | 0 | memset(p->Stamps, 0, sizeof(p->Stamps)); |
158 | | |
159 | | /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end. |
160 | | All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */ |
161 | 0 | if (p->LoUnit != p->HiUnit) |
162 | 0 | ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; |
163 | | |
164 | | /* Glue free blocks */ |
165 | 0 | for (i = 0; i < PPMD_NUM_INDEXES; i++) |
166 | 0 | { |
167 | 0 | CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; |
168 | 0 | p->FreeList[i] = 0; |
169 | 0 | while (next != 0) |
170 | 0 | { |
171 | 0 | CPpmd8_Node *node = NODE(next); |
172 | 0 | if (node->NU != 0) |
173 | 0 | { |
174 | 0 | CPpmd8_Node *node2; |
175 | 0 | *prev = next; |
176 | 0 | prev = &(node->Next); |
177 | 0 | while ((node2 = node + node->NU)->Stamp == EMPTY_NODE) |
178 | 0 | { |
179 | 0 | node->NU += node2->NU; |
180 | 0 | node2->NU = 0; |
181 | 0 | } |
182 | 0 | } |
183 | 0 | next = node->Next; |
184 | 0 | } |
185 | 0 | } |
186 | 0 | *prev = 0; |
187 | | |
188 | | /* Fill lists of free blocks */ |
189 | 0 | while (head != 0) |
190 | 0 | { |
191 | 0 | CPpmd8_Node *node = NODE(head); |
192 | 0 | unsigned nu; |
193 | 0 | head = node->Next; |
194 | 0 | nu = node->NU; |
195 | 0 | if (nu == 0) |
196 | 0 | continue; |
197 | 0 | for (; nu > 128; nu -= 128, node += 128) |
198 | 0 | InsertNode(p, node, PPMD_NUM_INDEXES - 1); |
199 | 0 | if (I2U(i = U2I(nu)) != nu) |
200 | 0 | { |
201 | 0 | unsigned k = I2U(--i); |
202 | 0 | InsertNode(p, node + k, nu - k - 1); |
203 | 0 | } |
204 | 0 | InsertNode(p, node, i); |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | | static void *AllocUnitsRare(CPpmd8 *p, unsigned indx) |
209 | 0 | { |
210 | 0 | unsigned i; |
211 | 0 | void *retVal; |
212 | 0 | if (p->GlueCount == 0) |
213 | 0 | { |
214 | 0 | GlueFreeBlocks(p); |
215 | 0 | if (p->FreeList[indx] != 0) |
216 | 0 | return RemoveNode(p, indx); |
217 | 0 | } |
218 | 0 | i = indx; |
219 | 0 | do |
220 | 0 | { |
221 | 0 | if (++i == PPMD_NUM_INDEXES) |
222 | 0 | { |
223 | 0 | UInt32 numBytes = U2B(I2U(indx)); |
224 | 0 | p->GlueCount--; |
225 | 0 | return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); |
226 | 0 | } |
227 | 0 | } |
228 | 0 | while (p->FreeList[i] == 0); |
229 | 0 | retVal = RemoveNode(p, i); |
230 | 0 | SplitBlock(p, retVal, i, indx); |
231 | 0 | return retVal; |
232 | 0 | } |
233 | | |
234 | | static void *AllocUnits(CPpmd8 *p, unsigned indx) |
235 | 18.4k | { |
236 | 18.4k | UInt32 numBytes; |
237 | 18.4k | if (p->FreeList[indx] != 0) |
238 | 2.50k | return RemoveNode(p, indx); |
239 | 15.9k | numBytes = U2B(I2U(indx)); |
240 | 15.9k | if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) |
241 | 15.9k | { |
242 | 15.9k | void *retVal = p->LoUnit; |
243 | 15.9k | p->LoUnit += numBytes; |
244 | 15.9k | return retVal; |
245 | 15.9k | } |
246 | 0 | return AllocUnitsRare(p, indx); |
247 | 15.9k | } |
248 | | |
249 | 3.76k | #define MyMem12Cpy(dest, src, num) do { \ |
250 | 3.76k | UInt32 *d = (UInt32 *)dest; \ |
251 | 3.76k | const UInt32 *z = (const UInt32 *)src; \ |
252 | 3.76k | UInt32 n = num; \ |
253 | 4.54k | do { \ |
254 | 4.54k | d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; \ |
255 | 4.54k | } while (--n); \ |
256 | 3.76k | } while (0) |
257 | | |
258 | | static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU) |
259 | 88 | { |
260 | 88 | unsigned i0 = U2I(oldNU); |
261 | 88 | unsigned i1 = U2I(newNU); |
262 | 88 | if (i0 == i1) |
263 | 0 | return oldPtr; |
264 | 88 | if (p->FreeList[i1] != 0) |
265 | 74 | { |
266 | 74 | void *ptr = RemoveNode(p, i1); |
267 | 74 | MyMem12Cpy(ptr, oldPtr, newNU); |
268 | 74 | InsertNode(p, oldPtr, i0); |
269 | 74 | return ptr; |
270 | 74 | } |
271 | 14 | SplitBlock(p, oldPtr, i0, i1); |
272 | 14 | return oldPtr; |
273 | 88 | } |
274 | | |
275 | | static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) |
276 | 0 | { |
277 | 0 | InsertNode(p, ptr, U2I(nu)); |
278 | 0 | } |
279 | | |
280 | | static void SpecialFreeUnit(CPpmd8 *p, void *ptr) |
281 | 0 | { |
282 | 0 | if ((Byte *)ptr != p->UnitsStart) |
283 | 0 | InsertNode(p, ptr, 0); |
284 | 0 | else |
285 | 0 | { |
286 | | #ifdef PPMD8_FREEZE_SUPPORT |
287 | | *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */ |
288 | | #endif |
289 | 0 | p->UnitsStart += UNIT_SIZE; |
290 | 0 | } |
291 | 0 | } |
292 | | |
293 | | static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) |
294 | 0 | { |
295 | 0 | unsigned indx = U2I(nu); |
296 | 0 | void *ptr; |
297 | 0 | if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx]) |
298 | 0 | return oldPtr; |
299 | 0 | ptr = RemoveNode(p, indx); |
300 | 0 | MyMem12Cpy(ptr, oldPtr, nu); |
301 | 0 | if ((Byte*)oldPtr != p->UnitsStart) |
302 | 0 | InsertNode(p, oldPtr, indx); |
303 | 0 | else |
304 | 0 | p->UnitsStart += U2B(I2U(indx)); |
305 | 0 | return ptr; |
306 | 0 | } |
307 | | |
308 | | static void ExpandTextArea(CPpmd8 *p) |
309 | 0 | { |
310 | 0 | UInt32 count[PPMD_NUM_INDEXES]; |
311 | 0 | unsigned i; |
312 | 0 | memset(count, 0, sizeof(count)); |
313 | 0 | if (p->LoUnit != p->HiUnit) |
314 | 0 | ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; |
315 | | |
316 | 0 | { |
317 | 0 | CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart; |
318 | 0 | for (; node->Stamp == EMPTY_NODE; node += node->NU) |
319 | 0 | { |
320 | 0 | node->Stamp = 0; |
321 | 0 | count[U2I(node->NU)]++; |
322 | 0 | } |
323 | 0 | p->UnitsStart = (Byte *)node; |
324 | 0 | } |
325 | | |
326 | 0 | for (i = 0; i < PPMD_NUM_INDEXES; i++) |
327 | 0 | { |
328 | 0 | CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i]; |
329 | 0 | while (count[i] != 0) |
330 | 0 | { |
331 | 0 | CPpmd8_Node *node = NODE(*next); |
332 | 0 | while (node->Stamp == 0) |
333 | 0 | { |
334 | 0 | *next = node->Next; |
335 | 0 | node = NODE(*next); |
336 | 0 | p->Stamps[i]--; |
337 | 0 | if (--count[i] == 0) |
338 | 0 | break; |
339 | 0 | } |
340 | 0 | next = &node->Next; |
341 | 0 | } |
342 | 0 | } |
343 | 0 | } |
344 | | |
345 | 93.9k | #define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) |
346 | | |
347 | | static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) |
348 | 502k | { |
349 | | #ifdef __clang_analyzer__ |
350 | | assert(p); |
351 | | #endif |
352 | 502k | (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); |
353 | 502k | (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); |
354 | 502k | } |
355 | | |
356 | 1.60k | #define RESET_TEXT(offs) do { \ |
357 | 1.60k | p->Text = p->Base + p->AlignOffset + (offs); \ |
358 | 1.60k | } while (0) |
359 | | |
360 | | static void RestartModel(CPpmd8 *p) |
361 | 1.60k | { |
362 | 1.60k | unsigned i, k, m, r; |
363 | | |
364 | 1.60k | memset(p->FreeList, 0, sizeof(p->FreeList)); |
365 | 1.60k | memset(p->Stamps, 0, sizeof(p->Stamps)); |
366 | 1.60k | RESET_TEXT(0); |
367 | 1.60k | p->HiUnit = p->Text + p->Size; |
368 | 1.60k | p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; |
369 | 1.60k | p->GlueCount = 0; |
370 | | |
371 | 1.60k | p->OrderFall = p->MaxOrder; |
372 | 1.60k | p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; |
373 | 1.60k | p->PrevSuccess = 0; |
374 | | |
375 | 1.60k | p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ |
376 | 1.60k | p->MinContext->Suffix = 0; |
377 | 1.60k | p->MinContext->NumStats = 255; |
378 | 1.60k | p->MinContext->Flags = 0; |
379 | 1.60k | p->MinContext->SummFreq = 256 + 1; |
380 | 1.60k | p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ |
381 | 1.60k | p->LoUnit += U2B(256 / 2); |
382 | 1.60k | p->MinContext->Stats = REF(p->FoundState); |
383 | 413k | for (i = 0; i < 256; i++) |
384 | 411k | { |
385 | 411k | CPpmd_State *s = &p->FoundState[i]; |
386 | 411k | s->Symbol = (Byte)i; |
387 | 411k | s->Freq = 1; |
388 | 411k | SetSuccessor(s, 0); |
389 | 411k | } |
390 | | |
391 | 41.8k | for (i = m = 0; m < 25; m++) |
392 | 40.2k | { |
393 | 385k | while (p->NS2Indx[i] == m) |
394 | 345k | i++; |
395 | 361k | for (k = 0; k < 8; k++) |
396 | 321k | { |
397 | 321k | UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1)); |
398 | 321k | UInt16 *dest = p->BinSumm[m] + k; |
399 | 2.89M | for (r = 0; r < 64; r += 8) |
400 | 2.57M | dest[r] = val; |
401 | 321k | } |
402 | 40.2k | } |
403 | | |
404 | 40.2k | for (i = m = 0; m < 24; m++) |
405 | 38.5k | { |
406 | 448k | while (p->NS2Indx[i + 3] == m + 3) |
407 | 410k | i++; |
408 | 1.27M | for (k = 0; k < 32; k++) |
409 | 1.23M | { |
410 | 1.23M | CPpmd_See *s = &p->See[m][k]; |
411 | 1.23M | s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4)); |
412 | 1.23M | s->Count = 7; |
413 | 1.23M | } |
414 | 38.5k | } |
415 | 1.60k | } |
416 | | |
417 | | void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) |
418 | 1.60k | { |
419 | 1.60k | p->MaxOrder = maxOrder; |
420 | 1.60k | p->RestoreMethod = restoreMethod; |
421 | 1.60k | RestartModel(p); |
422 | 1.60k | p->DummySee.Shift = PPMD_PERIOD_BITS; |
423 | 1.60k | p->DummySee.Summ = 0; /* unused */ |
424 | 1.60k | p->DummySee.Count = 64; /* unused */ |
425 | 1.60k | } |
426 | | |
427 | | static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale) |
428 | 0 | { |
429 | 0 | unsigned i = ctx->NumStats, escFreq, sumFreq, flags; |
430 | 0 | CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); |
431 | 0 | ctx->Stats = REF(s); |
432 | | #ifdef PPMD8_FREEZE_SUPPORT |
433 | | /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */ |
434 | | scale |= (ctx->SummFreq >= ((UInt32)1 << 15)); |
435 | | #endif |
436 | 0 | flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40); |
437 | 0 | escFreq = ctx->SummFreq - s->Freq; |
438 | 0 | sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale)); |
439 | 0 | do |
440 | 0 | { |
441 | 0 | escFreq -= (++s)->Freq; |
442 | 0 | sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale)); |
443 | 0 | flags |= 0x08 * (s->Symbol >= 0x40); |
444 | 0 | } |
445 | 0 | while (--i); |
446 | 0 | ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); |
447 | 0 | ctx->Flags = (Byte)flags; |
448 | 0 | } |
449 | | |
450 | | static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) |
451 | 14.1k | { |
452 | 14.1k | CPpmd_State tmp = *t1; |
453 | 14.1k | *t1 = *t2; |
454 | 14.1k | *t2 = tmp; |
455 | 14.1k | } |
456 | | |
457 | | static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order) |
458 | 0 | { |
459 | 0 | int i; |
460 | 0 | unsigned tmp; |
461 | 0 | CPpmd_State *s; |
462 | | |
463 | 0 | if (!ctx->NumStats) |
464 | 0 | { |
465 | 0 | s = ONE_STATE(ctx); |
466 | 0 | if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart) |
467 | 0 | { |
468 | 0 | if (order < p->MaxOrder) |
469 | 0 | SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); |
470 | 0 | else |
471 | 0 | SetSuccessor(s, 0); |
472 | 0 | if (SUCCESSOR(s) || order <= 9) /* O_BOUND */ |
473 | 0 | return REF(ctx); |
474 | 0 | } |
475 | 0 | SpecialFreeUnit(p, ctx); |
476 | 0 | return 0; |
477 | 0 | } |
478 | | |
479 | 0 | ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1)); |
480 | |
|
481 | 0 | for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--) |
482 | 0 | if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart) |
483 | 0 | { |
484 | 0 | CPpmd_State *s2 = STATS(ctx) + (i--); |
485 | 0 | SetSuccessor(s, 0); |
486 | 0 | SwapStates(s, s2); |
487 | 0 | } |
488 | 0 | else if (order < p->MaxOrder) |
489 | 0 | SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); |
490 | 0 | else |
491 | 0 | SetSuccessor(s, 0); |
492 | | |
493 | 0 | if (i != ctx->NumStats && order) |
494 | 0 | { |
495 | 0 | ctx->NumStats = (Byte)i; |
496 | 0 | s = STATS(ctx); |
497 | 0 | if (i < 0) |
498 | 0 | { |
499 | 0 | FreeUnits(p, s, tmp); |
500 | 0 | SpecialFreeUnit(p, ctx); |
501 | 0 | return 0; |
502 | 0 | } |
503 | 0 | if (i == 0) |
504 | 0 | { |
505 | 0 | ctx->Flags = (Byte)((ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40)); |
506 | 0 | *ONE_STATE(ctx) = *s; |
507 | 0 | FreeUnits(p, s, tmp); |
508 | | /* 9.31: the code was fixed. It's was not BUG, if Freq <= MAX_FREQ = 124 */ |
509 | 0 | ONE_STATE(ctx)->Freq = (Byte)(((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3); |
510 | 0 | } |
511 | 0 | else |
512 | 0 | Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i); |
513 | 0 | } |
514 | 0 | return REF(ctx); |
515 | 0 | } |
516 | | |
517 | | #ifdef PPMD8_FREEZE_SUPPORT |
518 | | static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order) |
519 | | { |
520 | | CPpmd_State *s; |
521 | | if (!ctx->NumStats) |
522 | | { |
523 | | s = ONE_STATE(ctx); |
524 | | if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) |
525 | | SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); |
526 | | else |
527 | | SetSuccessor(s, 0); |
528 | | /* Suffix context can be removed already, since different (high-order) |
529 | | Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */ |
530 | | if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF)) |
531 | | { |
532 | | FreeUnits(p, ctx, 1); |
533 | | return 0; |
534 | | } |
535 | | else |
536 | | return REF(ctx); |
537 | | } |
538 | | |
539 | | for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--) |
540 | | if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) |
541 | | SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); |
542 | | else |
543 | | SetSuccessor(s, 0); |
544 | | |
545 | | return REF(ctx); |
546 | | } |
547 | | #endif |
548 | | |
549 | | static UInt32 GetUsedMemory(const CPpmd8 *p) |
550 | 0 | { |
551 | 0 | UInt32 v = 0; |
552 | 0 | unsigned i; |
553 | 0 | for (i = 0; i < PPMD_NUM_INDEXES; i++) |
554 | 0 | v += p->Stamps[i] * I2U(i); |
555 | 0 | return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); |
556 | 0 | } |
557 | | |
558 | | #ifdef PPMD8_FREEZE_SUPPORT |
559 | | #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) |
560 | | #else |
561 | 0 | #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1) |
562 | | #endif |
563 | | |
564 | | static void RestoreModel(CPpmd8 *p, CTX_PTR c1 |
565 | | #ifdef PPMD8_FREEZE_SUPPORT |
566 | | , CTX_PTR fSuccessor |
567 | | #endif |
568 | | ) |
569 | 0 | { |
570 | 0 | CTX_PTR c; |
571 | 0 | CPpmd_State *s; |
572 | 0 | RESET_TEXT(0); |
573 | 0 | for (c = p->MaxContext; c != c1; c = SUFFIX(c)) |
574 | 0 | if (--(c->NumStats) == 0) |
575 | 0 | { |
576 | 0 | s = STATS(c); |
577 | 0 | c->Flags = (Byte)((c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40)); |
578 | 0 | *ONE_STATE(c) = *s; |
579 | 0 | SpecialFreeUnit(p, s); |
580 | 0 | ONE_STATE(c)->Freq = (Byte)(((unsigned)ONE_STATE(c)->Freq + 11) >> 3); |
581 | 0 | } |
582 | 0 | else |
583 | 0 | Refresh(p, c, (c->NumStats+3) >> 1, 0); |
584 | | |
585 | 0 | for (; c != p->MinContext; c = SUFFIX(c)) |
586 | 0 | if (!c->NumStats) |
587 | 0 | ONE_STATE(c)->Freq = (Byte)(ONE_STATE(c)->Freq - (ONE_STATE(c)->Freq >> 1)); |
588 | 0 | else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats) |
589 | 0 | Refresh(p, c, (c->NumStats + 2) >> 1, 1); |
590 | |
|
591 | | #ifdef PPMD8_FREEZE_SUPPORT |
592 | | if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) |
593 | | { |
594 | | p->MaxContext = fSuccessor; |
595 | | p->GlueCount += !(p->Stamps[1] & 1); |
596 | | } |
597 | | else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE) |
598 | | { |
599 | | while (p->MaxContext->Suffix) |
600 | | p->MaxContext = SUFFIX(p->MaxContext); |
601 | | RemoveBinContexts(p, p->MaxContext, 0); |
602 | | p->RestoreMethod++; |
603 | | p->GlueCount = 0; |
604 | | p->OrderFall = p->MaxOrder; |
605 | | } |
606 | | else |
607 | | #endif |
608 | 0 | if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) |
609 | 0 | RestartModel(p); |
610 | 0 | else |
611 | 0 | { |
612 | 0 | while (p->MaxContext->Suffix) |
613 | 0 | p->MaxContext = SUFFIX(p->MaxContext); |
614 | 0 | do |
615 | 0 | { |
616 | 0 | CutOff(p, p->MaxContext, 0); |
617 | 0 | ExpandTextArea(p); |
618 | 0 | } |
619 | 0 | while (GetUsedMemory(p) > 3 * (p->Size >> 2)); |
620 | 0 | p->GlueCount = 0; |
621 | 0 | p->OrderFall = p->MaxOrder; |
622 | 0 | } |
623 | 0 | } |
624 | | |
625 | | static CTX_PTR CreateSuccessors(CPpmd8 *p, Bool skip, CPpmd_State *s1, CTX_PTR c) |
626 | 18.5k | { |
627 | 18.5k | CPpmd_State upState; |
628 | 18.5k | Byte flags; |
629 | 18.5k | CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); |
630 | | /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ |
631 | 18.5k | CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; |
632 | 18.5k | unsigned numPs = 0; |
633 | | |
634 | | #ifdef __clang_analyzer__ |
635 | | memset(ps, 0, sizeof(ps)); |
636 | | #endif |
637 | | |
638 | | |
639 | 18.5k | if (!skip) |
640 | 13.9k | ps[numPs++] = p->FoundState; |
641 | | |
642 | 41.9k | while (c->Suffix) |
643 | 37.2k | { |
644 | 37.2k | CPpmd_Void_Ref successor; |
645 | 37.2k | CPpmd_State *s; |
646 | 37.2k | c = SUFFIX(c); |
647 | 37.2k | if (s1) |
648 | 15.9k | { |
649 | 15.9k | s = s1; |
650 | 15.9k | s1 = NULL; |
651 | 15.9k | } |
652 | 21.3k | else if (c->NumStats != 0) |
653 | 7.30k | { |
654 | 312k | for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); |
655 | 7.30k | if (s->Freq < MAX_FREQ - 9) |
656 | 7.30k | { |
657 | 7.30k | s->Freq++; |
658 | 7.30k | c->SummFreq++; |
659 | 7.30k | } |
660 | 7.30k | } |
661 | 14.0k | else |
662 | 14.0k | { |
663 | 14.0k | s = ONE_STATE(c); |
664 | 14.0k | s->Freq = (Byte)(s->Freq + (!SUFFIX(c)->NumStats & (s->Freq < 24))); |
665 | 14.0k | } |
666 | 37.2k | successor = SUCCESSOR(s); |
667 | 37.2k | if (successor != upBranch) |
668 | 13.7k | { |
669 | 13.7k | c = CTX(successor); |
670 | 13.7k | if (numPs == 0) |
671 | 1.50k | return c; |
672 | 12.2k | break; |
673 | 13.7k | } |
674 | 23.4k | ps[numPs++] = s; |
675 | 23.4k | } |
676 | | |
677 | 17.0k | upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch); |
678 | 17.0k | SetSuccessor(&upState, upBranch + 1); |
679 | 17.0k | flags = (Byte)(0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40)); |
680 | | |
681 | 17.0k | if (c->NumStats == 0) |
682 | 8.87k | upState.Freq = ONE_STATE(c)->Freq; |
683 | 8.15k | else |
684 | 8.15k | { |
685 | 8.15k | UInt32 cf, s0; |
686 | 8.15k | CPpmd_State *s; |
687 | 494k | for (s = STATS(c); s->Symbol != upState.Symbol; s++); |
688 | 8.15k | cf = s->Freq - 1; |
689 | 8.15k | s0 = c->SummFreq - c->NumStats - cf; |
690 | 8.15k | upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); |
691 | 8.15k | } |
692 | | |
693 | 54.4k | while (numPs != 0) |
694 | 37.4k | { |
695 | | /* Create Child */ |
696 | 37.4k | CTX_PTR c1; /* = AllocContext(p); */ |
697 | 37.4k | if (p->HiUnit != p->LoUnit) |
698 | 37.4k | c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); |
699 | 0 | else if (p->FreeList[0] != 0) |
700 | 0 | c1 = (CTX_PTR)RemoveNode(p, 0); |
701 | 0 | else |
702 | 0 | { |
703 | 0 | c1 = (CTX_PTR)AllocUnitsRare(p, 0); |
704 | 0 | if (!c1) |
705 | 0 | return NULL; |
706 | 0 | } |
707 | 37.4k | c1->NumStats = 0; |
708 | 37.4k | c1->Flags = flags; |
709 | 37.4k | *ONE_STATE(c1) = upState; |
710 | 37.4k | c1->Suffix = REF(c); |
711 | 37.4k | SetSuccessor(ps[--numPs], REF(c1)); |
712 | 37.4k | c = c1; |
713 | 37.4k | } |
714 | | |
715 | 17.0k | return c; |
716 | 17.0k | } |
717 | | |
718 | | static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c) |
719 | 12.2k | { |
720 | 12.2k | CPpmd_State *s = NULL; |
721 | 12.2k | CTX_PTR c1 = c; |
722 | 12.2k | CPpmd_Void_Ref upBranch = REF(p->Text); |
723 | | |
724 | | #ifdef PPMD8_FREEZE_SUPPORT |
725 | | /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */ |
726 | | CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; |
727 | | unsigned numPs = 0; |
728 | | ps[numPs++] = p->FoundState; |
729 | | #endif |
730 | | |
731 | 12.2k | SetSuccessor(p->FoundState, upBranch); |
732 | 12.2k | p->OrderFall++; |
733 | | |
734 | 12.2k | for (;;) |
735 | 12.2k | { |
736 | 12.2k | if (s1) |
737 | 0 | { |
738 | 0 | c = SUFFIX(c); |
739 | 0 | s = s1; |
740 | 0 | s1 = NULL; |
741 | 0 | } |
742 | 12.2k | else |
743 | 12.2k | { |
744 | 12.2k | if (!c->Suffix) |
745 | 12.2k | { |
746 | | #ifdef PPMD8_FREEZE_SUPPORT |
747 | | if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) |
748 | | { |
749 | | do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); |
750 | | RESET_TEXT(1); |
751 | | p->OrderFall = 1; |
752 | | } |
753 | | #endif |
754 | 12.2k | return c; |
755 | 12.2k | } |
756 | 0 | c = SUFFIX(c); |
757 | 0 | if (c->NumStats) |
758 | 0 | { |
759 | 0 | if ((s = STATS(c))->Symbol != p->FoundState->Symbol) |
760 | 0 | do { s++; } while (s->Symbol != p->FoundState->Symbol); |
761 | 0 | if (s->Freq < MAX_FREQ - 9) |
762 | 0 | { |
763 | 0 | s->Freq += 2; |
764 | 0 | c->SummFreq += 2; |
765 | 0 | } |
766 | 0 | } |
767 | 0 | else |
768 | 0 | { |
769 | 0 | s = ONE_STATE(c); |
770 | 0 | s->Freq = (Byte)(s->Freq + (s->Freq < 32)); |
771 | 0 | } |
772 | 0 | } |
773 | 0 | if (SUCCESSOR(s)) |
774 | 0 | break; |
775 | | #ifdef PPMD8_FREEZE_SUPPORT |
776 | | ps[numPs++] = s; |
777 | | #endif |
778 | 0 | SetSuccessor(s, upBranch); |
779 | 0 | p->OrderFall++; |
780 | 0 | } |
781 | | |
782 | | #ifdef PPMD8_FREEZE_SUPPORT |
783 | | if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) |
784 | | { |
785 | | c = CTX(SUCCESSOR(s)); |
786 | | do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); |
787 | | RESET_TEXT(1); |
788 | | p->OrderFall = 1; |
789 | | return c; |
790 | | } |
791 | | else |
792 | | #endif |
793 | 0 | if (SUCCESSOR(s) <= upBranch) |
794 | 0 | { |
795 | 0 | CTX_PTR successor; |
796 | 0 | CPpmd_State *s2 = p->FoundState; |
797 | 0 | p->FoundState = s; |
798 | |
|
799 | 0 | successor = CreateSuccessors(p, False, NULL, c); |
800 | 0 | if (successor == NULL) |
801 | 0 | SetSuccessor(s, 0); |
802 | 0 | else |
803 | 0 | SetSuccessor(s, REF(successor)); |
804 | 0 | p->FoundState = s2; |
805 | 0 | } |
806 | | |
807 | 0 | if (p->OrderFall == 1 && c1 == p->MaxContext) |
808 | 0 | { |
809 | 0 | SetSuccessor(p->FoundState, SUCCESSOR(s)); |
810 | 0 | p->Text--; |
811 | 0 | } |
812 | 0 | if (SUCCESSOR(s) == 0) |
813 | 0 | return NULL; |
814 | 0 | return CTX(SUCCESSOR(s)); |
815 | 0 | } |
816 | | |
817 | | static void UpdateModel(CPpmd8 *p) |
818 | 38.1k | { |
819 | 38.1k | CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); |
820 | 38.1k | CTX_PTR c; |
821 | 38.1k | unsigned s0, ns, fFreq = p->FoundState->Freq; |
822 | 38.1k | Byte flag, fSymbol = p->FoundState->Symbol; |
823 | 38.1k | CPpmd_State *s = NULL; |
824 | | |
825 | 38.1k | if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) |
826 | 20.2k | { |
827 | 20.2k | c = SUFFIX(p->MinContext); |
828 | | |
829 | 20.2k | if (c->NumStats == 0) |
830 | 13.2k | { |
831 | 13.2k | s = ONE_STATE(c); |
832 | 13.2k | if (s->Freq < 32) |
833 | 13.2k | s->Freq++; |
834 | 13.2k | } |
835 | 7.00k | else |
836 | 7.00k | { |
837 | 7.00k | s = STATS(c); |
838 | 7.00k | if (s->Symbol != p->FoundState->Symbol) |
839 | 3.71k | { |
840 | 285k | do { s++; } while (s->Symbol != p->FoundState->Symbol); |
841 | 3.71k | if (s[0].Freq >= s[-1].Freq) |
842 | 2.67k | { |
843 | 2.67k | SwapStates(&s[0], &s[-1]); |
844 | 2.67k | s--; |
845 | 2.67k | } |
846 | 3.71k | } |
847 | 7.00k | if (s->Freq < MAX_FREQ - 9) |
848 | 7.00k | { |
849 | 7.00k | s->Freq += 2; |
850 | 7.00k | c->SummFreq += 2; |
851 | 7.00k | } |
852 | 7.00k | } |
853 | 20.2k | } |
854 | | |
855 | 38.1k | c = p->MaxContext; |
856 | 38.1k | if (p->OrderFall == 0 && fSuccessor) |
857 | 4.55k | { |
858 | 4.55k | CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext); |
859 | 4.55k | if (cs == 0) |
860 | 0 | { |
861 | 0 | SetSuccessor(p->FoundState, 0); |
862 | 0 | RESTORE_MODEL(c, CTX(fSuccessor)); |
863 | 0 | } |
864 | 4.55k | else |
865 | 4.55k | { |
866 | 4.55k | SetSuccessor(p->FoundState, REF(cs)); |
867 | 4.55k | p->MaxContext = cs; |
868 | 4.55k | } |
869 | 4.55k | return; |
870 | 4.55k | } |
871 | | |
872 | 33.5k | *p->Text++ = p->FoundState->Symbol; |
873 | 33.5k | successor = REF(p->Text); |
874 | 33.5k | if (p->Text >= p->UnitsStart) |
875 | 0 | { |
876 | 0 | RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */ |
877 | 0 | return; |
878 | 0 | } |
879 | | |
880 | 33.5k | if (!fSuccessor) |
881 | 12.2k | { |
882 | 12.2k | CTX_PTR cs = ReduceOrder(p, s, p->MinContext); |
883 | 12.2k | if (cs == NULL) |
884 | 0 | { |
885 | 0 | RESTORE_MODEL(c, 0); |
886 | 0 | return; |
887 | 0 | } |
888 | 12.2k | fSuccessor = REF(cs); |
889 | 12.2k | } |
890 | 21.3k | else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart) |
891 | 13.9k | { |
892 | 13.9k | CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext); |
893 | 13.9k | if (cs == NULL) |
894 | 0 | { |
895 | 0 | RESTORE_MODEL(c, 0); |
896 | 0 | return; |
897 | 0 | } |
898 | 13.9k | fSuccessor = REF(cs); |
899 | 13.9k | } |
900 | | |
901 | 33.5k | if (--p->OrderFall == 0) |
902 | 2.70k | { |
903 | 2.70k | successor = fSuccessor; |
904 | 2.70k | p->Text -= (p->MaxContext != p->MinContext); |
905 | 2.70k | } |
906 | | #ifdef PPMD8_FREEZE_SUPPORT |
907 | | else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) |
908 | | { |
909 | | successor = fSuccessor; |
910 | | RESET_TEXT(0); |
911 | | p->OrderFall = 0; |
912 | | } |
913 | | #endif |
914 | | |
915 | 33.5k | s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq; |
916 | 33.5k | flag = (Byte)(0x08 * (fSymbol >= 0x40)); |
917 | | |
918 | 53.3k | for (; c != p->MinContext; c = SUFFIX(c)) |
919 | 19.7k | { |
920 | 19.7k | unsigned ns1; |
921 | 19.7k | UInt32 cf, sf; |
922 | 19.7k | if ((ns1 = c->NumStats) != 0) |
923 | 4.99k | { |
924 | 4.99k | if ((ns1 & 1) != 0) |
925 | 3.69k | { |
926 | | /* Expand for one UNIT */ |
927 | 3.69k | unsigned oldNU = (ns1 + 1) >> 1; |
928 | 3.69k | unsigned i = U2I(oldNU); |
929 | 3.69k | if (i != U2I(oldNU + 1)) |
930 | 3.68k | { |
931 | 3.68k | void *ptr = AllocUnits(p, i + 1); |
932 | 3.68k | void *oldPtr; |
933 | 3.68k | if (!ptr) |
934 | 0 | { |
935 | 0 | RESTORE_MODEL(c, CTX(fSuccessor)); |
936 | 0 | return; |
937 | 0 | } |
938 | 3.68k | oldPtr = STATS(c); |
939 | 3.68k | MyMem12Cpy(ptr, oldPtr, oldNU); |
940 | 3.68k | InsertNode(p, oldPtr, i); |
941 | 3.68k | c->Stats = STATS_REF(ptr); |
942 | 3.68k | } |
943 | 3.69k | } |
944 | 4.99k | c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns)); |
945 | 4.99k | } |
946 | 14.7k | else |
947 | 14.7k | { |
948 | 14.7k | CPpmd_State *s2 = (CPpmd_State*)AllocUnits(p, 0); |
949 | 14.7k | if (!s2) |
950 | 0 | { |
951 | 0 | RESTORE_MODEL(c, CTX(fSuccessor)); |
952 | 0 | return; |
953 | 0 | } |
954 | 14.7k | *s2 = *ONE_STATE(c); |
955 | 14.7k | c->Stats = REF(s2); |
956 | 14.7k | if (s2->Freq < MAX_FREQ / 4 - 1) |
957 | 13.7k | s2->Freq <<= 1; |
958 | 942 | else |
959 | 942 | s2->Freq = MAX_FREQ - 4; |
960 | 14.7k | c->SummFreq = (UInt16)(s2->Freq + p->InitEsc + (ns > 2)); |
961 | 14.7k | } |
962 | 19.7k | cf = 2 * fFreq * (c->SummFreq + 6); |
963 | 19.7k | sf = (UInt32)s0 + c->SummFreq; |
964 | 19.7k | if (cf < 6 * sf) |
965 | 10.1k | { |
966 | 10.1k | cf = 1 + (cf > sf) + (cf >= 4 * sf); |
967 | 10.1k | c->SummFreq += 4; |
968 | 10.1k | } |
969 | 9.52k | else |
970 | 9.52k | { |
971 | 9.52k | cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); |
972 | 9.52k | c->SummFreq = (UInt16)(c->SummFreq + cf); |
973 | 9.52k | } |
974 | 19.7k | { |
975 | 19.7k | CPpmd_State *s2 = STATS(c) + ns1 + 1; |
976 | 19.7k | SetSuccessor(s2, successor); |
977 | 19.7k | s2->Symbol = fSymbol; |
978 | 19.7k | s2->Freq = (Byte)cf; |
979 | 19.7k | c->Flags |= flag; |
980 | 19.7k | c->NumStats = (Byte)(ns1 + 1); |
981 | 19.7k | } |
982 | 19.7k | } |
983 | 33.5k | p->MaxContext = p->MinContext = CTX(fSuccessor); |
984 | 33.5k | } |
985 | | |
986 | | static void Rescale(CPpmd8 *p) |
987 | 1.55k | { |
988 | 1.55k | unsigned i, adder, sumFreq, escFreq; |
989 | 1.55k | CPpmd_State *stats = STATS(p->MinContext); |
990 | 1.55k | CPpmd_State *s = p->FoundState; |
991 | 1.55k | { |
992 | 1.55k | CPpmd_State tmp = *s; |
993 | 1.55k | for (; s != stats; s--) |
994 | 0 | s[0] = s[-1]; |
995 | 1.55k | *s = tmp; |
996 | 1.55k | } |
997 | 1.55k | escFreq = p->MinContext->SummFreq - s->Freq; |
998 | 1.55k | s->Freq += 4; |
999 | 1.55k | adder = (p->OrderFall != 0 |
1000 | | #ifdef PPMD8_FREEZE_SUPPORT |
1001 | | || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE |
1002 | | #endif |
1003 | 1.55k | ); |
1004 | 1.55k | s->Freq = (Byte)((s->Freq + adder) >> 1); |
1005 | 1.55k | sumFreq = s->Freq; |
1006 | | |
1007 | 1.55k | i = p->MinContext->NumStats; |
1008 | 1.55k | do |
1009 | 2.02k | { |
1010 | 2.02k | escFreq -= (++s)->Freq; |
1011 | 2.02k | s->Freq = (Byte)((s->Freq + adder) >> 1); |
1012 | 2.02k | sumFreq += s->Freq; |
1013 | 2.02k | if (s[0].Freq > s[-1].Freq) |
1014 | 204 | { |
1015 | 204 | CPpmd_State *s1 = s; |
1016 | 204 | CPpmd_State tmp = *s1; |
1017 | 204 | do |
1018 | 282 | s1[0] = s1[-1]; |
1019 | 282 | while (--s1 != stats && tmp.Freq > s1[-1].Freq); |
1020 | 204 | *s1 = tmp; |
1021 | 204 | } |
1022 | 2.02k | } |
1023 | 2.02k | while (--i); |
1024 | | |
1025 | 1.55k | if (s->Freq == 0) |
1026 | 392 | { |
1027 | 392 | unsigned numStats = p->MinContext->NumStats; |
1028 | 392 | unsigned n0, n1; |
1029 | 444 | do { i++; } while ((--s)->Freq == 0); |
1030 | 392 | escFreq += i; |
1031 | 392 | p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i); |
1032 | 392 | if (p->MinContext->NumStats == 0) |
1033 | 250 | { |
1034 | 250 | CPpmd_State tmp = *stats; |
1035 | 250 | tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq); |
1036 | 250 | if (tmp.Freq > MAX_FREQ / 3) |
1037 | 236 | tmp.Freq = MAX_FREQ / 3; |
1038 | 250 | InsertNode(p, stats, U2I((numStats + 2) >> 1)); |
1039 | 250 | p->MinContext->Flags = (Byte)((p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40)); |
1040 | 250 | *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; |
1041 | 250 | return; |
1042 | 250 | } |
1043 | 142 | n0 = (numStats + 2) >> 1; |
1044 | 142 | n1 = (p->MinContext->NumStats + 2) >> 1; |
1045 | 142 | if (n0 != n1) |
1046 | 88 | p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); |
1047 | 142 | p->MinContext->Flags &= ~0x08; |
1048 | 142 | p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40); |
1049 | 142 | i = p->MinContext->NumStats; |
1050 | 276 | do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i); |
1051 | 142 | } |
1052 | 1.30k | p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); |
1053 | 1.30k | p->MinContext->Flags |= 0x4; |
1054 | 1.30k | p->FoundState = STATS(p->MinContext); |
1055 | 1.30k | } |
1056 | | |
1057 | | CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) |
1058 | 6.99k | { |
1059 | 6.99k | CPpmd_See *see; |
1060 | 6.99k | if (p->MinContext->NumStats != 0xFF) |
1061 | 2.02k | { |
1062 | 2.02k | see = p->See[(unsigned)p->NS2Indx[(unsigned)p->MinContext->NumStats + 2] - 3] + |
1063 | 2.02k | (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) + |
1064 | 2.02k | 2 * (unsigned)(2 * (unsigned)p->MinContext->NumStats < |
1065 | 2.02k | ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) + |
1066 | 2.02k | p->MinContext->Flags; |
1067 | 2.02k | { |
1068 | 2.02k | unsigned r = (see->Summ >> see->Shift); |
1069 | 2.02k | see->Summ = (UInt16)(see->Summ - r); |
1070 | 2.02k | *escFreq = r + (r == 0); |
1071 | 2.02k | } |
1072 | 2.02k | } |
1073 | 4.97k | else |
1074 | 4.97k | { |
1075 | 4.97k | see = &p->DummySee; |
1076 | 4.97k | *escFreq = 1; |
1077 | 4.97k | } |
1078 | 6.99k | return see; |
1079 | 6.99k | } |
1080 | | |
1081 | | static void NextContext(CPpmd8 *p) |
1082 | 1.22M | { |
1083 | 1.22M | CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); |
1084 | 1.22M | if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart) |
1085 | 1.19M | p->MinContext = p->MaxContext = c; |
1086 | 32.3k | else |
1087 | 32.3k | { |
1088 | 32.3k | UpdateModel(p); |
1089 | 32.3k | p->MinContext = p->MaxContext; |
1090 | 32.3k | } |
1091 | 1.22M | } |
1092 | | |
1093 | | void Ppmd8_Update1(CPpmd8 *p) |
1094 | 13.2k | { |
1095 | 13.2k | CPpmd_State *s = p->FoundState; |
1096 | 13.2k | s->Freq += 4; |
1097 | 13.2k | p->MinContext->SummFreq += 4; |
1098 | 13.2k | if (s[0].Freq > s[-1].Freq) |
1099 | 11.4k | { |
1100 | 11.4k | SwapStates(&s[0], &s[-1]); |
1101 | 11.4k | p->FoundState = --s; |
1102 | 11.4k | if (s->Freq > MAX_FREQ) |
1103 | 2 | Rescale(p); |
1104 | 11.4k | } |
1105 | 13.2k | NextContext(p); |
1106 | 13.2k | } |
1107 | | |
1108 | | void Ppmd8_Update1_0(CPpmd8 *p) |
1109 | 23.6k | { |
1110 | 23.6k | p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq); |
1111 | 23.6k | p->RunLength += p->PrevSuccess; |
1112 | 23.6k | p->MinContext->SummFreq += 4; |
1113 | 23.6k | if ((p->FoundState->Freq += 4) > MAX_FREQ) |
1114 | 1.55k | Rescale(p); |
1115 | 23.6k | NextContext(p); |
1116 | 23.6k | } |
1117 | | |
1118 | | void Ppmd8_UpdateBin(CPpmd8 *p) |
1119 | 1.19M | { |
1120 | 1.19M | p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196)); |
1121 | 1.19M | p->PrevSuccess = 1; |
1122 | 1.19M | p->RunLength++; |
1123 | 1.19M | NextContext(p); |
1124 | 1.19M | } |
1125 | | |
1126 | | void Ppmd8_Update2(CPpmd8 *p) |
1127 | 5.79k | { |
1128 | 5.79k | p->MinContext->SummFreq += 4; |
1129 | 5.79k | if ((p->FoundState->Freq += 4) > MAX_FREQ) |
1130 | 0 | Rescale(p); |
1131 | 5.79k | p->RunLength = p->InitRL; |
1132 | 5.79k | UpdateModel(p); |
1133 | 5.79k | p->MinContext = p->MaxContext; |
1134 | 5.79k | } |
1135 | | |
1136 | | /* Ppmd8Dec.c -- PPMdI Decoder |
1137 | | 2010-04-16 : Igor Pavlov : Public domain |
1138 | | This code is based on: |
1139 | | PPMd var.I (2002): Dmitry Shkarin : Public domain |
1140 | | Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ |
1141 | | |
1142 | | Bool Ppmd8_RangeDec_Init(CPpmd8 *p) |
1143 | 1.61k | { |
1144 | 1.61k | unsigned i; |
1145 | 1.61k | p->Low = 0; |
1146 | 1.61k | p->Range = 0xFFFFFFFF; |
1147 | 1.61k | p->Code = 0; |
1148 | 8.05k | for (i = 0; i < 4; i++) |
1149 | 6.44k | p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); |
1150 | 1.61k | return (p->Code < 0xFFFFFFFF); |
1151 | 1.61k | } |
1152 | | |
1153 | | static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total) |
1154 | 46.1k | { |
1155 | 46.1k | return p->Code / (p->Range /= total); |
1156 | 46.1k | } |
1157 | | |
1158 | | static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size) |
1159 | 1.24M | { |
1160 | 1.24M | start *= p->Range; |
1161 | 1.24M | p->Low += start; |
1162 | 1.24M | p->Code -= start; |
1163 | 1.24M | p->Range *= size; |
1164 | | |
1165 | 1.26M | while ((p->Low ^ (p->Low + p->Range)) < kTop || |
1166 | 1.24M | (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) |
1167 | 20.6k | { |
1168 | 20.6k | p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); |
1169 | 20.6k | p->Range <<= 8; |
1170 | 20.6k | p->Low <<= 8; |
1171 | 20.6k | } |
1172 | 1.24M | } |
1173 | | |
1174 | 1.42M | #define MASK(sym) ((signed char *)charMask)[sym] |
1175 | | |
1176 | | int Ppmd8_DecodeSymbol(CPpmd8 *p) |
1177 | 1.23M | { |
1178 | 1.23M | size_t charMask[256 / sizeof(size_t)]; |
1179 | 1.23M | if (p->MinContext->NumStats != 0) |
1180 | 39.1k | { |
1181 | 39.1k | CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); |
1182 | 39.1k | unsigned i; |
1183 | 39.1k | UInt32 count, hiCnt; |
1184 | 39.1k | if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) |
1185 | 23.6k | { |
1186 | 23.6k | Byte symbol; |
1187 | 23.6k | RangeDec_Decode(p, 0, s->Freq); |
1188 | 23.6k | p->FoundState = s; |
1189 | 23.6k | symbol = s->Symbol; |
1190 | 23.6k | Ppmd8_Update1_0(p); |
1191 | 23.6k | return symbol; |
1192 | 23.6k | } |
1193 | 15.4k | p->PrevSuccess = 0; |
1194 | 15.4k | i = p->MinContext->NumStats; |
1195 | 15.4k | do |
1196 | 1.56M | { |
1197 | 1.56M | if ((hiCnt += (++s)->Freq) > count) |
1198 | 13.2k | { |
1199 | 13.2k | Byte symbol; |
1200 | 13.2k | RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); |
1201 | 13.2k | p->FoundState = s; |
1202 | 13.2k | symbol = s->Symbol; |
1203 | 13.2k | Ppmd8_Update1(p); |
1204 | 13.2k | return symbol; |
1205 | 13.2k | } |
1206 | 1.56M | } |
1207 | 1.55M | while (--i); |
1208 | 2.23k | if (count >= p->MinContext->SummFreq) |
1209 | 262 | return -2; |
1210 | 1.97k | RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt); |
1211 | 1.97k | PPMD_SetAllBitsIn256Bytes(charMask); |
1212 | 1.97k | MASK(s->Symbol) = 0; |
1213 | 1.97k | i = p->MinContext->NumStats; |
1214 | 127k | do { MASK((--s)->Symbol) = 0; } while (--i); |
1215 | 1.97k | } |
1216 | 1.19M | else |
1217 | 1.19M | { |
1218 | 1.19M | UInt16 *prob = Ppmd8_GetBinSumm(p); |
1219 | 1.19M | if (((p->Code / (p->Range >>= 14)) < *prob)) |
1220 | 1.19M | { |
1221 | 1.19M | Byte symbol; |
1222 | 1.19M | RangeDec_Decode(p, 0, *prob); |
1223 | 1.19M | *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); |
1224 | 1.19M | symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; |
1225 | 1.19M | Ppmd8_UpdateBin(p); |
1226 | 1.19M | return symbol; |
1227 | 1.19M | } |
1228 | 4.53k | RangeDec_Decode(p, *prob, (1 << 14) - *prob); |
1229 | 4.53k | *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); |
1230 | 4.53k | p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; |
1231 | 4.53k | PPMD_SetAllBitsIn256Bytes(charMask); |
1232 | 4.53k | MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; |
1233 | 4.53k | p->PrevSuccess = 0; |
1234 | 4.53k | } |
1235 | 6.50k | for (;;) |
1236 | 7.51k | { |
1237 | 7.51k | CPpmd_State *ps[256], *s; |
1238 | 7.51k | UInt32 freqSum, count, hiCnt; |
1239 | 7.51k | CPpmd_See *see; |
1240 | 7.51k | unsigned i, num, numMasked = p->MinContext->NumStats; |
1241 | 7.51k | do |
1242 | 21.2k | { |
1243 | 21.2k | p->OrderFall++; |
1244 | 21.2k | if (!p->MinContext->Suffix) |
1245 | 522 | return -1; |
1246 | 20.7k | p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); |
1247 | 20.7k | } |
1248 | 20.7k | while (p->MinContext->NumStats == numMasked); |
1249 | 6.99k | hiCnt = 0; |
1250 | 6.99k | s = Ppmd8_GetStats(p, p->MinContext); |
1251 | 6.99k | i = 0; |
1252 | 6.99k | num = p->MinContext->NumStats - numMasked; |
1253 | 6.99k | do |
1254 | 1.27M | { |
1255 | 1.27M | int k = (int)(MASK(s->Symbol)); |
1256 | 1.27M | hiCnt += (s->Freq & k); |
1257 | 1.27M | ps[i] = s++; |
1258 | 1.27M | i -= k; |
1259 | 1.27M | } |
1260 | 1.27M | while (i != num); |
1261 | | |
1262 | 6.99k | see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); |
1263 | 6.99k | freqSum += hiCnt; |
1264 | 6.99k | count = RangeDec_GetThreshold(p, freqSum); |
1265 | | |
1266 | 6.99k | if (count < hiCnt) |
1267 | 5.79k | { |
1268 | 5.79k | Byte symbol; |
1269 | 5.79k | CPpmd_State **pps = ps; |
1270 | 585k | for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); |
1271 | 5.79k | s = *pps; |
1272 | 5.79k | RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); |
1273 | 5.79k | Ppmd_See_Update(see); |
1274 | 5.79k | p->FoundState = s; |
1275 | 5.79k | symbol = s->Symbol; |
1276 | 5.79k | Ppmd8_Update2(p); |
1277 | 5.79k | return symbol; |
1278 | 5.79k | } |
1279 | 1.20k | if (count >= freqSum) |
1280 | 194 | return -2; |
1281 | 1.01k | RangeDec_Decode(p, hiCnt, freqSum - hiCnt); |
1282 | 1.01k | see->Summ = (UInt16)(see->Summ + freqSum); |
1283 | 9.80k | do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); |
1284 | 1.01k | } |
1285 | 6.50k | } |
1286 | | |
1287 | | /* H->I changes: |
1288 | | NS2Indx |
1289 | | GlewCount, and Glue method |
1290 | | BinSum |
1291 | | See / EscFreq |
1292 | | CreateSuccessors updates more suffix contexts |
1293 | | UpdateModel consts. |
1294 | | PrevSuccess Update |
1295 | | */ |
1296 | | |
1297 | | const IPpmd8 __archive_ppmd8_functions = |
1298 | | { |
1299 | | &Ppmd8_Construct, |
1300 | | &Ppmd8_Alloc, |
1301 | | &Ppmd8_Free, |
1302 | | &Ppmd8_Init, |
1303 | | &Ppmd8_RangeDec_Init, |
1304 | | &Ppmd8_DecodeSymbol, |
1305 | | }; |