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

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;
}