XADMaster/XADLZXHandle.m
2018-03-21 14:24:50 +02:00

211 lines
4.9 KiB
Objective-C

/*
* XADLZXHandle.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 "XADLZXHandle.h"
#import "XADException.h"
@implementation XADLZXHandle
-(id)initWithHandle:(CSHandle *)handle length:(off_t)length
{
if((self=[super initWithInputBufferForHandle:[[[XADLZXSwapHandle alloc] initWithHandle:handle] autorelease]
length:length windowSize:65536]))
{
maincode=offsetcode=nil;
}
return self;
}
-(void)dealloc
{
[maincode release];
[offsetcode release];
[super dealloc];
}
-(void)resetLZSSHandle
{
lastoffs=1;
blockend=0;
memset(mainlengths,0,sizeof(mainlengths));
}
-(int)nextLiteralOrOffset:(int *)offset andLength:(int *)length atPosition:(off_t)pos
{
static const unsigned char AdditionalBitsTable[32]=
{
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
};
static const unsigned int BaseTable[32]=
{
0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,
1536,2048,3072,4096,6144,8192,12288,16384,24576,32768,49152
};
if(pos>=blockend) [self readBlockHeaderAtPosition:pos];
int symbol=CSInputNextSymbolUsingCodeLE(input,maincode);
if(symbol<256) return symbol;
int offsclass=symbol&31;
int offs=BaseTable[offsclass];
int offsbits=AdditionalBitsTable[offsclass];
if(offs==0)
{
offs=lastoffs;
}
else if(blocktype==3 && offsbits>=3)
{
offs+=CSInputNextBitStringLE(input,offsbits-3)<<3;
offs+=CSInputNextSymbolUsingCodeLE(input,offsetcode);
}
else
{
offs+=CSInputNextBitStringLE(input,offsbits);
}
int lenclass=((symbol-256)>>5)&15;
int len=BaseTable[lenclass]+3;
int lenbits=AdditionalBitsTable[lenclass];
len+=CSInputNextBitStringLE(input,lenbits);
*offset=offs;
*length=len;
lastoffs=offs;
return XADLZSSMatch;
}
-(void)readBlockHeaderAtPosition:(off_t)pos
{
[maincode release];
[offsetcode release];
maincode=offsetcode=nil;
blocktype=CSInputNextBitStringLE(input,3);
if(blocktype<1||blocktype>3) [XADException raiseIllegalDataException];
if(blocktype==1) [XADException raiseNotSupportedException]; // Never encountered one of these?
if(blocktype==3)
{
int codelengths[8];
for(int i=0;i<8;i++) codelengths[i]=CSInputNextBitStringLE(input,3);
offsetcode=[[XADPrefixCode alloc] initWithLengths:codelengths
numberOfSymbols:8 maximumLength:7 shortestCodeIsZeros:YES];
}
int blocksize=CSInputNextBitStringLE(input,8)<<16;
blocksize|=CSInputNextBitStringLE(input,8)<<8;
blocksize|=CSInputNextBitStringLE(input,8);
blockend=pos+blocksize;
if(blocktype!=1)
{
[self readDeltaLengths:&mainlengths[0] count:256 alternateMode:NO];
[self readDeltaLengths:&mainlengths[256] count:512 alternateMode:YES];
maincode=[[XADPrefixCode alloc] initWithLengths:mainlengths
numberOfSymbols:768 maximumLength:16 shortestCodeIsZeros:YES];
}
}
-(void)readDeltaLengths:(int *)lengths count:(int)count alternateMode:(BOOL)altmode;
{
XADPrefixCode *precode=nil;
int fix=altmode?1:0;
@try
{
int prelengths[20];
for(int i=0;i<20;i++) prelengths[i]=CSInputNextBitStringLE(input,4);
precode=[[XADPrefixCode alloc] initWithLengths:prelengths
numberOfSymbols:20 maximumLength:15 shortestCodeIsZeros:YES];
int i=0;
while(i<count)
{
int val=CSInputNextSymbolUsingCodeLE(input,precode);
int n,length;
if(val<=16)
{
n=1;
length=(lengths[i]+17-val)%17;
}
else if(val==17)
{
n=CSInputNextBitStringLE(input,4)+4-fix;
length=0;
}
else if(val==18)
{
n=CSInputNextBitStringLE(input,5+fix)+20-fix;
length=0;
}
else if(val==19)
{
n=CSInputNextBitStringLE(input,1)+4-fix;
int newval=CSInputNextSymbolUsingCodeLE(input,precode);
length=(lengths[i]+17-newval)%17;
}
if(i+n>count) [XADException raiseDecrunchException];
for(int j=0;j<n;j++) lengths[i+j]=length;
i+=n;
}
[precode release];
}
@catch(id e)
{
[precode release];
@throw;
}
}
@end
@implementation XADLZXSwapHandle
-(id)initWithHandle:(CSHandle *)handle
{
return [super initWithInputBufferForHandle:handle];
}
-(uint8_t)produceByteAtOffset:(off_t)pos
{
if(pos&1) return otherbyte;
if(CSInputAtEOF(input)) CSByteStreamEOF(self);
otherbyte=CSInputNextByte(input);
if(CSInputAtEOF(input)) CSByteStreamEOF(self);
return CSInputNextByte(input);
}
@end