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