mirror of
https://github.com/MacPaw/XADMaster.git
synced 2025-08-29 03:23:48 +02:00
351 lines
7.3 KiB
Objective-C
351 lines
7.3 KiB
Objective-C
/*
|
|
* XADLibXADIOHandle.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 "XADLibXADIOHandle.h"
|
|
#import "XADException.h"
|
|
#import "Checksums.h"
|
|
#import "CRC.h"
|
|
|
|
static xadUINT8 xadIOPutFunc(struct xadInOut *io, xadUINT8 data);
|
|
static xadUINT8 xadIOGetFunc(struct xadInOut *io);
|
|
|
|
@implementation XADLibXADIOHandle
|
|
|
|
-(id)initWithHandle:(CSHandle *)handle
|
|
{
|
|
return [self initWithHandle:handle length:0];
|
|
}
|
|
|
|
-(id)initWithHandle:(CSHandle *)handle length:(off_t)outlength
|
|
{
|
|
if((self=[super initWithData:[NSMutableData dataWithCapacity:(long)outlength]]))
|
|
{
|
|
[self setParentHandle:handle];
|
|
inlen=[handle fileSize];
|
|
outlen=outlength;
|
|
unpacked=NO;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
|
|
|
|
|
|
-(off_t)fileSize
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
return [super fileSize];
|
|
}
|
|
|
|
-(off_t)offsetInFile
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
return [super offsetInFile];
|
|
}
|
|
|
|
-(BOOL)atEndOfFile
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
return [super atEndOfFile];
|
|
}
|
|
|
|
-(void)seekToFileOffset:(off_t)offs
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
[super seekToFileOffset:offs];
|
|
}
|
|
|
|
-(void)seekToEndOfFile
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
[super seekToEndOfFile];
|
|
}
|
|
|
|
-(int)readAtMost:(int)num toBuffer:(void *)buffer
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
return [super readAtMost:num toBuffer:buffer];
|
|
}
|
|
|
|
-(void)writeBytes:(int)num fromBuffer:(const void *)buffer
|
|
{
|
|
[self _raiseNotImplemented:_cmd];
|
|
}
|
|
|
|
-(NSData *)fileContents;
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
return [super fileContents];
|
|
}
|
|
|
|
-(NSData *)remainingFileContents;
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
return [super remainingFileContents];
|
|
}
|
|
|
|
-(NSData *)readDataOfLength:(int)length;
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
return [super readDataOfLength:length];
|
|
}
|
|
|
|
-(NSData *)readDataOfLengthAtMost:(int)length;
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
return [super readDataOfLengthAtMost:length];
|
|
}
|
|
|
|
-(NSData *)copyDataOfLength:(int)length;
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
return [super copyDataOfLength:length];
|
|
}
|
|
|
|
-(NSData *)copyDataOfLengthAtMost:(int)length;
|
|
{
|
|
if(!unpacked) [self runUnpacker];
|
|
return [super copyDataOfLengthAtMost:length];
|
|
}
|
|
|
|
|
|
|
|
|
|
-(void)runUnpacker
|
|
{
|
|
unpacked=YES;
|
|
xadUINT32 err=[self unpackData];
|
|
|
|
if(err) [XADException raiseExceptionWithXADError:err];
|
|
}
|
|
|
|
-(struct xadInOut *)ioStructWithFlags:(xadUINT32)flags
|
|
{
|
|
memset(&iostruct,0,sizeof(iostruct));
|
|
|
|
iostruct.xio_Flags=flags;
|
|
iostruct.xio_PutFunc=xadIOPutFunc;
|
|
iostruct.xio_GetFunc=xadIOGetFunc;
|
|
|
|
if(flags&XADIOF_ALLOCINBUFFER)
|
|
{
|
|
iostruct.xio_InBuffer=inbuf;
|
|
iostruct.xio_InBufferSize=iostruct.xio_InBufferPos=XIDBUFSIZE;
|
|
}
|
|
if(flags & XADIOF_ALLOCOUTBUFFER)
|
|
{
|
|
iostruct.xio_OutBuffer=outbuf;
|
|
iostruct.xio_OutBufferSize=XIDBUFSIZE;
|
|
}
|
|
|
|
iostruct.xio_InSize=inlen;
|
|
iostruct.xio_OutSize=outlen;
|
|
|
|
iostruct.inputhandle=parent;
|
|
iostruct.outputdata=(NSMutableData *)backingdata;
|
|
|
|
return &iostruct;
|
|
}
|
|
|
|
-(xadINT32)unpackData { return XADERR_NOTSUPPORTED; }
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
static xadUINT8 xadIOPutFunc(struct xadInOut *io, xadUINT8 data)
|
|
{
|
|
if(!io->xio_Error)
|
|
{
|
|
if(!io->xio_OutSize && !(io->xio_Flags & XADIOF_NOOUTENDERR))
|
|
{
|
|
io->xio_Error = XADERR_DECRUNCH;
|
|
io->xio_Flags |= XADIOF_ERROR;
|
|
}
|
|
else
|
|
{
|
|
if(io->xio_OutBufferPos >= io->xio_OutBufferSize)
|
|
xadIOWriteBuf(io);
|
|
io->xio_OutBuffer[io->xio_OutBufferPos++] = data;
|
|
if(!--io->xio_OutSize)
|
|
io->xio_Flags |= XADIOF_LASTOUTBYTE;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
static xadUINT8 xadIOGetFunc(struct xadInOut *io)
|
|
{
|
|
xadUINT8 res = 0;
|
|
|
|
if(!io->xio_Error)
|
|
{
|
|
if(!io->xio_InSize)
|
|
{
|
|
if(!(io->xio_Flags & XADIOF_NOINENDERR))
|
|
{
|
|
io->xio_Error = XADERR_DECRUNCH;
|
|
io->xio_Flags |= XADIOF_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(io->xio_InBufferPos >= io->xio_InBufferSize)
|
|
{
|
|
xadSize i;
|
|
|
|
if((i = io->xio_InBufferSize) > io->xio_InSize)
|
|
i = io->xio_InSize;
|
|
|
|
@try {
|
|
int actual=[io->inputhandle readAtMost:(int)i toBuffer:io->xio_InBuffer];
|
|
if(!actual)
|
|
{
|
|
io->xio_Flags|=XADIOF_ERROR;
|
|
io->xio_Error=XADERR_INPUT;
|
|
}
|
|
} @catch(id e) {
|
|
io->xio_Flags |= XADIOF_ERROR;
|
|
io->xio_Error=XADERR_DECRUNCH;
|
|
};
|
|
|
|
if(io->xio_InFunc)
|
|
(*(io->xio_InFunc))(io, (xadUINT32)i);
|
|
|
|
res = *io->xio_InBuffer;
|
|
io->xio_InBufferPos = 1;
|
|
}
|
|
else
|
|
res = io->xio_InBuffer[io->xio_InBufferPos++];
|
|
|
|
--io->xio_InSize;
|
|
}
|
|
if(!io->xio_InSize)
|
|
io->xio_Flags |= XADIOF_LASTINBYTE;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
xadUINT32 xadIOGetBitsLow(struct xadInOut *io, xadUINT8 bits)
|
|
{
|
|
xadUINT32 x;
|
|
|
|
while(io->xio_BitNum < bits)
|
|
{
|
|
io->xio_BitBuf |= xadIOGetChar(io) << io->xio_BitNum;
|
|
io->xio_BitNum += 8;
|
|
}
|
|
x = io->xio_BitBuf & ((1<<bits)-1);
|
|
io->xio_BitBuf >>= bits;
|
|
io->xio_BitNum -= bits;
|
|
return x;
|
|
}
|
|
|
|
xadUINT32 xadIOGetBitsLowR(struct xadInOut *io, xadUINT8 bits)
|
|
{
|
|
xadUINT32 x;
|
|
|
|
while(io->xio_BitNum < bits)
|
|
{
|
|
io->xio_BitBuf |= xadIOGetChar(io) << io->xio_BitNum;
|
|
io->xio_BitNum += 8;
|
|
}
|
|
x = 0;
|
|
io->xio_BitNum -= bits;
|
|
while(bits)
|
|
{
|
|
x = (x<<1) | (io->xio_BitBuf & 1);
|
|
io->xio_BitBuf >>= 1;
|
|
--bits;
|
|
}
|
|
return x;
|
|
}
|
|
|
|
xadUINT32 xadIOReadBitsLow(struct xadInOut *io, xadUINT8 bits)
|
|
{
|
|
while(io->xio_BitNum < bits)
|
|
{
|
|
io->xio_BitBuf |= xadIOGetChar(io) << io->xio_BitNum;
|
|
io->xio_BitNum += 8;
|
|
}
|
|
return io->xio_BitBuf & ((1<<bits)-1);
|
|
}
|
|
|
|
void xadIODropBitsLow(struct xadInOut *io, xadUINT8 bits)
|
|
{
|
|
io->xio_BitBuf >>= bits;
|
|
io->xio_BitNum -= bits;
|
|
}
|
|
|
|
xadUINT32 xadIOGetBitsHigh(struct xadInOut *io, xadUINT8 bits)
|
|
{
|
|
xadUINT32 x;
|
|
|
|
while(io->xio_BitNum < bits)
|
|
{
|
|
io->xio_BitBuf = (io->xio_BitBuf << 8) | xadIOGetChar(io);
|
|
io->xio_BitNum += 8;
|
|
}
|
|
x = (io->xio_BitBuf >> (io->xio_BitNum-bits)) & ((1<<bits)-1);
|
|
io->xio_BitNum -= bits;
|
|
return x;
|
|
}
|
|
|
|
xadUINT32 xadIOReadBitsHigh(struct xadInOut *io, xadUINT8 bits)
|
|
{
|
|
while(io->xio_BitNum < bits)
|
|
{
|
|
io->xio_BitBuf = (io->xio_BitBuf << 8) | xadIOGetChar(io);
|
|
io->xio_BitNum += 8;
|
|
}
|
|
return (io->xio_BitBuf >> (io->xio_BitNum-bits)) & ((1<<bits)-1);
|
|
}
|
|
|
|
void xadIODropBitsHigh(struct xadInOut *io, xadUINT8 bits)
|
|
{
|
|
io->xio_BitNum -= bits;
|
|
}
|
|
|
|
xadERROR xadIOWriteBuf(struct xadInOut *io)
|
|
{
|
|
if(!io->xio_Error && io->xio_OutBufferPos)
|
|
{
|
|
if(io->xio_OutFunc)
|
|
io->xio_OutFunc(io, (xadUINT32)io->xio_OutBufferPos);
|
|
if(!(io->xio_Flags & XADIOF_COMPLETEOUTFUNC))
|
|
{
|
|
[io->outputdata appendBytes:io->xio_OutBuffer length:(long)io->xio_OutBufferPos];
|
|
if(!(io->xio_Flags & XADIOF_NOCRC16))
|
|
{
|
|
// &io->xio_CRC16,
|
|
}
|
|
if(!(io->xio_Flags & XADIOF_NOCRC32))
|
|
{
|
|
io->xio_CRC32=XADCalculateCRC(io->xio_CRC32,io->xio_OutBuffer,(int)io->xio_OutBufferPos,XADCRCTable_edb88320);
|
|
// &io->xio_CRC32,
|
|
}
|
|
}
|
|
io->xio_OutBufferPos = 0;
|
|
}
|
|
return io->xio_Error;
|
|
}
|