mirror of
https://github.com/MacPaw/XADMaster.git
synced 2025-08-28 19:13:49 +02:00
352 lines
7.8 KiB
Objective-C
352 lines
7.8 KiB
Objective-C
/*
|
|
* XADStuffItXIronHandle.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 "XADStuffItXIronHandle.h"
|
|
#import "XADException.h"
|
|
#import "StuffItXUtilities.h"
|
|
#import "CarrylessRangeCoder.h"
|
|
#import "BWT.h"
|
|
|
|
|
|
|
|
static int NextBitWithWeight(CarrylessRangeCoder *coder,uint32_t *weight,int shift)
|
|
{
|
|
int bit=NextWeightedBitFromRangeCoder(coder,*weight,0x1000);
|
|
if(bit==0) *weight+=(0x1000-*weight)>>shift;
|
|
else *weight-=*weight>>shift;
|
|
return bit;
|
|
}
|
|
|
|
static int NextBitWithDoubleWeights(CarrylessRangeCoder *coder,uint32_t *weight1,int shift1,uint32_t *weight2,int shift2)
|
|
{
|
|
int bit=NextWeightedBitFromRangeCoder(coder,(*weight1+*weight2)/2,0x1000);
|
|
if(bit==0)
|
|
{
|
|
*weight1+=(0x1000-*weight1)>>shift1;
|
|
*weight2+=(0x1000-*weight2)>>shift2;
|
|
}
|
|
else
|
|
{
|
|
*weight1-=*weight1>>shift1;
|
|
*weight2-=*weight2>>shift2;
|
|
}
|
|
return bit;
|
|
}
|
|
|
|
|
|
|
|
@implementation XADStuffItXIronHandle
|
|
|
|
-(id)initWithHandle:(CSHandle *)handle length:(off_t)length
|
|
{
|
|
if((self=[super initWithInputBufferForHandle:handle length:length]))
|
|
{
|
|
block=NULL;
|
|
currsize=0;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
free(block);
|
|
[super dealloc];
|
|
}
|
|
|
|
-(void)resetBlockStream
|
|
{
|
|
st4transform=CSInputNextBitLE(input);
|
|
fancymtf=CSInputNextBitLE(input);
|
|
|
|
maxfreq1=1<<CSInputNextSitxP2(input);
|
|
maxfreq2=1<<CSInputNextSitxP2(input);
|
|
maxfreq3=1<<CSInputNextSitxP2(input);
|
|
|
|
byteshift1=(unsigned int)CSInputNextSitxP2(input);
|
|
byteshift2=(unsigned int)CSInputNextSitxP2(input);
|
|
byteshift3=(unsigned int)CSInputNextSitxP2(input);
|
|
countshift1=(unsigned int)CSInputNextSitxP2(input);
|
|
countshift2=(unsigned int)CSInputNextSitxP2(input);
|
|
countshift3=(unsigned int)CSInputNextSitxP2(input);
|
|
}
|
|
|
|
-(int)produceBlockAtOffset:(off_t)pos
|
|
{
|
|
CSInputSkipToByteBoundary(input);
|
|
|
|
if(CSInputNextBitLE(input)==1) return -1;
|
|
|
|
unsigned int blocksize=(unsigned int)CSInputNextSitxP2(input);
|
|
|
|
if(blocksize>currsize)
|
|
{
|
|
free(block);
|
|
block=malloc(blocksize*6);
|
|
if(!block) [XADException raiseOutOfMemoryException];
|
|
sorted=block+blocksize;
|
|
table=(uint32_t *)(block+2*blocksize);
|
|
currsize=blocksize;
|
|
}
|
|
|
|
if(CSInputNextBitLE(input)==0) // compressed
|
|
{
|
|
unsigned int firstindex=(int)CSInputNextSitxP2(input);
|
|
if(firstindex>=blocksize) [XADException raiseDecrunchException];
|
|
|
|
CSInputSkipToByteBoundary(input);
|
|
|
|
[self decodeBlockWithLength:blocksize];
|
|
|
|
if(st4transform)
|
|
{
|
|
if(!UnsortST4(block,sorted,blocksize,firstindex,table)) [XADException raiseDecrunchException];
|
|
}
|
|
else
|
|
{
|
|
UnsortBWT(block,sorted,blocksize,firstindex,table);
|
|
}
|
|
}
|
|
else // uncompressed
|
|
{
|
|
CSInputSkipToByteBoundary(input); // necessary?
|
|
for(int i=0;i<blocksize;i++) block[i]=CSInputNextByte(input);
|
|
}
|
|
|
|
[self setBlockPointer:block];
|
|
return blocksize;
|
|
}
|
|
|
|
-(void)decodeBlockWithLength:(int)blocksize
|
|
{
|
|
uint32_t mainfrequencies[4];
|
|
uint32_t lastbytefrequencies[256][4];
|
|
uint32_t somethingfrequencies[4][256][4];
|
|
|
|
uint32_t bytelengthweights[8];
|
|
uint32_t bytelengthweights2[8][8];
|
|
uint32_t bytebitweights[8][128];
|
|
|
|
uint32_t countlengthweights[4][16][24];
|
|
uint32_t countlengthweights2[256][24];
|
|
uint32_t countbitweights[24][24];
|
|
|
|
uint8_t mtfbuffer[256];
|
|
uint32_t numbytes;
|
|
uint32_t intarray1[257];
|
|
uint32_t intarray2[257];
|
|
uint32_t intarray3[257];
|
|
|
|
for(int i=0;i<4;i++) mainfrequencies[i]=1;
|
|
|
|
for(int i=0;i<256;i++)
|
|
for(int j=0;j<4;j++) lastbytefrequencies[i][j]=0;
|
|
|
|
for(int i=0;i<4;i++)
|
|
for(int j=0;j<256;j++)
|
|
for(int k=0;k<4;k++) somethingfrequencies[i][j][k]=0;
|
|
|
|
for(int i=0;i<8;i++) bytelengthweights[i]=0x800;
|
|
|
|
for(int i=0;i<8;i++)
|
|
for(int j=0;j<8;j++) bytelengthweights2[i][j]=0x800;
|
|
|
|
for(int i=0;i<8;i++)
|
|
for(int j=0;j<128;j++) bytebitweights[i][j]=0x800;
|
|
|
|
for(int i=0;i<4;i++)
|
|
for(int j=0;j<16;j++)
|
|
for(int k=0;k<24;k++) countlengthweights[i][j][k]=0x800;
|
|
|
|
for(int i=0;i<256;i++)
|
|
for(int j=0;j<24;j++) countlengthweights2[i][j]=0x800;
|
|
|
|
for(int i=0;i<24;i++)
|
|
for(int j=0;j<24;j++) countbitweights[i][j]=0x800;
|
|
|
|
if(fancymtf)
|
|
{
|
|
for(int i=0;i<257;i++)
|
|
{
|
|
intarray1[i]=i;
|
|
intarray2[i]=i;
|
|
intarray3[i]=0;
|
|
}
|
|
intarray3[256]=-1; // unnecessary?
|
|
|
|
numbytes=0;
|
|
}
|
|
else
|
|
{
|
|
for(int i=0;i<256;i++) mtfbuffer[i]=i;
|
|
}
|
|
|
|
|
|
|
|
CarrylessRangeCoder coder;
|
|
|
|
CSInputSkipBytes(input,1);
|
|
InitializeRangeCoder(&coder,input,NO,0);
|
|
|
|
int valuehistory=0,lengthhistory=0,lastbits=0,lastbyte=0;
|
|
|
|
for(int i=0;i<blocksize;)
|
|
{
|
|
uint32_t *freqs1=mainfrequencies;
|
|
uint32_t *freqs2=lastbytefrequencies[lastbyte];
|
|
uint32_t *freqs3=somethingfrequencies[lengthhistory&3][valuehistory];
|
|
uint32_t frequencies[4];
|
|
for(int j=0;j<4;j++) frequencies[j]=freqs1[j]+freqs2[j]+freqs3[j];
|
|
|
|
int symbol=NextSymbolFromRangeCoder(&coder,frequencies,4);
|
|
|
|
freqs1[symbol]+=2;
|
|
freqs2[symbol]+=2;
|
|
freqs3[symbol]+=2;
|
|
|
|
uint32_t total1=0,total2=0,total3=0;
|
|
for(int j=0;j<4;j++)
|
|
{
|
|
total1+=freqs1[j];
|
|
total2+=freqs2[j];
|
|
total3+=freqs3[j];
|
|
}
|
|
|
|
if(total1>maxfreq1) for(int j=0;j<4;j++) freqs1[j]=(freqs1[j]+1)/2;
|
|
if(total2>maxfreq2) for(int j=0;j<4;j++) freqs2[j]/=2;
|
|
if(total3>maxfreq3) for(int j=0;j<4;j++) freqs3[j]/=2;
|
|
|
|
int value;
|
|
if(symbol!=3) value=symbol;
|
|
else
|
|
{
|
|
int bits=0;
|
|
while(bits<6)
|
|
{
|
|
int bit=NextBitWithDoubleWeights(&coder,
|
|
&bytelengthweights[bits],byteshift1,
|
|
&bytelengthweights2[lastbits][bits],byteshift2);
|
|
if(bit==0) break;
|
|
bits++;
|
|
}
|
|
|
|
value=1;
|
|
for(int j=0;j<=bits;j++)
|
|
{
|
|
int bit=NextBitWithWeight(&coder,&bytebitweights[bits][value],byteshift3);
|
|
value=(value<<1)|bit;
|
|
}
|
|
value++;
|
|
|
|
lastbits=bits;
|
|
}
|
|
|
|
int byte;
|
|
if(fancymtf)
|
|
{
|
|
int index=(value+1)&0xff;
|
|
|
|
byte=intarray1[index]&0xff;
|
|
block[numbytes]=byte;
|
|
|
|
intarray3[byte]+=0x4000;
|
|
|
|
for(int i=intarray2[byte];i>0;i--)
|
|
{
|
|
intarray1[i]=intarray1[i-1];
|
|
intarray2[intarray1[i-1]]=i;
|
|
}
|
|
|
|
intarray1[0]=byte;
|
|
intarray2[byte]=0;
|
|
|
|
for(int j=0;j<12;j++)
|
|
{
|
|
int n=1<<j;
|
|
if(n<=numbytes)
|
|
{
|
|
int b2=block[numbytes-n];
|
|
|
|
if(j==0) intarray3[b2]-=0x3801;
|
|
else intarray3[b2]-=0x800>>j;
|
|
|
|
if(b2!=byte)
|
|
{
|
|
uint32_t val=intarray2[b2];
|
|
while(intarray3[intarray1[val+1]]>intarray3[b2])
|
|
{
|
|
intarray1[val]=intarray1[val+1];
|
|
intarray2[intarray1[val+1]]=val;
|
|
val++;
|
|
}
|
|
intarray1[val]=b2;
|
|
intarray2[b2]=val;
|
|
}
|
|
}
|
|
}
|
|
|
|
numbytes++;
|
|
}
|
|
else
|
|
{
|
|
int index=(value+1)&0xff;
|
|
byte=mtfbuffer[index];
|
|
memmove(mtfbuffer+1,mtfbuffer,index);
|
|
mtfbuffer[0]=byte;
|
|
}
|
|
|
|
int shortvalue;
|
|
if(value<=3) shortvalue=value;
|
|
else shortvalue=3;
|
|
|
|
int bits=0;
|
|
for(;;)
|
|
{
|
|
int bit=NextBitWithDoubleWeights(&coder,
|
|
&countlengthweights[shortvalue][lengthhistory][bits],countshift1,
|
|
&countlengthweights2[byte][bits],countshift2);
|
|
if(bit==0) break;
|
|
|
|
bits++;
|
|
if(bits>=24) [XADException raiseIllegalDataException];
|
|
}
|
|
|
|
int count=1;
|
|
for(int j=0;j<bits;j++)
|
|
{
|
|
int bit=NextBitWithWeight(&coder,&countbitweights[bits][j],countshift3);
|
|
count=(count<<1)|bit;
|
|
}
|
|
|
|
for(int j=0;j<count;j++)
|
|
{
|
|
if(i>=blocksize) [XADException raiseIllegalDataException];
|
|
sorted[i++]=byte;
|
|
}
|
|
|
|
valuehistory=((valuehistory<<2)|shortvalue)&0xff;
|
|
|
|
lengthhistory=((lengthhistory<<1)&0x0e);
|
|
if(bits>1) lengthhistory|=1;
|
|
|
|
lastbyte=byte;
|
|
}
|
|
}
|
|
|
|
@end
|