/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 | 42.2M | #define MAX_FREQ 124 |
19 | 29.9M | #define UNIT_SIZE 12 |
20 | | |
21 | 9.00M | #define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) |
22 | 14.4M | #define U2I(nu) (p->Units2Indx[(nu) - 1]) |
23 | 11.7M | #define I2U(indx) (p->Indx2Units[indx]) |
24 | | |
25 | | #ifdef PPMD_32BIT |
26 | | #define REF(ptr) (ptr) |
27 | | #else |
28 | 98.9M | #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) |
29 | | #endif |
30 | | |
31 | 6.98M | #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) |
32 | | |
33 | 118M | #define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) |
34 | 58.4M | #define STATS(ctx) Ppmd8_GetStats(p, ctx) |
35 | 63.4M | #define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) |
36 | 67.0M | #define SUFFIX(ctx) CTX((ctx)->Suffix) |
37 | | |
38 | 68.7M | #define kTop (1 << 24) |
39 | 59.4M | #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 | 11.2M | #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs))) |
64 | | #endif |
65 | | |
66 | 12.6M | #define EMPTY_NODE 0xFFFFFFFF |
67 | | |
68 | | void Ppmd8_Construct(CPpmd8 *p) |
69 | 1.37k | { |
70 | 1.37k | unsigned i, k, m; |
71 | | |
72 | 1.37k | p->Base = 0; |
73 | | |
74 | 53.7k | for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) |
75 | 52.3k | { |
76 | 52.3k | unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); |
77 | 176k | do { p->Units2Indx[k++] = (Byte)i; } while (--step); |
78 | 52.3k | p->Indx2Units[i] = (Byte)k; |
79 | 52.3k | } |
80 | | |
81 | 1.37k | p->NS2BSIndx[0] = (0 << 1); |
82 | 1.37k | p->NS2BSIndx[1] = (1 << 1); |
83 | 1.37k | memset(p->NS2BSIndx + 2, (2 << 1), 9); |
84 | 1.37k | memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); |
85 | | |
86 | 8.26k | for (i = 0; i < 5; i++) |
87 | 6.89k | p->NS2Indx[i] = (Byte)i; |
88 | 352k | for (m = i, k = 1; i < 260; i++) |
89 | 351k | { |
90 | 351k | p->NS2Indx[i] = (Byte)m; |
91 | 351k | if (--k == 0) |
92 | 30.3k | k = (++m) - 4; |
93 | 351k | } |
94 | 1.37k | } |
95 | | |
96 | | void Ppmd8_Free(CPpmd8 *p) |
97 | 2.70k | { |
98 | 2.70k | free(p->Base); |
99 | 2.70k | p->Size = 0; |
100 | 2.70k | p->Base = 0; |
101 | 2.70k | } |
102 | | |
103 | | Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size) |
104 | 1.35k | { |
105 | 1.35k | if (p->Base == 0 || p->Size != size) |
106 | 1.35k | { |
107 | 1.35k | Ppmd8_Free(p); |
108 | 1.35k | p->AlignOffset = |
109 | | #ifdef PPMD_32BIT |
110 | | (4 - size) & 3; |
111 | | #else |
112 | 1.35k | 4 - (size & 3); |
113 | 1.35k | #endif |
114 | 1.35k | if ((p->Base = malloc(p->AlignOffset + size)) == 0) |
115 | 0 | return False; |
116 | 1.35k | p->Size = size; |
117 | 1.35k | } |
118 | 1.35k | return True; |
119 | 1.35k | } |
120 | | |
121 | | static void InsertNode(CPpmd8 *p, void *node, unsigned indx) |
122 | 10.4M | { |
123 | 10.4M | ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; |
124 | 10.4M | ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; |
125 | 10.4M | ((CPpmd8_Node *)node)->NU = I2U(indx); |
126 | 10.4M | p->FreeList[indx] = REF(node); |
127 | 10.4M | p->Stamps[indx]++; |
128 | 10.4M | } |
129 | | |
130 | | static void *RemoveNode(CPpmd8 *p, unsigned indx) |
131 | 4.51M | { |
132 | 4.51M | CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); |
133 | 4.51M | p->FreeList[indx] = node->Next; |
134 | 4.51M | p->Stamps[indx]--; |
135 | 4.51M | return node; |
136 | 4.51M | } |
137 | | |
138 | | static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) |
139 | 198k | { |
140 | 198k | unsigned i, nu = I2U(oldIndx) - I2U(newIndx); |
141 | 198k | ptr = (Byte *)ptr + U2B(I2U(newIndx)); |
142 | 198k | if (I2U(i = U2I(nu)) != nu) |
143 | 28.7k | { |
144 | 28.7k | unsigned k = I2U(--i); |
145 | 28.7k | InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); |
146 | 28.7k | } |
147 | 198k | InsertNode(p, ptr, i); |
148 | 198k | } |
149 | | |
150 | | static void GlueFreeBlocks(CPpmd8 *p) |
151 | 444 | { |
152 | 444 | CPpmd8_Node_Ref head = 0; |
153 | 444 | CPpmd8_Node_Ref *prev = &head; |
154 | 444 | unsigned i; |
155 | | |
156 | 444 | p->GlueCount = 1 << 13; |
157 | 444 | 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 | 444 | if (p->LoUnit != p->HiUnit) |
162 | 30 | ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; |
163 | | |
164 | | /* Glue free blocks */ |
165 | 17.3k | for (i = 0; i < PPMD_NUM_INDEXES; i++) |
166 | 16.8k | { |
167 | 16.8k | CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; |
168 | 16.8k | p->FreeList[i] = 0; |
169 | 1.82M | while (next != 0) |
170 | 1.81M | { |
171 | 1.81M | CPpmd8_Node *node = NODE(next); |
172 | 1.81M | if (node->NU != 0) |
173 | 960k | { |
174 | 960k | CPpmd8_Node *node2; |
175 | 960k | *prev = next; |
176 | 960k | prev = &(node->Next); |
177 | 2.17M | while ((node2 = node + node->NU)->Stamp == EMPTY_NODE) |
178 | 1.21M | { |
179 | 1.21M | node->NU += node2->NU; |
180 | 1.21M | node2->NU = 0; |
181 | 1.21M | } |
182 | 960k | } |
183 | 1.81M | next = node->Next; |
184 | 1.81M | } |
185 | 16.8k | } |
186 | 444 | *prev = 0; |
187 | | |
188 | | /* Fill lists of free blocks */ |
189 | 961k | while (head != 0) |
190 | 960k | { |
191 | 960k | CPpmd8_Node *node = NODE(head); |
192 | 960k | unsigned nu; |
193 | 960k | head = node->Next; |
194 | 960k | nu = node->NU; |
195 | 960k | if (nu == 0) |
196 | 365k | continue; |
197 | 595k | for (; nu > 128; nu -= 128, node += 128) |
198 | 12 | InsertNode(p, node, PPMD_NUM_INDEXES - 1); |
199 | 595k | if (I2U(i = U2I(nu)) != nu) |
200 | 77.0k | { |
201 | 77.0k | unsigned k = I2U(--i); |
202 | 77.0k | InsertNode(p, node + k, nu - k - 1); |
203 | 77.0k | } |
204 | 595k | InsertNode(p, node, i); |
205 | 595k | } |
206 | 444 | } |
207 | | |
208 | | static void *AllocUnitsRare(CPpmd8 *p, unsigned indx) |
209 | 2.32M | { |
210 | 2.32M | unsigned i; |
211 | 2.32M | void *retVal; |
212 | 2.32M | if (p->GlueCount == 0) |
213 | 444 | { |
214 | 444 | GlueFreeBlocks(p); |
215 | 444 | if (p->FreeList[indx] != 0) |
216 | 122 | return RemoveNode(p, indx); |
217 | 444 | } |
218 | 2.32M | i = indx; |
219 | 2.32M | do |
220 | 80.8M | { |
221 | 80.8M | if (++i == PPMD_NUM_INDEXES) |
222 | 2.12M | { |
223 | 2.12M | UInt32 numBytes = U2B(I2U(indx)); |
224 | 2.12M | p->GlueCount--; |
225 | 2.12M | return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); |
226 | 2.12M | } |
227 | 80.8M | } |
228 | 78.6M | while (p->FreeList[i] == 0); |
229 | 195k | retVal = RemoveNode(p, i); |
230 | 195k | SplitBlock(p, retVal, i, indx); |
231 | 195k | return retVal; |
232 | 2.32M | } |
233 | | |
234 | | static void *AllocUnits(CPpmd8 *p, unsigned indx) |
235 | 10.0M | { |
236 | 10.0M | UInt32 numBytes; |
237 | 10.0M | if (p->FreeList[indx] != 0) |
238 | 3.35M | return RemoveNode(p, indx); |
239 | 6.65M | numBytes = U2B(I2U(indx)); |
240 | 6.65M | if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) |
241 | 5.99M | { |
242 | 5.99M | void *retVal = p->LoUnit; |
243 | 5.99M | p->LoUnit += numBytes; |
244 | 5.99M | return retVal; |
245 | 5.99M | } |
246 | 658k | return AllocUnitsRare(p, indx); |
247 | 6.65M | } |
248 | | |
249 | 4.00M | #define MyMem12Cpy(dest, src, num) do { \ |
250 | 4.00M | UInt32 *d = (UInt32 *)dest; \ |
251 | 4.00M | const UInt32 *z = (const UInt32 *)src; \ |
252 | 4.00M | UInt32 n = num; \ |
253 | 7.11M | do { \ |
254 | 7.11M | d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; \ |
255 | 7.11M | } while (--n); \ |
256 | 4.00M | } while (0) |
257 | | |
258 | | static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU) |
259 | 640k | { |
260 | 640k | unsigned i0 = U2I(oldNU); |
261 | 640k | unsigned i1 = U2I(newNU); |
262 | 640k | if (i0 == i1) |
263 | 90.5k | return oldPtr; |
264 | 549k | if (p->FreeList[i1] != 0) |
265 | 546k | { |
266 | 546k | void *ptr = RemoveNode(p, i1); |
267 | 546k | MyMem12Cpy(ptr, oldPtr, newNU); |
268 | 546k | InsertNode(p, oldPtr, i0); |
269 | 546k | return ptr; |
270 | 546k | } |
271 | 3.22k | SplitBlock(p, oldPtr, i0, i1); |
272 | 3.22k | return oldPtr; |
273 | 549k | } |
274 | | |
275 | | static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) |
276 | 2.40M | { |
277 | 2.40M | InsertNode(p, ptr, U2I(nu)); |
278 | 2.40M | } |
279 | | |
280 | | static void SpecialFreeUnit(CPpmd8 *p, void *ptr) |
281 | 3.13M | { |
282 | 3.13M | if ((Byte *)ptr != p->UnitsStart) |
283 | 3.13M | InsertNode(p, ptr, 0); |
284 | 256 | else |
285 | 256 | { |
286 | | #ifdef PPMD8_FREEZE_SUPPORT |
287 | | *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */ |
288 | | #endif |
289 | 256 | p->UnitsStart += UNIT_SIZE; |
290 | 256 | } |
291 | 3.13M | } |
292 | | |
293 | | static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) |
294 | 3.58M | { |
295 | 3.58M | unsigned indx = U2I(nu); |
296 | 3.58M | void *ptr; |
297 | 3.58M | if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx]) |
298 | 3.52M | return oldPtr; |
299 | 68.4k | ptr = RemoveNode(p, indx); |
300 | 68.4k | MyMem12Cpy(ptr, oldPtr, nu); |
301 | 68.4k | if ((Byte*)oldPtr != p->UnitsStart) |
302 | 68.3k | InsertNode(p, oldPtr, indx); |
303 | 62 | else |
304 | 62 | p->UnitsStart += U2B(I2U(indx)); |
305 | 68.4k | return ptr; |
306 | 3.58M | } |
307 | | |
308 | | static void ExpandTextArea(CPpmd8 *p) |
309 | 208 | { |
310 | 208 | UInt32 count[PPMD_NUM_INDEXES]; |
311 | 208 | unsigned i; |
312 | 208 | memset(count, 0, sizeof(count)); |
313 | 208 | if (p->LoUnit != p->HiUnit) |
314 | 0 | ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; |
315 | | |
316 | 208 | { |
317 | 208 | CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart; |
318 | 2.33k | for (; node->Stamp == EMPTY_NODE; node += node->NU) |
319 | 2.12k | { |
320 | 2.12k | node->Stamp = 0; |
321 | 2.12k | count[U2I(node->NU)]++; |
322 | 2.12k | } |
323 | 208 | p->UnitsStart = (Byte *)node; |
324 | 208 | } |
325 | | |
326 | 8.11k | for (i = 0; i < PPMD_NUM_INDEXES; i++) |
327 | 7.90k | { |
328 | 7.90k | CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i]; |
329 | 3.99M | while (count[i] != 0) |
330 | 3.98M | { |
331 | 3.98M | CPpmd8_Node *node = NODE(*next); |
332 | 3.98M | while (node->Stamp == 0) |
333 | 2.12k | { |
334 | 2.12k | *next = node->Next; |
335 | 2.12k | node = NODE(*next); |
336 | 2.12k | p->Stamps[i]--; |
337 | 2.12k | if (--count[i] == 0) |
338 | 286 | break; |
339 | 2.12k | } |
340 | 3.98M | next = &node->Next; |
341 | 3.98M | } |
342 | 7.90k | } |
343 | 208 | } |
344 | | |
345 | 63.5M | #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 | 62.9M | { |
349 | | #ifdef __clang_analyzer__ |
350 | | assert(p); |
351 | | #endif |
352 | 62.9M | (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); |
353 | 62.9M | (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); |
354 | 62.9M | } |
355 | | |
356 | 1.69k | #define RESET_TEXT(offs) do { \ |
357 | 1.69k | p->Text = p->Base + p->AlignOffset + (offs); \ |
358 | 1.69k | } while (0) |
359 | | |
360 | | static void RestartModel(CPpmd8 *p) |
361 | 1.42k | { |
362 | 1.42k | unsigned i, k, m, r; |
363 | | |
364 | 1.42k | memset(p->FreeList, 0, sizeof(p->FreeList)); |
365 | 1.42k | memset(p->Stamps, 0, sizeof(p->Stamps)); |
366 | 1.42k | RESET_TEXT(0); |
367 | 1.42k | p->HiUnit = p->Text + p->Size; |
368 | 1.42k | p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; |
369 | 1.42k | p->GlueCount = 0; |
370 | | |
371 | 1.42k | p->OrderFall = p->MaxOrder; |
372 | 1.42k | p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; |
373 | 1.42k | p->PrevSuccess = 0; |
374 | | |
375 | 1.42k | p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ |
376 | 1.42k | p->MinContext->Suffix = 0; |
377 | 1.42k | p->MinContext->NumStats = 255; |
378 | 1.42k | p->MinContext->Flags = 0; |
379 | 1.42k | p->MinContext->SummFreq = 256 + 1; |
380 | 1.42k | p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ |
381 | 1.42k | p->LoUnit += U2B(256 / 2); |
382 | 1.42k | p->MinContext->Stats = REF(p->FoundState); |
383 | 364k | for (i = 0; i < 256; i++) |
384 | 363k | { |
385 | 363k | CPpmd_State *s = &p->FoundState[i]; |
386 | 363k | s->Symbol = (Byte)i; |
387 | 363k | s->Freq = 1; |
388 | 363k | SetSuccessor(s, 0); |
389 | 363k | } |
390 | | |
391 | 36.9k | for (i = m = 0; m < 25; m++) |
392 | 35.5k | { |
393 | 340k | while (p->NS2Indx[i] == m) |
394 | 305k | i++; |
395 | 319k | for (k = 0; k < 8; k++) |
396 | 284k | { |
397 | 284k | UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1)); |
398 | 284k | UInt16 *dest = p->BinSumm[m] + k; |
399 | 2.55M | for (r = 0; r < 64; r += 8) |
400 | 2.27M | dest[r] = val; |
401 | 284k | } |
402 | 35.5k | } |
403 | | |
404 | 35.5k | for (i = m = 0; m < 24; m++) |
405 | 34.0k | { |
406 | 396k | while (p->NS2Indx[i + 3] == m + 3) |
407 | 362k | i++; |
408 | 1.12M | for (k = 0; k < 32; k++) |
409 | 1.09M | { |
410 | 1.09M | CPpmd_See *s = &p->See[m][k]; |
411 | 1.09M | s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4)); |
412 | 1.09M | s->Count = 7; |
413 | 1.09M | } |
414 | 34.0k | } |
415 | 1.42k | } |
416 | | |
417 | | void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) |
418 | 1.35k | { |
419 | 1.35k | p->MaxOrder = maxOrder; |
420 | 1.35k | p->RestoreMethod = restoreMethod; |
421 | 1.35k | RestartModel(p); |
422 | 1.35k | p->DummySee.Shift = PPMD_PERIOD_BITS; |
423 | 1.35k | p->DummySee.Summ = 0; /* unused */ |
424 | 1.35k | p->DummySee.Count = 64; /* unused */ |
425 | 1.35k | } |
426 | | |
427 | | static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale) |
428 | 629k | { |
429 | 629k | unsigned i = ctx->NumStats, escFreq, sumFreq, flags; |
430 | 629k | CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); |
431 | 629k | 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 | 629k | flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40); |
437 | 629k | escFreq = ctx->SummFreq - s->Freq; |
438 | 629k | sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale)); |
439 | 629k | do |
440 | 1.50M | { |
441 | 1.50M | escFreq -= (++s)->Freq; |
442 | 1.50M | sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale)); |
443 | 1.50M | flags |= 0x08 * (s->Symbol >= 0x40); |
444 | 1.50M | } |
445 | 1.50M | while (--i); |
446 | 629k | ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); |
447 | 629k | ctx->Flags = (Byte)flags; |
448 | 629k | } |
449 | | |
450 | | static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) |
451 | 8.61M | { |
452 | 8.61M | CPpmd_State tmp = *t1; |
453 | 8.61M | *t1 = *t2; |
454 | 8.61M | *t2 = tmp; |
455 | 8.61M | } |
456 | | |
457 | | static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order) |
458 | 12.0M | { |
459 | 12.0M | int i; |
460 | 12.0M | unsigned tmp; |
461 | 12.0M | CPpmd_State *s; |
462 | | |
463 | 12.0M | if (!ctx->NumStats) |
464 | 8.50M | { |
465 | 8.50M | s = ONE_STATE(ctx); |
466 | 8.50M | if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart) |
467 | 8.44M | { |
468 | 8.44M | if (order < p->MaxOrder) |
469 | 7.35M | SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); |
470 | 1.09M | else |
471 | 1.09M | SetSuccessor(s, 0); |
472 | 8.44M | if (SUCCESSOR(s) || order <= 9) /* O_BOUND */ |
473 | 6.32M | return REF(ctx); |
474 | 8.44M | } |
475 | 2.17M | SpecialFreeUnit(p, ctx); |
476 | 2.17M | return 0; |
477 | 8.50M | } |
478 | | |
479 | 3.58M | ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1)); |
480 | | |
481 | 13.7M | for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--) |
482 | 10.1M | if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart) |
483 | 5.21M | { |
484 | 5.21M | CPpmd_State *s2 = STATS(ctx) + (i--); |
485 | 5.21M | SetSuccessor(s, 0); |
486 | 5.21M | SwapStates(s, s2); |
487 | 5.21M | } |
488 | 4.93M | else if (order < p->MaxOrder) |
489 | 4.73M | SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); |
490 | 197k | else |
491 | 197k | SetSuccessor(s, 0); |
492 | | |
493 | 3.58M | if (i != ctx->NumStats && order) |
494 | 3.03M | { |
495 | 3.03M | ctx->NumStats = (Byte)i; |
496 | 3.03M | s = STATS(ctx); |
497 | 3.03M | if (i < 0) |
498 | 963k | { |
499 | 963k | FreeUnits(p, s, tmp); |
500 | 963k | SpecialFreeUnit(p, ctx); |
501 | 963k | return 0; |
502 | 963k | } |
503 | 2.07M | if (i == 0) |
504 | 1.44M | { |
505 | 1.44M | ctx->Flags = (Byte)((ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40)); |
506 | 1.44M | *ONE_STATE(ctx) = *s; |
507 | 1.44M | FreeUnits(p, s, tmp); |
508 | | /* 9.31: the code was fixed. It's was not BUG, if Freq <= MAX_FREQ = 124 */ |
509 | 1.44M | ONE_STATE(ctx)->Freq = (Byte)(((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3); |
510 | 1.44M | } |
511 | 628k | else |
512 | 628k | Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i); |
513 | 2.07M | } |
514 | 2.62M | return REF(ctx); |
515 | 3.58M | } |
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 | 416 | { |
551 | 416 | UInt32 v = 0; |
552 | 416 | unsigned i; |
553 | 16.2k | for (i = 0; i < PPMD_NUM_INDEXES; i++) |
554 | 15.8k | v += p->Stamps[i] * I2U(i); |
555 | 416 | return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); |
556 | 416 | } |
557 | | |
558 | | #ifdef PPMD8_FREEZE_SUPPORT |
559 | | #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) |
560 | | #else |
561 | 276 | #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 | 276 | { |
570 | 276 | CTX_PTR c; |
571 | 276 | CPpmd_State *s; |
572 | 276 | RESET_TEXT(0); |
573 | 776 | for (c = p->MaxContext; c != c1; c = SUFFIX(c)) |
574 | 500 | if (--(c->NumStats) == 0) |
575 | 216 | { |
576 | 216 | s = STATS(c); |
577 | 216 | c->Flags = (Byte)((c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40)); |
578 | 216 | *ONE_STATE(c) = *s; |
579 | 216 | SpecialFreeUnit(p, s); |
580 | 216 | ONE_STATE(c)->Freq = (Byte)(((unsigned)ONE_STATE(c)->Freq + 11) >> 3); |
581 | 216 | } |
582 | 284 | else |
583 | 284 | Refresh(p, c, (c->NumStats+3) >> 1, 0); |
584 | | |
585 | 768 | for (; c != p->MinContext; c = SUFFIX(c)) |
586 | 492 | if (!c->NumStats) |
587 | 146 | ONE_STATE(c)->Freq = (Byte)(ONE_STATE(c)->Freq - (ONE_STATE(c)->Freq >> 1)); |
588 | 346 | else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats) |
589 | 44 | 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 | 276 | if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) |
609 | 68 | RestartModel(p); |
610 | 208 | else |
611 | 208 | { |
612 | 2.11k | while (p->MaxContext->Suffix) |
613 | 1.90k | p->MaxContext = SUFFIX(p->MaxContext); |
614 | 208 | do |
615 | 208 | { |
616 | 208 | CutOff(p, p->MaxContext, 0); |
617 | 208 | ExpandTextArea(p); |
618 | 208 | } |
619 | 208 | while (GetUsedMemory(p) > 3 * (p->Size >> 2)); |
620 | 208 | p->GlueCount = 0; |
621 | 208 | p->OrderFall = p->MaxOrder; |
622 | 208 | } |
623 | 276 | } |
624 | | |
625 | | static CTX_PTR CreateSuccessors(CPpmd8 *p, Bool skip, CPpmd_State *s1, CTX_PTR c) |
626 | 6.50M | { |
627 | 6.50M | CPpmd_State upState; |
628 | 6.50M | Byte flags; |
629 | 6.50M | CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); |
630 | | /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ |
631 | 6.50M | CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; |
632 | 6.50M | unsigned numPs = 0; |
633 | | |
634 | | #ifdef __clang_analyzer__ |
635 | | memset(ps, 0, sizeof(ps)); |
636 | | #endif |
637 | | |
638 | | |
639 | 6.50M | if (!skip) |
640 | 4.26M | ps[numPs++] = p->FoundState; |
641 | | |
642 | 25.1M | while (c->Suffix) |
643 | 25.0M | { |
644 | 25.0M | CPpmd_Void_Ref successor; |
645 | 25.0M | CPpmd_State *s; |
646 | 25.0M | c = SUFFIX(c); |
647 | 25.0M | if (s1) |
648 | 6.44M | { |
649 | 6.44M | s = s1; |
650 | 6.44M | s1 = NULL; |
651 | 6.44M | } |
652 | 18.6M | else if (c->NumStats != 0) |
653 | 6.40M | { |
654 | 41.9M | for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); |
655 | 6.40M | if (s->Freq < MAX_FREQ - 9) |
656 | 6.37M | { |
657 | 6.37M | s->Freq++; |
658 | 6.37M | c->SummFreq++; |
659 | 6.37M | } |
660 | 6.40M | } |
661 | 12.2M | else |
662 | 12.2M | { |
663 | 12.2M | s = ONE_STATE(c); |
664 | 12.2M | s->Freq = (Byte)(s->Freq + (!SUFFIX(c)->NumStats & (s->Freq < 24))); |
665 | 12.2M | } |
666 | 25.0M | successor = SUCCESSOR(s); |
667 | 25.0M | if (successor != upBranch) |
668 | 6.41M | { |
669 | 6.41M | c = CTX(successor); |
670 | 6.41M | if (numPs == 0) |
671 | 263k | return c; |
672 | 6.14M | break; |
673 | 6.41M | } |
674 | 18.6M | ps[numPs++] = s; |
675 | 18.6M | } |
676 | | |
677 | 6.24M | upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch); |
678 | 6.24M | SetSuccessor(&upState, upBranch + 1); |
679 | 6.24M | flags = (Byte)(0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40)); |
680 | | |
681 | 6.24M | if (c->NumStats == 0) |
682 | 2.55M | upState.Freq = ONE_STATE(c)->Freq; |
683 | 3.68M | else |
684 | 3.68M | { |
685 | 3.68M | UInt32 cf, s0; |
686 | 3.68M | CPpmd_State *s; |
687 | 17.4M | for (s = STATS(c); s->Symbol != upState.Symbol; s++); |
688 | 3.68M | cf = s->Freq - 1; |
689 | 3.68M | s0 = c->SummFreq - c->NumStats - cf; |
690 | 3.68M | upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); |
691 | 3.68M | } |
692 | | |
693 | 29.1M | while (numPs != 0) |
694 | 22.9M | { |
695 | | /* Create Child */ |
696 | 22.9M | CTX_PTR c1; /* = AllocContext(p); */ |
697 | 22.9M | if (p->HiUnit != p->LoUnit) |
698 | 20.9M | c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); |
699 | 2.01M | else if (p->FreeList[0] != 0) |
700 | 352k | c1 = (CTX_PTR)RemoveNode(p, 0); |
701 | 1.66M | else |
702 | 1.66M | { |
703 | 1.66M | c1 = (CTX_PTR)AllocUnitsRare(p, 0); |
704 | 1.66M | if (!c1) |
705 | 136 | return NULL; |
706 | 1.66M | } |
707 | 22.9M | c1->NumStats = 0; |
708 | 22.9M | c1->Flags = flags; |
709 | 22.9M | *ONE_STATE(c1) = upState; |
710 | 22.9M | c1->Suffix = REF(c); |
711 | 22.9M | SetSuccessor(ps[--numPs], REF(c1)); |
712 | 22.9M | c = c1; |
713 | 22.9M | } |
714 | | |
715 | 6.24M | return c; |
716 | 6.24M | } |
717 | | |
718 | | static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c) |
719 | 187k | { |
720 | 187k | CPpmd_State *s = NULL; |
721 | 187k | CTX_PTR c1 = c; |
722 | 187k | 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 | 187k | SetSuccessor(p->FoundState, upBranch); |
732 | 187k | p->OrderFall++; |
733 | | |
734 | 187k | for (;;) |
735 | 229k | { |
736 | 229k | if (s1) |
737 | 71.6k | { |
738 | 71.6k | c = SUFFIX(c); |
739 | 71.6k | s = s1; |
740 | 71.6k | s1 = NULL; |
741 | 71.6k | } |
742 | 158k | else |
743 | 158k | { |
744 | 158k | if (!c->Suffix) |
745 | 114k | { |
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 | 114k | return c; |
755 | 114k | } |
756 | 43.3k | c = SUFFIX(c); |
757 | 43.3k | if (c->NumStats) |
758 | 22.3k | { |
759 | 22.3k | if ((s = STATS(c))->Symbol != p->FoundState->Symbol) |
760 | 81.6k | do { s++; } while (s->Symbol != p->FoundState->Symbol); |
761 | 22.3k | if (s->Freq < MAX_FREQ - 9) |
762 | 22.2k | { |
763 | 22.2k | s->Freq += 2; |
764 | 22.2k | c->SummFreq += 2; |
765 | 22.2k | } |
766 | 22.3k | } |
767 | 21.0k | else |
768 | 21.0k | { |
769 | 21.0k | s = ONE_STATE(c); |
770 | 21.0k | s->Freq = (Byte)(s->Freq + (s->Freq < 32)); |
771 | 21.0k | } |
772 | 43.3k | } |
773 | 114k | if (SUCCESSOR(s)) |
774 | 72.2k | break; |
775 | | #ifdef PPMD8_FREEZE_SUPPORT |
776 | | ps[numPs++] = s; |
777 | | #endif |
778 | 42.6k | SetSuccessor(s, upBranch); |
779 | 42.6k | p->OrderFall++; |
780 | 42.6k | } |
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 | 72.2k | if (SUCCESSOR(s) <= upBranch) |
794 | 674 | { |
795 | 674 | CTX_PTR successor; |
796 | 674 | CPpmd_State *s2 = p->FoundState; |
797 | 674 | p->FoundState = s; |
798 | | |
799 | 674 | successor = CreateSuccessors(p, False, NULL, c); |
800 | 674 | if (successor == NULL) |
801 | 0 | SetSuccessor(s, 0); |
802 | 674 | else |
803 | 674 | SetSuccessor(s, REF(successor)); |
804 | 674 | p->FoundState = s2; |
805 | 674 | } |
806 | | |
807 | 72.2k | if (p->OrderFall == 1 && c1 == p->MaxContext) |
808 | 2.79k | { |
809 | 2.79k | SetSuccessor(p->FoundState, SUCCESSOR(s)); |
810 | 2.79k | p->Text--; |
811 | 2.79k | } |
812 | 72.2k | if (SUCCESSOR(s) == 0) |
813 | 0 | return NULL; |
814 | 72.2k | return CTX(SUCCESSOR(s)); |
815 | 72.2k | } |
816 | | |
817 | | static void UpdateModel(CPpmd8 *p) |
818 | 14.7M | { |
819 | 14.7M | CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); |
820 | 14.7M | CTX_PTR c; |
821 | 14.7M | unsigned s0, ns, fFreq = p->FoundState->Freq; |
822 | 14.7M | Byte flag, fSymbol = p->FoundState->Symbol; |
823 | 14.7M | CPpmd_State *s = NULL; |
824 | | |
825 | 14.7M | if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) |
826 | 12.6M | { |
827 | 12.6M | c = SUFFIX(p->MinContext); |
828 | | |
829 | 12.6M | if (c->NumStats == 0) |
830 | 6.30M | { |
831 | 6.30M | s = ONE_STATE(c); |
832 | 6.30M | if (s->Freq < 32) |
833 | 6.30M | s->Freq++; |
834 | 6.30M | } |
835 | 6.33M | else |
836 | 6.33M | { |
837 | 6.33M | s = STATS(c); |
838 | 6.33M | if (s->Symbol != p->FoundState->Symbol) |
839 | 4.17M | { |
840 | 66.8M | do { s++; } while (s->Symbol != p->FoundState->Symbol); |
841 | 4.17M | if (s[0].Freq >= s[-1].Freq) |
842 | 1.79M | { |
843 | 1.79M | SwapStates(&s[0], &s[-1]); |
844 | 1.79M | s--; |
845 | 1.79M | } |
846 | 4.17M | } |
847 | 6.33M | if (s->Freq < MAX_FREQ - 9) |
848 | 6.23M | { |
849 | 6.23M | s->Freq += 2; |
850 | 6.23M | c->SummFreq += 2; |
851 | 6.23M | } |
852 | 6.33M | } |
853 | 12.6M | } |
854 | | |
855 | 14.7M | c = p->MaxContext; |
856 | 14.7M | if (p->OrderFall == 0 && fSuccessor) |
857 | 2.24M | { |
858 | 2.24M | CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext); |
859 | 2.24M | if (cs == 0) |
860 | 92 | { |
861 | 92 | SetSuccessor(p->FoundState, 0); |
862 | 92 | RESTORE_MODEL(c, CTX(fSuccessor)); |
863 | 92 | } |
864 | 2.24M | else |
865 | 2.24M | { |
866 | 2.24M | SetSuccessor(p->FoundState, REF(cs)); |
867 | 2.24M | p->MaxContext = cs; |
868 | 2.24M | } |
869 | 2.24M | return; |
870 | 2.24M | } |
871 | | |
872 | 12.5M | *p->Text++ = p->FoundState->Symbol; |
873 | 12.5M | successor = REF(p->Text); |
874 | 12.5M | if (p->Text >= p->UnitsStart) |
875 | 6 | { |
876 | 6 | RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */ |
877 | 6 | return; |
878 | 6 | } |
879 | | |
880 | 12.5M | if (!fSuccessor) |
881 | 187k | { |
882 | 187k | CTX_PTR cs = ReduceOrder(p, s, p->MinContext); |
883 | 187k | if (cs == NULL) |
884 | 0 | { |
885 | 0 | RESTORE_MODEL(c, 0); |
886 | 0 | return; |
887 | 0 | } |
888 | 187k | fSuccessor = REF(cs); |
889 | 187k | } |
890 | 12.3M | else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart) |
891 | 4.26M | { |
892 | 4.26M | CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext); |
893 | 4.26M | if (cs == NULL) |
894 | 44 | { |
895 | 44 | RESTORE_MODEL(c, 0); |
896 | 44 | return; |
897 | 44 | } |
898 | 4.26M | fSuccessor = REF(cs); |
899 | 4.26M | } |
900 | | |
901 | 12.5M | if (--p->OrderFall == 0) |
902 | 1.06M | { |
903 | 1.06M | successor = fSuccessor; |
904 | 1.06M | p->Text -= (p->MaxContext != p->MinContext); |
905 | 1.06M | } |
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 | 12.5M | s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq; |
916 | 12.5M | flag = (Byte)(0x08 * (fSymbol >= 0x40)); |
917 | | |
918 | 24.8M | for (; c != p->MinContext; c = SUFFIX(c)) |
919 | 12.2M | { |
920 | 12.2M | unsigned ns1; |
921 | 12.2M | UInt32 cf, sf; |
922 | 12.2M | if ((ns1 = c->NumStats) != 0) |
923 | 5.67M | { |
924 | 5.67M | if ((ns1 & 1) != 0) |
925 | 3.60M | { |
926 | | /* Expand for one UNIT */ |
927 | 3.60M | unsigned oldNU = (ns1 + 1) >> 1; |
928 | 3.60M | unsigned i = U2I(oldNU); |
929 | 3.60M | if (i != U2I(oldNU + 1)) |
930 | 3.38M | { |
931 | 3.38M | void *ptr = AllocUnits(p, i + 1); |
932 | 3.38M | void *oldPtr; |
933 | 3.38M | if (!ptr) |
934 | 96 | { |
935 | 96 | RESTORE_MODEL(c, CTX(fSuccessor)); |
936 | 96 | return; |
937 | 96 | } |
938 | 3.38M | oldPtr = STATS(c); |
939 | 3.38M | MyMem12Cpy(ptr, oldPtr, oldNU); |
940 | 3.38M | InsertNode(p, oldPtr, i); |
941 | 3.38M | c->Stats = STATS_REF(ptr); |
942 | 3.38M | } |
943 | 3.60M | } |
944 | 5.67M | c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns)); |
945 | 5.67M | } |
946 | 6.61M | else |
947 | 6.61M | { |
948 | 6.61M | CPpmd_State *s2 = (CPpmd_State*)AllocUnits(p, 0); |
949 | 6.61M | if (!s2) |
950 | 38 | { |
951 | 38 | RESTORE_MODEL(c, CTX(fSuccessor)); |
952 | 38 | return; |
953 | 38 | } |
954 | 6.61M | *s2 = *ONE_STATE(c); |
955 | 6.61M | c->Stats = REF(s2); |
956 | 6.61M | if (s2->Freq < MAX_FREQ / 4 - 1) |
957 | 6.61M | s2->Freq <<= 1; |
958 | 2.50k | else |
959 | 2.50k | s2->Freq = MAX_FREQ - 4; |
960 | 6.61M | c->SummFreq = (UInt16)(s2->Freq + p->InitEsc + (ns > 2)); |
961 | 6.61M | } |
962 | 12.2M | cf = 2 * fFreq * (c->SummFreq + 6); |
963 | 12.2M | sf = (UInt32)s0 + c->SummFreq; |
964 | 12.2M | if (cf < 6 * sf) |
965 | 7.20M | { |
966 | 7.20M | cf = 1 + (cf > sf) + (cf >= 4 * sf); |
967 | 7.20M | c->SummFreq += 4; |
968 | 7.20M | } |
969 | 5.09M | else |
970 | 5.09M | { |
971 | 5.09M | cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); |
972 | 5.09M | c->SummFreq = (UInt16)(c->SummFreq + cf); |
973 | 5.09M | } |
974 | 12.2M | { |
975 | 12.2M | CPpmd_State *s2 = STATS(c) + ns1 + 1; |
976 | 12.2M | SetSuccessor(s2, successor); |
977 | 12.2M | s2->Symbol = fSymbol; |
978 | 12.2M | s2->Freq = (Byte)cf; |
979 | 12.2M | c->Flags |= flag; |
980 | 12.2M | c->NumStats = (Byte)(ns1 + 1); |
981 | 12.2M | } |
982 | 12.2M | } |
983 | 12.5M | p->MaxContext = p->MinContext = CTX(fSuccessor); |
984 | 12.5M | } |
985 | | |
986 | | static void Rescale(CPpmd8 *p) |
987 | 45.3k | { |
988 | 45.3k | unsigned i, adder, sumFreq, escFreq; |
989 | 45.3k | CPpmd_State *stats = STATS(p->MinContext); |
990 | 45.3k | CPpmd_State *s = p->FoundState; |
991 | 45.3k | { |
992 | 45.3k | CPpmd_State tmp = *s; |
993 | 89.4k | for (; s != stats; s--) |
994 | 44.1k | s[0] = s[-1]; |
995 | 45.3k | *s = tmp; |
996 | 45.3k | } |
997 | 45.3k | escFreq = p->MinContext->SummFreq - s->Freq; |
998 | 45.3k | s->Freq += 4; |
999 | 45.3k | adder = (p->OrderFall != 0 |
1000 | | #ifdef PPMD8_FREEZE_SUPPORT |
1001 | | || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE |
1002 | | #endif |
1003 | 45.3k | ); |
1004 | 45.3k | s->Freq = (Byte)((s->Freq + adder) >> 1); |
1005 | 45.3k | sumFreq = s->Freq; |
1006 | | |
1007 | 45.3k | i = p->MinContext->NumStats; |
1008 | 45.3k | do |
1009 | 1.27M | { |
1010 | 1.27M | escFreq -= (++s)->Freq; |
1011 | 1.27M | s->Freq = (Byte)((s->Freq + adder) >> 1); |
1012 | 1.27M | sumFreq += s->Freq; |
1013 | 1.27M | if (s[0].Freq > s[-1].Freq) |
1014 | 464k | { |
1015 | 464k | CPpmd_State *s1 = s; |
1016 | 464k | CPpmd_State tmp = *s1; |
1017 | 464k | do |
1018 | 12.4M | s1[0] = s1[-1]; |
1019 | 12.4M | while (--s1 != stats && tmp.Freq > s1[-1].Freq); |
1020 | 464k | *s1 = tmp; |
1021 | 464k | } |
1022 | 1.27M | } |
1023 | 1.27M | while (--i); |
1024 | | |
1025 | 45.3k | if (s->Freq == 0) |
1026 | 15.4k | { |
1027 | 15.4k | unsigned numStats = p->MinContext->NumStats; |
1028 | 15.4k | unsigned n0, n1; |
1029 | 32.9k | do { i++; } while ((--s)->Freq == 0); |
1030 | 15.4k | escFreq += i; |
1031 | 15.4k | p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i); |
1032 | 15.4k | if (p->MinContext->NumStats == 0) |
1033 | 1.43k | { |
1034 | 1.43k | CPpmd_State tmp = *stats; |
1035 | 1.43k | tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq); |
1036 | 1.43k | if (tmp.Freq > MAX_FREQ / 3) |
1037 | 1.26k | tmp.Freq = MAX_FREQ / 3; |
1038 | 1.43k | InsertNode(p, stats, U2I((numStats + 2) >> 1)); |
1039 | 1.43k | p->MinContext->Flags = (Byte)((p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40)); |
1040 | 1.43k | *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; |
1041 | 1.43k | return; |
1042 | 1.43k | } |
1043 | 14.0k | n0 = (numStats + 2) >> 1; |
1044 | 14.0k | n1 = (p->MinContext->NumStats + 2) >> 1; |
1045 | 14.0k | if (n0 != n1) |
1046 | 10.8k | p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); |
1047 | 14.0k | p->MinContext->Flags &= ~0x08; |
1048 | 14.0k | p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40); |
1049 | 14.0k | i = p->MinContext->NumStats; |
1050 | 141k | do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i); |
1051 | 14.0k | } |
1052 | 43.8k | p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); |
1053 | 43.8k | p->MinContext->Flags |= 0x4; |
1054 | 43.8k | p->FoundState = STATS(p->MinContext); |
1055 | 43.8k | } |
1056 | | |
1057 | | CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) |
1058 | 5.59M | { |
1059 | 5.59M | CPpmd_See *see; |
1060 | 5.59M | if (p->MinContext->NumStats != 0xFF) |
1061 | 4.70M | { |
1062 | 4.70M | see = p->See[(unsigned)p->NS2Indx[(unsigned)p->MinContext->NumStats + 2] - 3] + |
1063 | 4.70M | (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) + |
1064 | 4.70M | 2 * (unsigned)(2 * (unsigned)p->MinContext->NumStats < |
1065 | 4.70M | ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) + |
1066 | 4.70M | p->MinContext->Flags; |
1067 | 4.70M | { |
1068 | 4.70M | unsigned r = (see->Summ >> see->Shift); |
1069 | 4.70M | see->Summ = (UInt16)(see->Summ - r); |
1070 | 4.70M | *escFreq = r + (r == 0); |
1071 | 4.70M | } |
1072 | 4.70M | } |
1073 | 895k | else |
1074 | 895k | { |
1075 | 895k | see = &p->DummySee; |
1076 | 895k | *escFreq = 1; |
1077 | 895k | } |
1078 | 5.59M | return see; |
1079 | 5.59M | } |
1080 | | |
1081 | | static void NextContext(CPpmd8 *p) |
1082 | 20.1M | { |
1083 | 20.1M | CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); |
1084 | 20.1M | if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart) |
1085 | 9.37M | p->MinContext = p->MaxContext = c; |
1086 | 10.8M | else |
1087 | 10.8M | { |
1088 | 10.8M | UpdateModel(p); |
1089 | 10.8M | p->MinContext = p->MaxContext; |
1090 | 10.8M | } |
1091 | 20.1M | } |
1092 | | |
1093 | | void Ppmd8_Update1(CPpmd8 *p) |
1094 | 2.65M | { |
1095 | 2.65M | CPpmd_State *s = p->FoundState; |
1096 | 2.65M | s->Freq += 4; |
1097 | 2.65M | p->MinContext->SummFreq += 4; |
1098 | 2.65M | if (s[0].Freq > s[-1].Freq) |
1099 | 1.60M | { |
1100 | 1.60M | SwapStates(&s[0], &s[-1]); |
1101 | 1.60M | p->FoundState = --s; |
1102 | 1.60M | if (s->Freq > MAX_FREQ) |
1103 | 390 | Rescale(p); |
1104 | 1.60M | } |
1105 | 2.65M | NextContext(p); |
1106 | 2.65M | } |
1107 | | |
1108 | | void Ppmd8_Update1_0(CPpmd8 *p) |
1109 | 2.56M | { |
1110 | 2.56M | p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq); |
1111 | 2.56M | p->RunLength += p->PrevSuccess; |
1112 | 2.56M | p->MinContext->SummFreq += 4; |
1113 | 2.56M | if ((p->FoundState->Freq += 4) > MAX_FREQ) |
1114 | 36.7k | Rescale(p); |
1115 | 2.56M | NextContext(p); |
1116 | 2.56M | } |
1117 | | |
1118 | | void Ppmd8_UpdateBin(CPpmd8 *p) |
1119 | 14.9M | { |
1120 | 14.9M | p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196)); |
1121 | 14.9M | p->PrevSuccess = 1; |
1122 | 14.9M | p->RunLength++; |
1123 | 14.9M | NextContext(p); |
1124 | 14.9M | } |
1125 | | |
1126 | | void Ppmd8_Update2(CPpmd8 *p) |
1127 | 3.96M | { |
1128 | 3.96M | p->MinContext->SummFreq += 4; |
1129 | 3.96M | if ((p->FoundState->Freq += 4) > MAX_FREQ) |
1130 | 8.17k | Rescale(p); |
1131 | 3.96M | p->RunLength = p->InitRL; |
1132 | 3.96M | UpdateModel(p); |
1133 | 3.96M | p->MinContext = p->MaxContext; |
1134 | 3.96M | } |
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.35k | { |
1144 | 1.35k | unsigned i; |
1145 | 1.35k | p->Low = 0; |
1146 | 1.35k | p->Range = 0xFFFFFFFF; |
1147 | 1.35k | p->Code = 0; |
1148 | 6.77k | for (i = 0; i < 4; i++) |
1149 | 5.41k | p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); |
1150 | 1.35k | return (p->Code < 0xFFFFFFFF); |
1151 | 1.35k | } |
1152 | | |
1153 | | static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total) |
1154 | 12.6M | { |
1155 | 12.6M | return p->Code / (p->Range /= total); |
1156 | 12.6M | } |
1157 | | |
1158 | | static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size) |
1159 | 29.7M | { |
1160 | 29.7M | start *= p->Range; |
1161 | 29.7M | p->Low += start; |
1162 | 29.7M | p->Code -= start; |
1163 | 29.7M | p->Range *= size; |
1164 | | |
1165 | 34.3M | while ((p->Low ^ (p->Low + p->Range)) < kTop || |
1166 | 29.7M | (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) |
1167 | 4.64M | { |
1168 | 4.64M | p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); |
1169 | 4.64M | p->Range <<= 8; |
1170 | 4.64M | p->Low <<= 8; |
1171 | 4.64M | } |
1172 | 29.7M | } |
1173 | | |
1174 | 306M | #define MASK(sym) ((signed char *)charMask)[sym] |
1175 | | |
1176 | | int Ppmd8_DecodeSymbol(CPpmd8 *p) |
1177 | 24.1M | { |
1178 | 24.1M | size_t charMask[256 / sizeof(size_t)]; |
1179 | 24.1M | if (p->MinContext->NumStats != 0) |
1180 | 7.07M | { |
1181 | 7.07M | CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); |
1182 | 7.07M | unsigned i; |
1183 | 7.07M | UInt32 count, hiCnt; |
1184 | 7.07M | if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) |
1185 | 2.56M | { |
1186 | 2.56M | Byte symbol; |
1187 | 2.56M | RangeDec_Decode(p, 0, s->Freq); |
1188 | 2.56M | p->FoundState = s; |
1189 | 2.56M | symbol = s->Symbol; |
1190 | 2.56M | Ppmd8_Update1_0(p); |
1191 | 2.56M | return symbol; |
1192 | 2.56M | } |
1193 | 4.50M | p->PrevSuccess = 0; |
1194 | 4.50M | i = p->MinContext->NumStats; |
1195 | 4.50M | do |
1196 | 28.4M | { |
1197 | 28.4M | if ((hiCnt += (++s)->Freq) > count) |
1198 | 2.65M | { |
1199 | 2.65M | Byte symbol; |
1200 | 2.65M | RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); |
1201 | 2.65M | p->FoundState = s; |
1202 | 2.65M | symbol = s->Symbol; |
1203 | 2.65M | Ppmd8_Update1(p); |
1204 | 2.65M | return symbol; |
1205 | 2.65M | } |
1206 | 28.4M | } |
1207 | 25.8M | while (--i); |
1208 | 1.84M | if (count >= p->MinContext->SummFreq) |
1209 | 316 | return -2; |
1210 | 1.84M | RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt); |
1211 | 1.84M | PPMD_SetAllBitsIn256Bytes(charMask); |
1212 | 1.84M | MASK(s->Symbol) = 0; |
1213 | 1.84M | i = p->MinContext->NumStats; |
1214 | 8.41M | do { MASK((--s)->Symbol) = 0; } while (--i); |
1215 | 1.84M | } |
1216 | 17.0M | else |
1217 | 17.0M | { |
1218 | 17.0M | UInt16 *prob = Ppmd8_GetBinSumm(p); |
1219 | 17.0M | if (((p->Code / (p->Range >>= 14)) < *prob)) |
1220 | 14.9M | { |
1221 | 14.9M | Byte symbol; |
1222 | 14.9M | RangeDec_Decode(p, 0, *prob); |
1223 | 14.9M | *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); |
1224 | 14.9M | symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; |
1225 | 14.9M | Ppmd8_UpdateBin(p); |
1226 | 14.9M | return symbol; |
1227 | 14.9M | } |
1228 | 2.12M | RangeDec_Decode(p, *prob, (1 << 14) - *prob); |
1229 | 2.12M | *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); |
1230 | 2.12M | p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; |
1231 | 2.12M | PPMD_SetAllBitsIn256Bytes(charMask); |
1232 | 2.12M | MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; |
1233 | 2.12M | p->PrevSuccess = 0; |
1234 | 2.12M | } |
1235 | 3.96M | for (;;) |
1236 | 5.59M | { |
1237 | 5.59M | CPpmd_State *ps[256], *s; |
1238 | 5.59M | UInt32 freqSum, count, hiCnt; |
1239 | 5.59M | CPpmd_See *see; |
1240 | 5.59M | unsigned i, num, numMasked = p->MinContext->NumStats; |
1241 | 5.59M | do |
1242 | 12.2M | { |
1243 | 12.2M | p->OrderFall++; |
1244 | 12.2M | if (!p->MinContext->Suffix) |
1245 | 122 | return -1; |
1246 | 12.2M | p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); |
1247 | 12.2M | } |
1248 | 12.2M | while (p->MinContext->NumStats == numMasked); |
1249 | 5.59M | hiCnt = 0; |
1250 | 5.59M | s = Ppmd8_GetStats(p, p->MinContext); |
1251 | 5.59M | i = 0; |
1252 | 5.59M | num = p->MinContext->NumStats - numMasked; |
1253 | 5.59M | do |
1254 | 286M | { |
1255 | 286M | int k = (int)(MASK(s->Symbol)); |
1256 | 286M | hiCnt += (s->Freq & k); |
1257 | 286M | ps[i] = s++; |
1258 | 286M | i -= k; |
1259 | 286M | } |
1260 | 286M | while (i != num); |
1261 | | |
1262 | 5.59M | see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); |
1263 | 5.59M | freqSum += hiCnt; |
1264 | 5.59M | count = RangeDec_GetThreshold(p, freqSum); |
1265 | | |
1266 | 5.59M | if (count < hiCnt) |
1267 | 3.96M | { |
1268 | 3.96M | Byte symbol; |
1269 | 3.96M | CPpmd_State **pps = ps; |
1270 | 70.7M | for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); |
1271 | 3.96M | s = *pps; |
1272 | 3.96M | RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); |
1273 | 3.96M | Ppmd_See_Update(see); |
1274 | 3.96M | p->FoundState = s; |
1275 | 3.96M | symbol = s->Symbol; |
1276 | 3.96M | Ppmd8_Update2(p); |
1277 | 3.96M | return symbol; |
1278 | 3.96M | } |
1279 | 1.62M | if (count >= freqSum) |
1280 | 436 | return -2; |
1281 | 1.62M | RangeDec_Decode(p, hiCnt, freqSum - hiCnt); |
1282 | 1.62M | see->Summ = (UInt16)(see->Summ + freqSum); |
1283 | 7.57M | do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); |
1284 | 1.62M | } |
1285 | 3.96M | } |
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 | | }; |