mirror of
https://github.com/MacPaw/XADMaster.git
synced 2025-08-29 03:23:48 +02:00
278 lines
7 KiB
Objective-C
278 lines
7 KiB
Objective-C
/*
|
|
* XADQuantumHandle.m
|
|
*
|
|
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301 USA
|
|
*/
|
|
#import "XADQuantumHandle.h"
|
|
#import "XADException.h"
|
|
|
|
|
|
static void InitQuantumCoder(QuantumCoder *self,CSInputBuffer *input);
|
|
static uint16_t GetQuantumFrequency(QuantumCoder *self,uint16_t totfreq);
|
|
static void RemoveQuantumCode(QuantumCoder *self,int cumfreqm1,int cumfreq,int totfreq);
|
|
static int NextQuantumSymbolForModel(QuantumCoder *self,QuantumModel *model);
|
|
static void InitQuantumModel(QuantumModel *self,int numsymbols);
|
|
static void UpdateQuantumModel(QuantumModel *model,int index);
|
|
|
|
|
|
|
|
|
|
@implementation XADQuantumHandle
|
|
|
|
-(id)initWithBlockReader:(XADCABBlockReader *)blockreader windowBits:(int)windowbits
|
|
{
|
|
if((self=[super initWithBlockReader:blockreader]))
|
|
{
|
|
[self setInputBuffer:CSInputBufferAllocEmpty()];
|
|
|
|
InitializeLZSS(&lzss,1<<windowbits);
|
|
|
|
numslots6=windowbits*2;
|
|
|
|
if(numslots6>36) numslots5=36;
|
|
else numslots5=numslots6;
|
|
|
|
if(numslots6>24) numslots4=24;
|
|
else numslots4=numslots6;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
CleanupLZSS(&lzss);
|
|
[super dealloc];
|
|
}
|
|
|
|
-(void)resetCABBlockHandle
|
|
{
|
|
InitQuantumModel(&selectormodel,7);
|
|
|
|
for(int i=0;i<4;i++) InitQuantumModel(&literalmodel[i],64);
|
|
|
|
InitQuantumModel(&offsetmodel4,numslots4);
|
|
InitQuantumModel(&offsetmodel5,numslots5);
|
|
InitQuantumModel(&offsetmodel6,numslots6);
|
|
|
|
InitQuantumModel(&lengthmodel6,27);
|
|
|
|
RestartLZSS(&lzss);
|
|
}
|
|
|
|
-(int)produceCABBlockWithInputBuffer:(uint8_t *)buffer length:(int)complength atOffset:(off_t)pos length:(int)uncomplength
|
|
{
|
|
static int OffsetBaseTable[]=
|
|
{
|
|
0x00000,0x00001,0x00002,0x00003,0x00004,0x00006,0x00008,0x0000c,
|
|
0x00010,0x00018,0x00020,0x00030,0x00040,0x00060,0x00080,0x000c0,
|
|
0x00100,0x00180,0x00200,0x00300,0x00400,0x00600,0x00800,0x00c00,
|
|
0x01000,0x01800,0x02000,0x03000,0x04000,0x06000,0x08000,0x0c000,
|
|
0x10000,0x18000,0x20000,0x30000,0x40000,0x60000,0x80000,0xc0000,
|
|
0x100000,0x180000
|
|
};
|
|
static int OffsetAdditionalBitsTable[]=
|
|
{
|
|
0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,
|
|
11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19
|
|
};
|
|
|
|
static int LengthBaseTable[]=
|
|
{
|
|
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x08,0x0a,0x0c,0x0e,0x12,
|
|
0x16,0x1a,0x1e,0x26,0x2e,0x36,0x3e,0x4e,0x5e,0x6e,0x7e,0x9e,
|
|
0xbe,0xde,0xfe
|
|
};
|
|
|
|
static int LengthAdditionalBitsTable[] =
|
|
{
|
|
0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0
|
|
};
|
|
|
|
CSInputSetMemoryBuffer(input,buffer,complength,0);
|
|
InitQuantumCoder(&coder,input);
|
|
|
|
// int dicpos=pos&dictionarymask;
|
|
int end=(int)LZSSPosition(&lzss)+uncomplength;
|
|
|
|
[self setBlockPointer:CurrentLZSSWindowPointer(&lzss)];
|
|
|
|
while(LZSSPosition(&lzss)<end)
|
|
{
|
|
int selector=NextQuantumSymbolForModel(&coder,&selectormodel);
|
|
if(selector<4)
|
|
{
|
|
EmitLZSSLiteral(&lzss,NextQuantumSymbolForModel(&coder,&literalmodel[selector])+selector*64);
|
|
}
|
|
else
|
|
{
|
|
int offset,length;
|
|
if(selector==4)
|
|
{
|
|
length=3;
|
|
|
|
int offsetslot=NextQuantumSymbolForModel(&coder,&offsetmodel4);
|
|
offset=OffsetBaseTable[offsetslot]+
|
|
CSInputNextBitString(input,OffsetAdditionalBitsTable[offsetslot])+1;
|
|
}
|
|
else if(selector==5)
|
|
{
|
|
length=4;
|
|
|
|
int offsetslot=NextQuantumSymbolForModel(&coder,&offsetmodel5);
|
|
offset=OffsetBaseTable[offsetslot]+
|
|
CSInputNextBitString(input,OffsetAdditionalBitsTable[offsetslot])+1;
|
|
}
|
|
else //if(selector==6)
|
|
{
|
|
int lengthslot=NextQuantumSymbolForModel(&coder,&lengthmodel6);
|
|
length=LengthBaseTable[lengthslot]+
|
|
CSInputNextBitString(input,LengthAdditionalBitsTable[lengthslot])+5;
|
|
|
|
int offsetslot=NextQuantumSymbolForModel(&coder,&offsetmodel6);
|
|
offset=OffsetBaseTable[offsetslot]+
|
|
CSInputNextBitString(input,OffsetAdditionalBitsTable[offsetslot])+1;
|
|
}
|
|
|
|
EmitLZSSMatch(&lzss,offset,length);
|
|
}
|
|
}
|
|
return uncomplength;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
static void InitQuantumCoder(QuantumCoder *self,CSInputBuffer *input)
|
|
{
|
|
self->CS_L=0;
|
|
self->CS_H=0xffff;
|
|
self->CS_C=CSInputNextBitString(input,16);
|
|
self->input=input;
|
|
}
|
|
|
|
static uint16_t GetQuantumFrequency(QuantumCoder *self,uint16_t totfreq)
|
|
{
|
|
uint32_t range=((self->CS_H-self->CS_L)&0xffff)+1;
|
|
uint32_t freq=((self->CS_C-self->CS_L+1)*totfreq-1)/range;
|
|
return freq&0xffff;
|
|
}
|
|
|
|
static void RemoveQuantumCode(QuantumCoder *self,int cumfreqm1,int cumfreq,int totfreq)
|
|
{
|
|
uint32_t range=(self->CS_H-self->CS_L) + 1;
|
|
self->CS_H=self->CS_L+((cumfreqm1*range)/totfreq)-1;
|
|
self->CS_L=self->CS_L+(cumfreq*range)/totfreq;
|
|
|
|
for(;;)
|
|
{
|
|
if((self->CS_L&0x8000)!=(self->CS_H&0x8000))
|
|
{
|
|
if((self->CS_L&0x4000)&&!(self->CS_H&0x4000))
|
|
{
|
|
self->CS_C^=0x4000;
|
|
self->CS_L&=0x3fff;
|
|
self->CS_H|=0x4000;
|
|
}
|
|
else return;
|
|
}
|
|
self->CS_L<<=1;
|
|
self->CS_H=(self->CS_H<<1)|1;
|
|
self->CS_C=(self->CS_C<<1)|CSInputNextBit(self->input);
|
|
}
|
|
}
|
|
|
|
static int NextQuantumSymbolForModel(QuantumCoder *self,QuantumModel *model)
|
|
{
|
|
int freq=GetQuantumFrequency(self,model->symbols[0].cumfreq);
|
|
|
|
int i;
|
|
for(i=1;i<model->numsymbols;i++)
|
|
{
|
|
if(model->symbols[i].cumfreq<=freq) break;
|
|
}
|
|
|
|
int symbol=model->symbols[i-1].symbol;
|
|
|
|
RemoveQuantumCode(self,model->symbols[i-1].cumfreq,
|
|
model->symbols[i].cumfreq,model->symbols[0].cumfreq);
|
|
|
|
UpdateQuantumModel(model,i);
|
|
|
|
return symbol;
|
|
}
|
|
|
|
static void InitQuantumModel(QuantumModel *self,int numsymbols)
|
|
{
|
|
self->numsymbols=numsymbols;
|
|
self->shiftsleft=4;
|
|
for(int i=0;i<numsymbols;i++)
|
|
{
|
|
self->symbols[i].symbol=i;
|
|
self->symbols[i].cumfreq=numsymbols-i;
|
|
}
|
|
self->symbols[numsymbols].cumfreq=0;
|
|
}
|
|
|
|
static void UpdateQuantumModel(QuantumModel *self,int index)
|
|
{
|
|
for(int i=0;i<index;i++) self->symbols[i].cumfreq+=8;
|
|
|
|
if(self->symbols[0].cumfreq<=3800) return;
|
|
|
|
self->shiftsleft--;
|
|
if(self->shiftsleft)
|
|
{
|
|
for(int i=self->numsymbols-1;i>=0;i--)
|
|
{
|
|
self->symbols[i].cumfreq>>=1;
|
|
|
|
if(self->symbols[i].cumfreq<=self->symbols[i+1].cumfreq)
|
|
self->symbols[i].cumfreq=self->symbols[i+1].cumfreq+1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self->shiftsleft=50;
|
|
for(int i=0;i<self->numsymbols;i++)
|
|
{
|
|
self->symbols[i].cumfreq-=self->symbols[i+1].cumfreq;
|
|
self->symbols[i].cumfreq++;
|
|
self->symbols[i].cumfreq>>=1;
|
|
}
|
|
|
|
for(int i=0;i<self->numsymbols-1;i++)
|
|
{
|
|
for(int j=i+1;j<self->numsymbols;j++)
|
|
{
|
|
if(self->symbols[i].cumfreq<self->symbols[j].cumfreq)
|
|
{
|
|
QuantumModelSymbol temp=self->symbols[i];
|
|
self->symbols[i]=self->symbols[j];
|
|
self->symbols[j]=temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(int i=self->numsymbols-1;i>=0;i--)
|
|
self->symbols[i].cumfreq+=self->symbols[i+1].cumfreq;
|
|
}
|
|
}
|
|
|