mirror of
https://github.com/MacPaw/XADMaster.git
synced 2025-08-28 19:13:49 +02:00
256 lines
6 KiB
Objective-C
256 lines
6 KiB
Objective-C
/*
|
|
* XADDiskDoublerDDnHandle.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 "XADDiskDoublerDDnHandle.h"
|
|
#import "XADException.h"
|
|
|
|
@implementation XADDiskDoublerDDnHandle
|
|
|
|
-(id)initWithHandle:(CSHandle *)handle length:(off_t)length
|
|
{
|
|
if((self=[super initWithInputBufferForHandle:handle length:length windowSize:65536]))
|
|
{
|
|
lengthcode=nil;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
[lengthcode release];
|
|
[super dealloc];
|
|
}
|
|
|
|
-(void)resetLZSSHandle
|
|
{
|
|
nextblock=0;
|
|
blockend=0;
|
|
literalsleft=0;
|
|
correctxor=0;
|
|
checksumcorrect=YES;
|
|
}
|
|
|
|
-(int)nextLiteralOrOffset:(int *)offsetout andLength:(int *)lengthout atPosition:(off_t)pos
|
|
{
|
|
if(pos>=blockend) [self readBlockAtPosition:pos];
|
|
|
|
if(uncompressed) return CSInputNextByte(input);
|
|
|
|
if(literalsleft)
|
|
{
|
|
literalsleft--;
|
|
// TODO: check for literals left
|
|
return *literalptr++;
|
|
}
|
|
|
|
int code=CSInputNextSymbolUsingCode(input,lengthcode);
|
|
if(code==0)
|
|
{
|
|
// TODO: check for literals left
|
|
return *literalptr++;
|
|
}
|
|
else if(code<128)
|
|
{
|
|
int length=code+2;
|
|
// TODO: check for offsets left
|
|
int offset=*offsetptr++;
|
|
|
|
if(offset>pos) [XADException raiseIllegalDataException];
|
|
if(pos+length>blockend) length=(int)(blockend-pos);
|
|
|
|
*offsetout=offset;
|
|
*lengthout=length;
|
|
return XADLZSSMatch;
|
|
}
|
|
else
|
|
{
|
|
int length=1<<(code-128);
|
|
|
|
if(pos+length>blockend) length=(int)(blockend-pos);
|
|
// TODO: check for literals left
|
|
|
|
literalsleft=length-1;
|
|
return *literalptr++;
|
|
}
|
|
}
|
|
|
|
-(void)readBlockAtPosition:(off_t)pos
|
|
{
|
|
NSAutoreleasePool *pool=[NSAutoreleasePool new];
|
|
|
|
if(blocksize<=65536)
|
|
{
|
|
int xor=0;
|
|
for(int i=0;i<blocksize;i++) xor^=windowbuffer[(pos-blocksize+i)&windowmask];
|
|
if(xor!=correctxor) checksumcorrect=NO;
|
|
}
|
|
|
|
CSInputSeekToBufferOffset(input,nextblock);
|
|
|
|
uint8_t headxor=0;
|
|
|
|
uint32_t uncompsize=CSInputNextUInt32BE(input);
|
|
headxor^=uncompsize^(uncompsize>>8)^(uncompsize>>16)^(uncompsize>>24);
|
|
|
|
int numliterals=CSInputNextUInt16BE(input);
|
|
headxor^=numliterals^(numliterals>>8);
|
|
|
|
int numoffsets=CSInputNextUInt16BE(input);
|
|
headxor^=numoffsets^(numoffsets>>8);
|
|
|
|
int lengthcompsize=CSInputNextUInt16BE(input);
|
|
headxor^=lengthcompsize^(lengthcompsize>>8);
|
|
|
|
int literalcompsize=CSInputNextUInt16BE(input);
|
|
headxor^=literalcompsize^(literalcompsize>>8);
|
|
|
|
int offsetcompsize=CSInputNextUInt16BE(input);
|
|
headxor^=offsetcompsize^(offsetcompsize>>8);
|
|
|
|
int flags=CSInputNextByte(input);
|
|
headxor^=flags;
|
|
|
|
headxor^=CSInputNextByte(input);
|
|
|
|
int datacorrectxor1=CSInputNextByte(input);
|
|
headxor^=datacorrectxor1;
|
|
|
|
int datacorrectxor2=CSInputNextByte(input);
|
|
headxor^=datacorrectxor2;
|
|
|
|
int datacorrectxor3=CSInputNextByte(input);
|
|
headxor^=datacorrectxor3;
|
|
|
|
int uncompcorrectxor=CSInputNextByte(input);
|
|
headxor^=uncompcorrectxor;
|
|
|
|
headxor^=CSInputNextByte(input);
|
|
|
|
int headcorrectxor=CSInputNextByte(input);
|
|
if(headxor!=headcorrectxor) [XADException raiseIllegalDataException];
|
|
|
|
//NSLog(@"%d (%d %d) %d %d %d %x <%x %x %x %x>",uncompsize,numliterals,numoffsets,lengthcompsize,literalcompsize,offsetcompsize,
|
|
//flags,datacorrectxor1,datacorrectxor2,datacorrectxor3,uncompcorrectxor);
|
|
|
|
blocksize=uncompsize;
|
|
blockend=pos+uncompsize;
|
|
correctxor=uncompcorrectxor;
|
|
|
|
if(flags&0x40)
|
|
{
|
|
uncompressed=YES;
|
|
[pool release];
|
|
return;
|
|
}
|
|
|
|
off_t literalstart=CSInputBufferOffset(input)+offsetcompsize;
|
|
off_t lengthstart=literalstart+literalcompsize;
|
|
nextblock=lengthstart+lengthcompsize;
|
|
|
|
if(numliterals+numoffsets*2>sizeof(buffer)) [XADException raiseIllegalDataException];
|
|
|
|
literalptr=buffer;
|
|
offsetptr=(uint16_t *)&buffer[numliterals];
|
|
|
|
XADPrefixCode *offsetcode=[self readCode];
|
|
|
|
for(int i=0;i<numoffsets;i++)
|
|
{
|
|
int slot=CSInputNextSymbolUsingCode(input,offsetcode);
|
|
|
|
if(slot<4)
|
|
{
|
|
offsetptr[i]=slot+1;
|
|
}
|
|
else
|
|
{
|
|
int bits=slot/2-1;
|
|
int start=((2+(slot&1))<<bits)+1;
|
|
offsetptr[i]=start+CSInputNextBitString(input,bits);
|
|
}
|
|
}
|
|
|
|
CSInputSeekToBufferOffset(input,literalstart);
|
|
|
|
if(flags&0x80)
|
|
{
|
|
XADPrefixCode *literalcode=[self readCode];
|
|
|
|
// Compressed literals
|
|
for(int i=0;i<numliterals;i++) literalptr[i]=CSInputNextSymbolUsingCode(input,literalcode);
|
|
}
|
|
else
|
|
{
|
|
// Uncompressed literals
|
|
for(int i=0;i<numliterals;i++) literalptr[i]=CSInputNextByte(input);
|
|
}
|
|
|
|
CSInputSeekToBufferOffset(input,lengthstart);
|
|
|
|
[lengthcode release];
|
|
lengthcode=[[self readCode] retain];
|
|
|
|
[pool release];
|
|
}
|
|
|
|
-(XADPrefixCode *)readCode
|
|
{
|
|
uint32_t head=CSInputNextUInt32BE(input);
|
|
|
|
int numcodes=((head>>24)&0xff)+1;
|
|
int numbytes=(head>>13)&0x7ff;
|
|
int maxlength=(head>>8)&0x1f;
|
|
int numbits=(head>>3)&0x1f;
|
|
int codelengths[numcodes];
|
|
|
|
off_t end=CSInputBufferOffset(input)+numbytes;
|
|
|
|
if(head&0x04) // uses zero coding
|
|
{
|
|
for(int i=0;i<numcodes;i++)
|
|
{
|
|
if(CSInputNextBit(input))
|
|
{
|
|
codelengths[i]=CSInputNextBitString(input,numbits);
|
|
if(codelengths[i]>maxlength) [XADException raiseIllegalDataException];
|
|
}
|
|
else codelengths[i]=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int i=0;i<numcodes;i++)
|
|
{
|
|
codelengths[i]=CSInputNextBitString(input,numbits);
|
|
if(codelengths[i]>maxlength) [XADException raiseIllegalDataException];
|
|
}
|
|
}
|
|
|
|
CSInputSeekToBufferOffset(input,end);
|
|
|
|
return [XADPrefixCode prefixCodeWithLengths:codelengths numberOfSymbols:numcodes
|
|
maximumLength:maxlength shortestCodeIsZeros:YES];
|
|
}
|
|
|
|
-(BOOL)hasChecksum { return YES; }
|
|
|
|
-(BOOL)isChecksumCorrect { return streampos==blockend && checksumcorrect; }
|
|
|
|
@end
|