Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions XADARCParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@

@interface XADARCParser:XADArchiveParser
{
BOOL isARC7;
}

+(int)requiredHeaderSize;
+(BOOL)recognizeFileWithHandle:(CSHandle *)handle firstBytes:(NSData *)data
name:(NSString *)name;

-(id)init;
-(void)parse;
-(CSHandle *)handleForEntryWithDictionary:(NSDictionary *)dict wantChecksum:(BOOL)checksum;
-(NSString *)formatName;
Expand Down
69 changes: 63 additions & 6 deletions XADARCParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#import "XADARCCrunchHandle.h"
#import "XADARCCrushHandle.h"
#import "XADARCDistillHandle.h"
#import "XADLZHDynamicHandle.h"
#import "XADRLE90Handle.h"
#import "XADSqueezeHandle.h"
#import "XADCompressHandle.h"
Expand Down Expand Up @@ -93,6 +94,28 @@ static BOOL IsARCHeader(const uint8_t *bytes,int length,BOOL acceptloader)
}
}

static BOOL IsARC7Header(const uint8_t *bytes,int length)
{
if(length<0x1d) return NO;

// Check ID.
if(bytes[0x00]!=0x1a) return NO;

// Method == 20
if(bytes[0x01]!=0x14) return NO;

// Name is an empty string
if(bytes[0x02]!=0) return NO;

// Uncompressed size == 0
if(bytes[25]!=0) return NO;
if(bytes[26]!=0) return NO;
if(bytes[27]!=0) return NO;
if(bytes[28]!=0) return NO;

return YES;
}

@implementation XADARCParser

+(int)requiredHeaderSize { return 0x1d; }
Expand All @@ -103,7 +126,16 @@ +(BOOL)recognizeFileWithHandle:(CSHandle *)handle firstBytes:(NSData *)data
const uint8_t *bytes=[data bytes];
int length=[data length];

return IsARCHeader(bytes,length,NO);
return IsARC7Header(bytes,length) || IsARCHeader(bytes,length,NO);
}

-(id)init
{
if((self=[super init]))
{
isARC7 = NO;
}
return self;
}

-(void)parse
Expand Down Expand Up @@ -177,6 +209,18 @@ -(void)parse

parent=path;
}
else if (method==0x14)
{
// Generated by SEA ARC 7; method 10 is Trim
if (namebuf[0]==0 && uncompsize==0)
isARC7 = YES;
[fh seekToFileOffset:dataoffset+compsize];
}
else if (method==0x15)
{
// SEA ARC file comment
[fh seekToFileOffset:dataoffset+compsize];
}
else
{
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:
Expand All @@ -202,7 +246,12 @@ -(void)parse
case 0x07: methodname=@"Crunched (fast)"; break;
case 0x08: methodname=@"Crunched (LZW)"; break;
case 0x09: methodname=@"Squashed"; break;
case 0x0a: methodname=@"Crushed"; break;
case 0x0a:
if (isARC7)
methodname=@"Trimmed";
else
methodname=@"Crushed";
break;
case 0x0b: methodname=@"Distilled"; break;
case 0x7f: methodname=@"Compressed"; break;
}
Expand Down Expand Up @@ -298,9 +347,17 @@ -(CSHandle *)handleForEntryWithDictionary:(NSDictionary *)dict wantChecksum:(BOO
length:length flags:0x8d] autorelease];
break;

case 0x0a: // Crushed
handle=[[[XADARCCrushHandle alloc] initWithHandle:handle] autorelease];

case 0x0a:
if (isARC7) // Trimmed
// Pass 0xffffffff as the length because some files get
// truncated if we pass the actual length. We need to rely on
// the stop code in the compressed data.
handle=[[[XADLZHDynamicHandle alloc] initWithHandle:handle length:0xffffffff
hasStopCode:YES] autorelease];
else // Crushed
handle=[[[XADARCCrushHandle alloc] initWithHandle:handle] autorelease];

// Both Trim and Crush use RLE90 on output
handle=[[[XADRLE90Handle alloc] initWithHandle:handle
length:length] autorelease];
break;
Expand Down Expand Up @@ -381,7 +438,7 @@ +(BOOL)recognizeFileWithHandle:(CSHandle *)handle firstBytes:(NSData *)data
{
for(int i=2;i<=length-0x1d /*&& i<0x10000-0x1d*/;i++)
{
if(IsARCHeader(&bytes[i],length-i,NO))
if(IsARC7Header(&bytes[i],length-i) || IsARCHeader(&bytes[i],length-i,NO))
{
[props setObject:[NSNumber numberWithInt:i] forKey:@"ARCSFXOffset"];
return YES;
Expand Down
2 changes: 2 additions & 0 deletions XADLZHDynamicHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ struct XADLZHDynamicNode
{
XADPrefixCode *distancecode;
XADLZHDynamicNode *nodes[314*2-1],nodestorage[314*2-1];
BOOL hasstopcode;
}

-(id)initWithHandle:(CSHandle *)handle length:(off_t)length;
-(id)initWithHandle:(CSHandle *)handle length:(off_t)length hasStopCode:(BOOL)hasStopCode;
-(void)dealloc;

-(void)resetLZSSHandle;
Expand Down
10 changes: 10 additions & 0 deletions XADLZHDynamicHandle.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
@implementation XADLZHDynamicHandle

-(id)initWithHandle:(CSHandle *)handle length:(off_t)length
{
return [self initWithHandle:handle length:length hasStopCode:NO];
}

-(id)initWithHandle:(CSHandle *)handle length:(off_t)length hasStopCode:(BOOL)hasStopCode
{
if((self=[super initWithInputBufferForHandle:handle length:length windowSize:4096]))
{
Expand All @@ -37,6 +42,7 @@ -(id)initWithHandle:(CSHandle *)handle length:(off_t)length

distancecode=[[XADPrefixCode alloc] initWithLengths:lengths numberOfSymbols:64
maximumLength:8 shortestCodeIsZeros:YES];
hasstopcode=hasStopCode;
}
return self;
}
Expand Down Expand Up @@ -96,9 +102,13 @@ -(int)nextLiteralOrOffset:(int *)offset andLength:(int *)length atPosition:(off_
int lit=node->value;

if(lit<0x100) return lit;
else if (lit==0x100 && hasstopcode)
return XADLZSSEnd;
else
{
*length=lit-0x100+3;
if (hasstopcode)
--(*length);

int highbits=CSInputNextSymbolUsingCode(input,distancecode);
int lowbits=CSInputNextBitString(input,6);
Expand Down