mirror of
https://github.com/MacPaw/XADMaster.git
synced 2025-08-29 03:23:48 +02:00
197 lines
6.1 KiB
Objective-C
197 lines
6.1 KiB
Objective-C
/*
|
|
* XADLZXParser.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 "XADLZXParser.h"
|
|
#import "XADLZXHandle.h"
|
|
#import "XADCRCHandle.h"
|
|
#import "NSDateXAD.h"
|
|
|
|
|
|
|
|
@implementation XADLZXParser
|
|
|
|
+(int)requiredHeaderSize { return 10; }
|
|
|
|
+(BOOL)recognizeFileWithHandle:(CSHandle *)handle firstBytes:(NSData *)data name:(NSString *)name
|
|
{
|
|
const uint8_t *bytes=[data bytes];
|
|
int length=[data length];
|
|
|
|
return length>=10&&bytes[0]=='L'&&bytes[1]=='Z'&&bytes[2]=='X';
|
|
}
|
|
|
|
-(void)parse
|
|
{
|
|
CSHandle *fh=[self handle];
|
|
|
|
[fh skipBytes:10];
|
|
|
|
NSMutableArray *solidfiles=[NSMutableArray array];
|
|
off_t solidsize=0;
|
|
|
|
while([self shouldKeepParsing])
|
|
{
|
|
int attributes;
|
|
@try { attributes=[fh readUInt16LE]; }
|
|
@catch(id e) { break; }
|
|
|
|
uint32_t filesize=[fh readUInt32LE];
|
|
uint32_t compsize=[fh readUInt32LE];
|
|
int os=[fh readUInt8];
|
|
int method=[fh readUInt8];
|
|
int flags=[fh readUInt16LE];
|
|
int commentlen=[fh readUInt8];
|
|
int version=[fh readUInt8];
|
|
[fh skipBytes:2];
|
|
uint32_t date=[fh readUInt32LE];
|
|
uint32_t datacrc=[fh readUInt32LE];
|
|
/*uint32_t headercrc=*/[fh readUInt32LE];
|
|
int namelen=[fh readUInt8];
|
|
|
|
NSData *namedata=[fh readDataOfLength:namelen];
|
|
NSData *commentdata=nil;
|
|
if(commentlen) commentdata=[fh readDataOfLength:commentlen];
|
|
|
|
off_t dataoffs=[fh offsetInFile];
|
|
|
|
int day=(date>>27)&31;
|
|
int month=((date>>23)&15)+1;
|
|
int year=((date>>17)&63)+1970;
|
|
int hour=(date>>12)&31;
|
|
int minute=(date>>6)&63;
|
|
int second=(date&63);
|
|
|
|
// From libxad LZX:
|
|
if(year>=2028) year+=2000-2028; // Original LZX
|
|
else if(year<1978) year+=2034-1970; // Dr.Titus
|
|
// Dates from 1978 to 1999 are correct
|
|
// Dates from 2000 to 2027 Mikolaj patch are correct
|
|
// Dates from 2000 to 2005 LZX/Dr.Titus patch are correct
|
|
// Dates from 2034 to 2041 Dr.Titus patch are correct
|
|
|
|
NSDate *dateobj=[NSDate XADDateWithYear:year month:month day:day hour:hour minute:minute second:second timeZone:nil];
|
|
|
|
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:
|
|
[self XADPathWithData:namedata separators:XADUnixPathSeparator],XADFileNameKey,
|
|
[NSNumber numberWithUnsignedLong:filesize],XADFileSizeKey,
|
|
[NSNumber numberWithUnsignedLong:filesize],XADSolidLengthKey,
|
|
[NSNumber numberWithLongLong:solidsize],XADSolidOffsetKey,
|
|
//[NSNumber numberWithUnsignedLong:compsize],XADCompressedSizeKey,
|
|
dateobj,XADLastModificationDateKey,
|
|
[NSNumber numberWithInt:os],@"LZXOS",
|
|
[NSNumber numberWithInt:method],@"LZXMethod",
|
|
[NSNumber numberWithInt:flags],@"LZXFlags",
|
|
[NSNumber numberWithInt:version],@"LZXVersion",
|
|
[NSNumber numberWithInt:datacrc],@"LZXCRC32",
|
|
nil];
|
|
|
|
NSString *methodname=nil;
|
|
switch(method)
|
|
{
|
|
case 0: methodname=@"None"; break;
|
|
case 2: methodname=@"LZX"; break;
|
|
}
|
|
if(methodname) [dict setObject:[self XADStringWithString:methodname] forKey:XADCompressionNameKey];
|
|
|
|
NSString *osname=nil;
|
|
switch(os)
|
|
{
|
|
case 0: osname=@"MSDOS"; break;
|
|
case 1: osname=@"Windows"; break;
|
|
case 2: osname=@"OS/2"; break;
|
|
case 10: osname=@"Amiga"; break;
|
|
case 20: osname=@"Unix"; break;
|
|
}
|
|
if(osname) [dict setObject:[self XADStringWithString:osname] forKey:@"LZXOSName"];
|
|
|
|
if(os==10)
|
|
{
|
|
// Decode Amiga protection bits
|
|
int prot=0;
|
|
if(!(attributes&0x01)) prot|=0x08; // Read
|
|
if(!(attributes&0x02)) prot|=0x04; // Write
|
|
if(!(attributes&0x04)) prot|=0x01; // Delete
|
|
if(!(attributes&0x08)) prot|=0x02; // Execute
|
|
if(attributes&0x10) prot|=0x10; // Archive
|
|
if(attributes&0x20) prot|=0x80; // Hold
|
|
if(attributes&0x40) prot|=0x40; // Script
|
|
if(attributes&0x80) prot|=0x20; // Pure
|
|
|
|
[dict setObject:[NSNumber numberWithInt:prot] forKey:XADAmigaProtectionBitsKey];
|
|
}
|
|
|
|
[solidfiles addObject:dict];
|
|
solidsize+=filesize;
|
|
|
|
if(compsize)
|
|
{
|
|
NSMutableDictionary *solidobj=[NSMutableDictionary dictionaryWithObjectsAndKeys:
|
|
[NSNumber numberWithUnsignedInt:compsize],XADDataLengthKey,
|
|
[NSNumber numberWithLongLong:dataoffs],XADDataOffsetKey,
|
|
[NSNumber numberWithLongLong:solidsize],@"TotalSize",
|
|
[NSNumber numberWithInt:method],@"Method",
|
|
nil];
|
|
|
|
NSEnumerator *enumerator=[solidfiles objectEnumerator];
|
|
NSMutableDictionary *dict;
|
|
while((dict=[enumerator nextObject]))
|
|
{
|
|
off_t compsize=0;
|
|
if(solidsize!=0) compsize=([[dict objectForKey:XADFileSizeKey] longLongValue]*(off_t)compsize)/solidsize;
|
|
[dict setObject:solidobj forKey:XADSolidObjectKey];
|
|
[dict setObject:[NSNumber numberWithLongLong:compsize] forKey:XADCompressedSizeKey];
|
|
[self addEntryWithDictionary:dict];
|
|
}
|
|
|
|
[solidfiles removeAllObjects];
|
|
solidsize=0;
|
|
}
|
|
|
|
[fh seekToFileOffset:dataoffs+compsize];
|
|
}
|
|
}
|
|
|
|
-(CSHandle *)handleForEntryWithDictionary:(NSDictionary *)dict wantChecksum:(BOOL)checksum
|
|
{
|
|
CSHandle *handle=[self subHandleFromSolidStreamForEntryWithDictionary:dict];
|
|
|
|
if(checksum) handle=[XADCRCHandle IEEECRC32HandleWithHandle:handle length:[handle fileSize]
|
|
correctCRC:[[dict objectForKey:@"LZXCRC32"] unsignedIntValue] conditioned:YES];
|
|
|
|
return handle;
|
|
}
|
|
|
|
-(CSHandle *)handleForSolidStreamWithObject:(id)obj wantChecksum:(BOOL)checksum
|
|
{
|
|
CSHandle *handle=[self handleAtDataOffsetForDictionary:obj];
|
|
off_t length=[[obj objectForKey:@"TotalSize"] longLongValue];
|
|
int method=[[obj objectForKey:@"Method"] intValue];
|
|
|
|
switch(method)
|
|
{
|
|
case 0: return handle;
|
|
case 2: return [[[XADLZXHandle alloc] initWithHandle:handle length:length] autorelease];
|
|
default: return nil;
|
|
}
|
|
}
|
|
|
|
-(NSString *)formatName { return @"LZX"; }
|
|
|
|
@end
|