File indexing completed on 2025-03-09 04:13:31
0001 /* Ppmd8.c -- PPMdI codec 0002 2010-03-24 : Igor Pavlov : Public domain 0003 This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ 0004 0005 #include "Precomp.h" 0006 0007 #include <memory.h> 0008 0009 #include "Ppmd8.h" 0010 0011 const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; 0012 static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; 0013 0014 #define MAX_FREQ 124 0015 #define UNIT_SIZE 12 0016 0017 #define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) 0018 #define U2I(nu) (p->Units2Indx[(nu) - 1]) 0019 #define I2U(indx) (p->Indx2Units[indx]) 0020 0021 #ifdef PPMD_32BIT 0022 #define REF(ptr) (ptr) 0023 #else 0024 #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) 0025 #endif 0026 0027 #define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) 0028 0029 #define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) 0030 #define STATS(ctx) Ppmd8_GetStats(p, ctx) 0031 #define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) 0032 #define SUFFIX(ctx) CTX((ctx)->Suffix) 0033 0034 typedef CPpmd8_Context * CTX_PTR; 0035 0036 struct CPpmd8_Node_; 0037 0038 typedef 0039 #ifdef PPMD_32BIT 0040 struct CPpmd8_Node_ * 0041 #else 0042 UInt32 0043 #endif 0044 CPpmd8_Node_Ref; 0045 0046 typedef struct CPpmd8_Node_ 0047 { 0048 UInt32 Stamp; 0049 CPpmd8_Node_Ref Next; 0050 UInt32 NU; 0051 } CPpmd8_Node; 0052 0053 #ifdef PPMD_32BIT 0054 #define NODE(ptr) (ptr) 0055 #else 0056 #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs))) 0057 #endif 0058 0059 #define EMPTY_NODE 0xFFFFFFFF 0060 0061 void Ppmd8_Construct(CPpmd8 *p) 0062 { 0063 unsigned i, k, m; 0064 0065 p->Base = 0; 0066 0067 for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) 0068 { 0069 unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); 0070 do { p->Units2Indx[k++] = (Byte)i; } while(--step); 0071 p->Indx2Units[i] = (Byte)k; 0072 } 0073 0074 p->NS2BSIndx[0] = (0 << 1); 0075 p->NS2BSIndx[1] = (1 << 1); 0076 memset(p->NS2BSIndx + 2, (2 << 1), 9); 0077 memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); 0078 0079 for (i = 0; i < 5; i++) 0080 p->NS2Indx[i] = (Byte)i; 0081 for (m = i, k = 1; i < 260; i++) 0082 { 0083 p->NS2Indx[i] = (Byte)m; 0084 if (--k == 0) 0085 k = (++m) - 4; 0086 } 0087 } 0088 0089 void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc) 0090 { 0091 alloc->Free(alloc, p->Base); 0092 p->Size = 0; 0093 p->Base = 0; 0094 } 0095 0096 Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc) 0097 { 0098 if (p->Base == 0 || p->Size != size) 0099 { 0100 Ppmd8_Free(p, alloc); 0101 p->AlignOffset = 0102 #ifdef PPMD_32BIT 0103 (4 - size) & 3; 0104 #else 0105 4 - (size & 3); 0106 #endif 0107 if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size)) == 0) 0108 return False; 0109 p->Size = size; 0110 } 0111 return True; 0112 } 0113 0114 static void InsertNode(CPpmd8 *p, void *node, unsigned indx) 0115 { 0116 ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; 0117 ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; 0118 ((CPpmd8_Node *)node)->NU = I2U(indx); 0119 p->FreeList[indx] = REF(node); 0120 p->Stamps[indx]++; 0121 } 0122 0123 static void *RemoveNode(CPpmd8 *p, unsigned indx) 0124 { 0125 CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); 0126 p->FreeList[indx] = node->Next; 0127 p->Stamps[indx]--; 0128 return node; 0129 } 0130 0131 static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) 0132 { 0133 unsigned i, nu = I2U(oldIndx) - I2U(newIndx); 0134 ptr = (Byte *)ptr + U2B(I2U(newIndx)); 0135 if (I2U(i = U2I(nu)) != nu) 0136 { 0137 unsigned k = I2U(--i); 0138 InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); 0139 } 0140 InsertNode(p, ptr, i); 0141 } 0142 0143 static void GlueFreeBlocks(CPpmd8 *p) 0144 { 0145 CPpmd8_Node_Ref head = 0; 0146 CPpmd8_Node_Ref *prev = &head; 0147 unsigned i; 0148 0149 p->GlueCount = 1 << 13; 0150 memset(p->Stamps, 0, sizeof(p->Stamps)); 0151 0152 /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end. 0153 All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */ 0154 if (p->LoUnit != p->HiUnit) 0155 ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; 0156 0157 /* Glue free blocks */ 0158 for (i = 0; i < PPMD_NUM_INDEXES; i++) 0159 { 0160 CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; 0161 p->FreeList[i] = 0; 0162 while (next != 0) 0163 { 0164 CPpmd8_Node *node = NODE(next); 0165 if (node->NU != 0) 0166 { 0167 CPpmd8_Node *node2; 0168 *prev = next; 0169 prev = &(node->Next); 0170 while ((node2 = node + node->NU)->Stamp == EMPTY_NODE) 0171 { 0172 node->NU += node2->NU; 0173 node2->NU = 0; 0174 } 0175 } 0176 next = node->Next; 0177 } 0178 } 0179 *prev = 0; 0180 0181 /* Fill lists of free blocks */ 0182 while (head != 0) 0183 { 0184 CPpmd8_Node *node = NODE(head); 0185 unsigned nu; 0186 head = node->Next; 0187 nu = node->NU; 0188 if (nu == 0) 0189 continue; 0190 for (; nu > 128; nu -= 128, node += 128) 0191 InsertNode(p, node, PPMD_NUM_INDEXES - 1); 0192 if (I2U(i = U2I(nu)) != nu) 0193 { 0194 unsigned k = I2U(--i); 0195 InsertNode(p, node + k, nu - k - 1); 0196 } 0197 InsertNode(p, node, i); 0198 } 0199 } 0200 0201 static void *AllocUnitsRare(CPpmd8 *p, unsigned indx) 0202 { 0203 unsigned i; 0204 void *retVal; 0205 if (p->GlueCount == 0) 0206 { 0207 GlueFreeBlocks(p); 0208 if (p->FreeList[indx] != 0) 0209 return RemoveNode(p, indx); 0210 } 0211 i = indx; 0212 do 0213 { 0214 if (++i == PPMD_NUM_INDEXES) 0215 { 0216 UInt32 numBytes = U2B(I2U(indx)); 0217 p->GlueCount--; 0218 return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); 0219 } 0220 } 0221 while (p->FreeList[i] == 0); 0222 retVal = RemoveNode(p, i); 0223 SplitBlock(p, retVal, i, indx); 0224 return retVal; 0225 } 0226 0227 static void *AllocUnits(CPpmd8 *p, unsigned indx) 0228 { 0229 UInt32 numBytes; 0230 if (p->FreeList[indx] != 0) 0231 return RemoveNode(p, indx); 0232 numBytes = U2B(I2U(indx)); 0233 if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) 0234 { 0235 void *retVal = p->LoUnit; 0236 p->LoUnit += numBytes; 0237 return retVal; 0238 } 0239 return AllocUnitsRare(p, indx); 0240 } 0241 0242 #define MyMem12Cpy(dest, src, num) \ 0243 { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ 0244 do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } 0245 0246 static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU) 0247 { 0248 unsigned i0 = U2I(oldNU); 0249 unsigned i1 = U2I(newNU); 0250 if (i0 == i1) 0251 return oldPtr; 0252 if (p->FreeList[i1] != 0) 0253 { 0254 void *ptr = RemoveNode(p, i1); 0255 MyMem12Cpy(ptr, oldPtr, newNU); 0256 InsertNode(p, oldPtr, i0); 0257 return ptr; 0258 } 0259 SplitBlock(p, oldPtr, i0, i1); 0260 return oldPtr; 0261 } 0262 0263 static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) 0264 { 0265 InsertNode(p, ptr, U2I(nu)); 0266 } 0267 0268 static void SpecialFreeUnit(CPpmd8 *p, void *ptr) 0269 { 0270 if ((Byte *)ptr != p->UnitsStart) 0271 InsertNode(p, ptr, 0); 0272 else 0273 { 0274 #ifdef PPMD8_FREEZE_SUPPORT 0275 *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */ 0276 #endif 0277 p->UnitsStart += UNIT_SIZE; 0278 } 0279 } 0280 0281 static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) 0282 { 0283 unsigned indx = U2I(nu); 0284 void *ptr; 0285 if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx]) 0286 return oldPtr; 0287 ptr = RemoveNode(p, indx); 0288 MyMem12Cpy(ptr, oldPtr, nu); 0289 if ((Byte*)oldPtr != p->UnitsStart) 0290 InsertNode(p, oldPtr, indx); 0291 else 0292 p->UnitsStart += U2B(I2U(indx)); 0293 return ptr; 0294 } 0295 0296 static void ExpandTextArea(CPpmd8 *p) 0297 { 0298 UInt32 count[PPMD_NUM_INDEXES]; 0299 unsigned i; 0300 memset(count, 0, sizeof(count)); 0301 if (p->LoUnit != p->HiUnit) 0302 ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; 0303 0304 { 0305 CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart; 0306 for (; node->Stamp == EMPTY_NODE; node += node->NU) 0307 { 0308 node->Stamp = 0; 0309 count[U2I(node->NU)]++; 0310 } 0311 p->UnitsStart = (Byte *)node; 0312 } 0313 0314 for (i = 0; i < PPMD_NUM_INDEXES; i++) 0315 { 0316 CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i]; 0317 while (count[i] != 0) 0318 { 0319 CPpmd8_Node *node = NODE(*next); 0320 while (node->Stamp == 0) 0321 { 0322 *next = node->Next; 0323 node = NODE(*next); 0324 p->Stamps[i]--; 0325 if (--count[i] == 0) 0326 break; 0327 } 0328 next = &node->Next; 0329 } 0330 } 0331 } 0332 0333 #define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) 0334 0335 static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) 0336 { 0337 (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); 0338 (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); 0339 } 0340 0341 #define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); } 0342 0343 static void RestartModel(CPpmd8 *p) 0344 { 0345 unsigned i, k, m, r; 0346 0347 memset(p->FreeList, 0, sizeof(p->FreeList)); 0348 memset(p->Stamps, 0, sizeof(p->Stamps)); 0349 RESET_TEXT(0); 0350 p->HiUnit = p->Text + p->Size; 0351 p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; 0352 p->GlueCount = 0; 0353 0354 p->OrderFall = p->MaxOrder; 0355 p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; 0356 p->PrevSuccess = 0; 0357 0358 p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ 0359 p->MinContext->Suffix = 0; 0360 p->MinContext->NumStats = 255; 0361 p->MinContext->Flags = 0; 0362 p->MinContext->SummFreq = 256 + 1; 0363 p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ 0364 p->LoUnit += U2B(256 / 2); 0365 p->MinContext->Stats = REF(p->FoundState); 0366 for (i = 0; i < 256; i++) 0367 { 0368 CPpmd_State *s = &p->FoundState[i]; 0369 s->Symbol = (Byte)i; 0370 s->Freq = 1; 0371 SetSuccessor(s, 0); 0372 } 0373 0374 for (i = m = 0; m < 25; m++) 0375 { 0376 while (p->NS2Indx[i] == m) 0377 i++; 0378 for (k = 0; k < 8; k++) 0379 { 0380 UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1)); 0381 UInt16 *dest = p->BinSumm[m] + k; 0382 for (r = 0; r < 64; r += 8) 0383 dest[r] = val; 0384 } 0385 } 0386 0387 for (i = m = 0; m < 24; m++) 0388 { 0389 while (p->NS2Indx[i + 3] == m + 3) 0390 i++; 0391 for (k = 0; k < 32; k++) 0392 { 0393 CPpmd_See *s = &p->See[m][k]; 0394 s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4)); 0395 s->Count = 7; 0396 } 0397 } 0398 } 0399 0400 void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) 0401 { 0402 p->MaxOrder = maxOrder; 0403 p->RestoreMethod = restoreMethod; 0404 RestartModel(p); 0405 p->DummySee.Shift = PPMD_PERIOD_BITS; 0406 p->DummySee.Summ = 0; /* unused */ 0407 p->DummySee.Count = 64; /* unused */ 0408 } 0409 0410 static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale) 0411 { 0412 unsigned i = ctx->NumStats, escFreq, sumFreq, flags; 0413 CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); 0414 ctx->Stats = REF(s); 0415 #ifdef PPMD8_FREEZE_SUPPORT 0416 /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */ 0417 scale |= (ctx->SummFreq >= ((UInt32)1 << 15)); 0418 #endif 0419 flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40); 0420 escFreq = ctx->SummFreq - s->Freq; 0421 sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale)); 0422 do 0423 { 0424 escFreq -= (++s)->Freq; 0425 sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale)); 0426 flags |= 0x08 * (s->Symbol >= 0x40); 0427 } 0428 while (--i); 0429 ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); 0430 ctx->Flags = (Byte)flags; 0431 } 0432 0433 static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) 0434 { 0435 CPpmd_State tmp = *t1; 0436 *t1 = *t2; 0437 *t2 = tmp; 0438 } 0439 0440 static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order) 0441 { 0442 int i; 0443 unsigned tmp; 0444 CPpmd_State *s; 0445 0446 if (!ctx->NumStats) 0447 { 0448 s = ONE_STATE(ctx); 0449 if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart) 0450 { 0451 if (order < p->MaxOrder) 0452 SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); 0453 else 0454 SetSuccessor(s, 0); 0455 if (SUCCESSOR(s) || order <= 9) /* O_BOUND */ 0456 return REF(ctx); 0457 } 0458 SpecialFreeUnit(p, ctx); 0459 return 0; 0460 } 0461 0462 ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1)); 0463 0464 for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--) 0465 if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart) 0466 { 0467 CPpmd_State *s2 = STATS(ctx) + (i--); 0468 SetSuccessor(s, 0); 0469 SwapStates(s, s2); 0470 } 0471 else if (order < p->MaxOrder) 0472 SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); 0473 else 0474 SetSuccessor(s, 0); 0475 0476 if (i != ctx->NumStats && order) 0477 { 0478 ctx->NumStats = (Byte)i; 0479 s = STATS(ctx); 0480 if (i < 0) 0481 { 0482 FreeUnits(p, s, tmp); 0483 SpecialFreeUnit(p, ctx); 0484 return 0; 0485 } 0486 if (i == 0) 0487 { 0488 ctx->Flags = (ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40); 0489 *ONE_STATE(ctx) = *s; 0490 FreeUnits(p, s, tmp); 0491 ONE_STATE(ctx)->Freq = (Byte)((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3; 0492 } 0493 else 0494 Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i); 0495 } 0496 return REF(ctx); 0497 } 0498 0499 #ifdef PPMD8_FREEZE_SUPPORT 0500 static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order) 0501 { 0502 CPpmd_State *s; 0503 if (!ctx->NumStats) 0504 { 0505 s = ONE_STATE(ctx); 0506 if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) 0507 SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); 0508 else 0509 SetSuccessor(s, 0); 0510 /* Suffix context can be removed already, since different (high-order) 0511 Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */ 0512 if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF)) 0513 { 0514 FreeUnits(p, ctx, 1); 0515 return 0; 0516 } 0517 else 0518 return REF(ctx); 0519 } 0520 0521 for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--) 0522 if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) 0523 SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); 0524 else 0525 SetSuccessor(s, 0); 0526 0527 return REF(ctx); 0528 } 0529 #endif 0530 0531 static UInt32 GetUsedMemory(const CPpmd8 *p) 0532 { 0533 UInt32 v = 0; 0534 unsigned i; 0535 for (i = 0; i < PPMD_NUM_INDEXES; i++) 0536 v += p->Stamps[i] * I2U(i); 0537 return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); 0538 } 0539 0540 #ifdef PPMD8_FREEZE_SUPPORT 0541 #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) 0542 #else 0543 #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1) 0544 #endif 0545 0546 static void RestoreModel(CPpmd8 *p, CTX_PTR c1 0547 #ifdef PPMD8_FREEZE_SUPPORT 0548 , CTX_PTR fSuccessor 0549 #endif 0550 ) 0551 { 0552 CTX_PTR c; 0553 CPpmd_State *s; 0554 RESET_TEXT(0); 0555 for (c = p->MaxContext; c != c1; c = SUFFIX(c)) 0556 if (--(c->NumStats) == 0) 0557 { 0558 s = STATS(c); 0559 c->Flags = (c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40); 0560 *ONE_STATE(c) = *s; 0561 SpecialFreeUnit(p, s); 0562 ONE_STATE(c)->Freq = (ONE_STATE(c)->Freq + 11) >> 3; 0563 } 0564 else 0565 Refresh(p, c, (c->NumStats+3) >> 1, 0); 0566 0567 for (; c != p->MinContext; c = SUFFIX(c)) 0568 if (!c->NumStats) 0569 ONE_STATE(c)->Freq -= ONE_STATE(c)->Freq >> 1; 0570 else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats) 0571 Refresh(p, c, (c->NumStats + 2) >> 1, 1); 0572 0573 #ifdef PPMD8_FREEZE_SUPPORT 0574 if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) 0575 { 0576 p->MaxContext = fSuccessor; 0577 p->GlueCount += !(p->Stamps[1] & 1); 0578 } 0579 else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE) 0580 { 0581 while (p->MaxContext->Suffix) 0582 p->MaxContext = SUFFIX(p->MaxContext); 0583 RemoveBinContexts(p, p->MaxContext, 0); 0584 p->RestoreMethod++; 0585 p->GlueCount = 0; 0586 p->OrderFall = p->MaxOrder; 0587 } 0588 else 0589 #endif 0590 if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) 0591 RestartModel(p); 0592 else 0593 { 0594 while (p->MaxContext->Suffix) 0595 p->MaxContext = SUFFIX(p->MaxContext); 0596 do 0597 { 0598 CutOff(p, p->MaxContext, 0); 0599 ExpandTextArea(p); 0600 } 0601 while (GetUsedMemory(p) > 3 * (p->Size >> 2)); 0602 p->GlueCount = 0; 0603 p->OrderFall = p->MaxOrder; 0604 } 0605 } 0606 0607 static CTX_PTR CreateSuccessors(CPpmd8 *p, Bool skip, CPpmd_State *s1, CTX_PTR c) 0608 { 0609 CPpmd_State upState; 0610 Byte flags; 0611 CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); 0612 /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ 0613 CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; 0614 unsigned numPs = 0; 0615 0616 if (!skip) 0617 ps[numPs++] = p->FoundState; 0618 0619 while (c->Suffix) 0620 { 0621 CPpmd_Void_Ref successor; 0622 CPpmd_State *s; 0623 c = SUFFIX(c); 0624 if (s1) 0625 { 0626 s = s1; 0627 s1 = NULL; 0628 } 0629 else if (c->NumStats != 0) 0630 { 0631 for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); 0632 if (s->Freq < MAX_FREQ - 9) 0633 { 0634 s->Freq++; 0635 c->SummFreq++; 0636 } 0637 } 0638 else 0639 { 0640 s = ONE_STATE(c); 0641 s->Freq += (!SUFFIX(c)->NumStats & (s->Freq < 24)); 0642 } 0643 successor = SUCCESSOR(s); 0644 if (successor != upBranch) 0645 { 0646 c = CTX(successor); 0647 if (numPs == 0) 0648 return c; 0649 break; 0650 } 0651 ps[numPs++] = s; 0652 } 0653 0654 upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch); 0655 SetSuccessor(&upState, upBranch + 1); 0656 flags = 0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40); 0657 0658 if (c->NumStats == 0) 0659 upState.Freq = ONE_STATE(c)->Freq; 0660 else 0661 { 0662 UInt32 cf, s0; 0663 CPpmd_State *s; 0664 for (s = STATS(c); s->Symbol != upState.Symbol; s++); 0665 cf = s->Freq - 1; 0666 s0 = c->SummFreq - c->NumStats - cf; 0667 upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); 0668 } 0669 0670 do 0671 { 0672 /* Create Child */ 0673 CTX_PTR c1; /* = AllocContext(p); */ 0674 if (p->HiUnit != p->LoUnit) 0675 c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); 0676 else if (p->FreeList[0] != 0) 0677 c1 = (CTX_PTR)RemoveNode(p, 0); 0678 else 0679 { 0680 c1 = (CTX_PTR)AllocUnitsRare(p, 0); 0681 if (!c1) 0682 return NULL; 0683 } 0684 c1->NumStats = 0; 0685 c1->Flags = flags; 0686 *ONE_STATE(c1) = upState; 0687 c1->Suffix = REF(c); 0688 SetSuccessor(ps[--numPs], REF(c1)); 0689 c = c1; 0690 } 0691 while (numPs != 0); 0692 0693 return c; 0694 } 0695 0696 static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c) 0697 { 0698 CPpmd_State *s = NULL; 0699 CTX_PTR c1 = c; 0700 CPpmd_Void_Ref upBranch = REF(p->Text); 0701 0702 #ifdef PPMD8_FREEZE_SUPPORT 0703 /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */ 0704 CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; 0705 unsigned numPs = 0; 0706 ps[numPs++] = p->FoundState; 0707 #endif 0708 0709 SetSuccessor(p->FoundState, upBranch); 0710 p->OrderFall++; 0711 0712 for (;;) 0713 { 0714 if (s1) 0715 { 0716 c = SUFFIX(c); 0717 s = s1; 0718 s1 = NULL; 0719 } 0720 else 0721 { 0722 if (!c->Suffix) 0723 { 0724 #ifdef PPMD8_FREEZE_SUPPORT 0725 if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) 0726 { 0727 do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); 0728 RESET_TEXT(1); 0729 p->OrderFall = 1; 0730 } 0731 #endif 0732 return c; 0733 } 0734 c = SUFFIX(c); 0735 if (c->NumStats) 0736 { 0737 if ((s = STATS(c))->Symbol != p->FoundState->Symbol) 0738 do { s++; } while (s->Symbol != p->FoundState->Symbol); 0739 if (s->Freq < MAX_FREQ - 9) 0740 { 0741 s->Freq += 2; 0742 c->SummFreq += 2; 0743 } 0744 } 0745 else 0746 { 0747 s = ONE_STATE(c); 0748 s->Freq += (s->Freq < 32); 0749 } 0750 } 0751 if (SUCCESSOR(s)) 0752 break; 0753 #ifdef PPMD8_FREEZE_SUPPORT 0754 ps[numPs++] = s; 0755 #endif 0756 SetSuccessor(s, upBranch); 0757 p->OrderFall++; 0758 } 0759 0760 #ifdef PPMD8_FREEZE_SUPPORT 0761 if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) 0762 { 0763 c = CTX(SUCCESSOR(s)); 0764 do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); 0765 RESET_TEXT(1); 0766 p->OrderFall = 1; 0767 return c; 0768 } 0769 else 0770 #endif 0771 if (SUCCESSOR(s) <= upBranch) 0772 { 0773 CTX_PTR successor; 0774 CPpmd_State *s1 = p->FoundState; 0775 p->FoundState = s; 0776 0777 successor = CreateSuccessors(p, False, NULL, c); 0778 if (successor == NULL) 0779 SetSuccessor(s, 0); 0780 else 0781 SetSuccessor(s, REF(successor)); 0782 p->FoundState = s1; 0783 } 0784 0785 if (p->OrderFall == 1 && c1 == p->MaxContext) 0786 { 0787 SetSuccessor(p->FoundState, SUCCESSOR(s)); 0788 p->Text--; 0789 } 0790 if (SUCCESSOR(s) == 0) 0791 return NULL; 0792 return CTX(SUCCESSOR(s)); 0793 } 0794 0795 static void UpdateModel(CPpmd8 *p) 0796 { 0797 CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); 0798 CTX_PTR c; 0799 unsigned s0, ns, fFreq = p->FoundState->Freq; 0800 Byte flag, fSymbol = p->FoundState->Symbol; 0801 CPpmd_State *s = NULL; 0802 0803 if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) 0804 { 0805 c = SUFFIX(p->MinContext); 0806 0807 if (c->NumStats == 0) 0808 { 0809 s = ONE_STATE(c); 0810 if (s->Freq < 32) 0811 s->Freq++; 0812 } 0813 else 0814 { 0815 s = STATS(c); 0816 if (s->Symbol != p->FoundState->Symbol) 0817 { 0818 do { s++; } while (s->Symbol != p->FoundState->Symbol); 0819 if (s[0].Freq >= s[-1].Freq) 0820 { 0821 SwapStates(&s[0], &s[-1]); 0822 s--; 0823 } 0824 } 0825 if (s->Freq < MAX_FREQ - 9) 0826 { 0827 s->Freq += 2; 0828 c->SummFreq += 2; 0829 } 0830 } 0831 } 0832 0833 c = p->MaxContext; 0834 if (p->OrderFall == 0 && fSuccessor) 0835 { 0836 CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext); 0837 if (cs == 0) 0838 { 0839 SetSuccessor(p->FoundState, 0); 0840 RESTORE_MODEL(c, CTX(fSuccessor)); 0841 } 0842 else 0843 { 0844 SetSuccessor(p->FoundState, REF(cs)); 0845 p->MaxContext = cs; 0846 } 0847 return; 0848 } 0849 0850 *p->Text++ = p->FoundState->Symbol; 0851 successor = REF(p->Text); 0852 if (p->Text >= p->UnitsStart) 0853 { 0854 RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */ 0855 return; 0856 } 0857 0858 if (!fSuccessor) 0859 { 0860 CTX_PTR cs = ReduceOrder(p, s, p->MinContext); 0861 if (cs == NULL) 0862 { 0863 RESTORE_MODEL(c, 0); 0864 return; 0865 } 0866 fSuccessor = REF(cs); 0867 } 0868 else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart) 0869 { 0870 CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext); 0871 if (cs == NULL) 0872 { 0873 RESTORE_MODEL(c, 0); 0874 return; 0875 } 0876 fSuccessor = REF(cs); 0877 } 0878 0879 if (--p->OrderFall == 0) 0880 { 0881 successor = fSuccessor; 0882 p->Text -= (p->MaxContext != p->MinContext); 0883 } 0884 #ifdef PPMD8_FREEZE_SUPPORT 0885 else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) 0886 { 0887 successor = fSuccessor; 0888 RESET_TEXT(0); 0889 p->OrderFall = 0; 0890 } 0891 #endif 0892 0893 s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq; 0894 flag = 0x08 * (fSymbol >= 0x40); 0895 0896 for (; c != p->MinContext; c = SUFFIX(c)) 0897 { 0898 unsigned ns1; 0899 UInt32 cf, sf; 0900 if ((ns1 = c->NumStats) != 0) 0901 { 0902 if ((ns1 & 1) != 0) 0903 { 0904 /* Expand for one UNIT */ 0905 unsigned oldNU = (ns1 + 1) >> 1; 0906 unsigned i = U2I(oldNU); 0907 if (i != U2I(oldNU + 1)) 0908 { 0909 void *ptr = AllocUnits(p, i + 1); 0910 void *oldPtr; 0911 if (!ptr) 0912 { 0913 RESTORE_MODEL(c, CTX(fSuccessor)); 0914 return; 0915 } 0916 oldPtr = STATS(c); 0917 MyMem12Cpy(ptr, oldPtr, oldNU); 0918 InsertNode(p, oldPtr, i); 0919 c->Stats = STATS_REF(ptr); 0920 } 0921 } 0922 c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns)); 0923 } 0924 else 0925 { 0926 CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); 0927 if (!s) 0928 { 0929 RESTORE_MODEL(c, CTX(fSuccessor)); 0930 return; 0931 } 0932 *s = *ONE_STATE(c); 0933 c->Stats = REF(s); 0934 if (s->Freq < MAX_FREQ / 4 - 1) 0935 s->Freq <<= 1; 0936 else 0937 s->Freq = MAX_FREQ - 4; 0938 c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 2)); 0939 } 0940 cf = 2 * fFreq * (c->SummFreq + 6); 0941 sf = (UInt32)s0 + c->SummFreq; 0942 if (cf < 6 * sf) 0943 { 0944 cf = 1 + (cf > sf) + (cf >= 4 * sf); 0945 c->SummFreq += 4; 0946 } 0947 else 0948 { 0949 cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); 0950 c->SummFreq = (UInt16)(c->SummFreq + cf); 0951 } 0952 { 0953 CPpmd_State *s = STATS(c) + ns1 + 1; 0954 SetSuccessor(s, successor); 0955 s->Symbol = fSymbol; 0956 s->Freq = (Byte)cf; 0957 c->Flags |= flag; 0958 c->NumStats = (Byte)(ns1 + 1); 0959 } 0960 } 0961 p->MaxContext = p->MinContext = CTX(fSuccessor); 0962 } 0963 0964 static void Rescale(CPpmd8 *p) 0965 { 0966 unsigned i, adder, sumFreq, escFreq; 0967 CPpmd_State *stats = STATS(p->MinContext); 0968 CPpmd_State *s = p->FoundState; 0969 { 0970 CPpmd_State tmp = *s; 0971 for (; s != stats; s--) 0972 s[0] = s[-1]; 0973 *s = tmp; 0974 } 0975 escFreq = p->MinContext->SummFreq - s->Freq; 0976 s->Freq += 4; 0977 adder = (p->OrderFall != 0 0978 #ifdef PPMD8_FREEZE_SUPPORT 0979 || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE 0980 #endif 0981 ); 0982 s->Freq = (Byte)((s->Freq + adder) >> 1); 0983 sumFreq = s->Freq; 0984 0985 i = p->MinContext->NumStats; 0986 do 0987 { 0988 escFreq -= (++s)->Freq; 0989 s->Freq = (Byte)((s->Freq + adder) >> 1); 0990 sumFreq += s->Freq; 0991 if (s[0].Freq > s[-1].Freq) 0992 { 0993 CPpmd_State *s1 = s; 0994 CPpmd_State tmp = *s1; 0995 do 0996 s1[0] = s1[-1]; 0997 while (--s1 != stats && tmp.Freq > s1[-1].Freq); 0998 *s1 = tmp; 0999 } 1000 } 1001 while (--i); 1002 1003 if (s->Freq == 0) 1004 { 1005 unsigned numStats = p->MinContext->NumStats; 1006 unsigned n0, n1; 1007 do { i++; } while ((--s)->Freq == 0); 1008 escFreq += i; 1009 p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i); 1010 if (p->MinContext->NumStats == 0) 1011 { 1012 CPpmd_State tmp = *stats; 1013 tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq); 1014 if (tmp.Freq > MAX_FREQ / 3) 1015 tmp.Freq = MAX_FREQ / 3; 1016 InsertNode(p, stats, U2I((numStats + 2) >> 1)); 1017 p->MinContext->Flags = (p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40); 1018 *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; 1019 return; 1020 } 1021 n0 = (numStats + 2) >> 1; 1022 n1 = (p->MinContext->NumStats + 2) >> 1; 1023 if (n0 != n1) 1024 p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); 1025 p->MinContext->Flags &= ~0x08; 1026 p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40); 1027 i = p->MinContext->NumStats; 1028 do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i); 1029 } 1030 p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); 1031 p->MinContext->Flags |= 0x4; 1032 p->FoundState = STATS(p->MinContext); 1033 } 1034 1035 CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) 1036 { 1037 CPpmd_See *see; 1038 if (p->MinContext->NumStats != 0xFF) 1039 { 1040 see = p->See[p->NS2Indx[p->MinContext->NumStats + 2] - 3] + 1041 (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) + 1042 2 * (2 * (unsigned)p->MinContext->NumStats < 1043 ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) + 1044 p->MinContext->Flags; 1045 { 1046 unsigned r = (see->Summ >> see->Shift); 1047 see->Summ = (UInt16)(see->Summ - r); 1048 *escFreq = r + (r == 0); 1049 } 1050 } 1051 else 1052 { 1053 see = &p->DummySee; 1054 *escFreq = 1; 1055 } 1056 return see; 1057 } 1058 1059 static void NextContext(CPpmd8 *p) 1060 { 1061 CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); 1062 if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart) 1063 p->MinContext = p->MaxContext = c; 1064 else 1065 { 1066 UpdateModel(p); 1067 p->MinContext = p->MaxContext; 1068 } 1069 } 1070 1071 void Ppmd8_Update1(CPpmd8 *p) 1072 { 1073 CPpmd_State *s = p->FoundState; 1074 s->Freq += 4; 1075 p->MinContext->SummFreq += 4; 1076 if (s[0].Freq > s[-1].Freq) 1077 { 1078 SwapStates(&s[0], &s[-1]); 1079 p->FoundState = --s; 1080 if (s->Freq > MAX_FREQ) 1081 Rescale(p); 1082 } 1083 NextContext(p); 1084 } 1085 1086 void Ppmd8_Update1_0(CPpmd8 *p) 1087 { 1088 p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq); 1089 p->RunLength += p->PrevSuccess; 1090 p->MinContext->SummFreq += 4; 1091 if ((p->FoundState->Freq += 4) > MAX_FREQ) 1092 Rescale(p); 1093 NextContext(p); 1094 } 1095 1096 void Ppmd8_UpdateBin(CPpmd8 *p) 1097 { 1098 p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196)); 1099 p->PrevSuccess = 1; 1100 p->RunLength++; 1101 NextContext(p); 1102 } 1103 1104 void Ppmd8_Update2(CPpmd8 *p) 1105 { 1106 p->MinContext->SummFreq += 4; 1107 if ((p->FoundState->Freq += 4) > MAX_FREQ) 1108 Rescale(p); 1109 p->RunLength = p->InitRL; 1110 UpdateModel(p); 1111 p->MinContext = p->MaxContext; 1112 } 1113 1114 /* H->I changes: 1115 NS2Indx 1116 GlewCount, and Glue method 1117 BinSum 1118 See / EscFreq 1119 CreateSuccessors updates more suffix contexts 1120 UpdateModel consts. 1121 PrevSuccess Update 1122 */