Created
March 28, 2009 08:06
-
-
Save iluvcapra/87059 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Riff.m | |
// riff-objc | |
// | |
// Created by Jamie Hardt on 3/27/09. | |
// Copyright 2009 The Sound Department. All rights reserved. | |
// | |
#import "Riff.h" | |
static const fourcc_t form_fourcc = {'F','O','R','M'}; | |
static const fourcc_t riff_fourcc = {'R','I','F','F'}; | |
static const fourcc_t list_fourcc = {'L','I','S','T'}; | |
@interface RiffChunk (private) | |
-(id)_initWithRiffFile:(RiffFile *)f atOffset:(UInt32)_offset; | |
@end | |
@interface RiffListChunk (private) | |
@end | |
@implementation RiffFile | |
-(RiffChunk *)_chunkAtOffset:(UInt32)_offset { | |
NSAssert(sizeof(UInt32) == FOURCC_MEMBER_COUNT, @"internal inconsistency/platform UInt32 type bad size"); | |
RiffChunk *retObj = nil; | |
const fourcc_t _holdingSig; | |
UInt32 readIn; | |
fseek(_fp, _offset, SEEK_SET); | |
readIn = fread(&_holdingSig, sizeof(UInt8), FOURCC_MEMBER_COUNT, _fp); | |
if (readIn != FOURCC_MEMBER_COUNT) { | |
NSLog(@"failed to read chunk fourcc in file %@ at offset %i", self, _offset); | |
return nil; | |
} | |
if (_littleEndian) { | |
if (!memcmp(_holdingSig, list_fourcc, FOURCC_MEMBER_COUNT) || | |
!memcmp(_holdingSig, riff_fourcc, FOURCC_MEMBER_COUNT) | |
) { | |
retObj = [[RiffListChunk alloc] _initWithRiffFile:self | |
atOffset:_offset]; | |
} else { | |
retObj = [[RiffChunk alloc] _initWithRiffFile:self | |
atOffset:_offset]; | |
} | |
} else { | |
if (!memcmp(_holdingSig, form_fourcc, FOURCC_MEMBER_COUNT) ) { | |
retObj = [[RiffListChunk alloc] _initWithRiffFile:self | |
atOffset:_offset]; | |
} else { | |
retObj = [[RiffChunk alloc] _initWithRiffFile:self | |
atOffset:_offset]; | |
} | |
} | |
return [retObj autorelease]; | |
} | |
-(id)initWithFileAtPath:(NSString *)path { | |
self = [super init]; | |
if (self != nil) { | |
const char *fsRepOfPath = [path fileSystemRepresentation]; | |
_fp = fopen(fsRepOfPath, "r"); | |
if (!_fp) { | |
NSLog(@"Unable to open file %@",path); | |
[self dealloc]; | |
return nil; | |
} | |
size_t readIn; | |
readIn = fread(&_signature, 1, 4, _fp); | |
NSAssert1(readIn == 4, @"error occured while opening file, %i bytes read", readIn); | |
if ( !memcmp(riff_fourcc, _signature, FOURCC_MEMBER_COUNT) ) { | |
_littleEndian = YES; | |
} else | |
if ( !memcmp(form_fourcc, _signature, FOURCC_MEMBER_COUNT) ) { | |
_littleEndian = NO; | |
} else { | |
// failed to identify file | |
[self dealloc]; | |
return nil; | |
} | |
} | |
return self; | |
} | |
-(FILE *)file { | |
return _fp; | |
} | |
-(void)signature:(fourcc_t *)fcc; { | |
memcpy(fcc, &_signature, FOURCC_MEMBER_COUNT); | |
return; | |
} | |
-(BOOL)littleEndian { | |
return _littleEndian; | |
} | |
-(RiffChunk *)rootChunk { | |
return [self _chunkAtOffset:0]; | |
} | |
-(void)dealloc { | |
if (_fp) | |
NSAssert( fclose(_fp) == 0 , @"failed to close file"); | |
[super dealloc]; | |
} | |
@end | |
@implementation RiffChunk | |
-(void)_readSignatureAtOffset:(UInt32)_offset { | |
UInt32 readIn; | |
fseek([_file file], _offset, SEEK_SET); | |
readIn = fread(&_sig, sizeof(UInt8), FOURCC_MEMBER_COUNT, [_file file]); | |
NSAssert2(readIn == FOURCC_MEMBER_COUNT,@"failed to read chunk fourcc in file %@ at offset %i", self, _offset); | |
} | |
-(void)_readSizeFromOffset:(UInt32)_offset { | |
UInt32 _holdingSize; | |
UInt32 readIn; | |
fseek([_file file], _offset, SEEK_SET); | |
readIn = fread(&_holdingSize, sizeof(UInt32), 1, [_file file]); | |
NSAssert2(readIn == 1,@"failed to read chunk fourcc in file %@, read %i bytes",self, readIn); | |
if ([_file littleEndian]) { | |
_length = EndianU32_LtoN(_holdingSize); | |
} else { | |
_length = EndianU32_BtoN(_holdingSize); | |
} | |
} | |
-(id)_initWithRiffFile:(RiffFile *)f | |
atOffset:(UInt32)_offset { | |
if (self = [super init]) { | |
_start = _offset; | |
_file = [f retain]; | |
[self _readSignatureAtOffset:_offset]; | |
[self _readSizeFromOffset:_offset + FOURCC_MEMBER_COUNT]; | |
} | |
return self; | |
} | |
-(void)signature:(fourcc_t *)fcc; { | |
memcpy(fcc, &_sig, FOURCC_MEMBER_COUNT); | |
return; | |
} | |
-(void) dealloc { | |
[_file release]; | |
[super dealloc]; | |
} | |
-(UInt32)length { | |
return _length; | |
} | |
-(RiffFile *)file { | |
return _file; | |
} | |
@end | |
@implementation RiffListChunk | |
-(id)_initWithRiffFile:(RiffFile *)f | |
atOffset:(UInt32)_offset { | |
if (self = [super init]) { | |
_start = _offset; | |
_file = [f retain]; | |
[self _readSignatureAtOffset:_offset + FOURCC_MEMBER_COUNT + sizeof(UInt32)]; | |
[self _readSizeFromOffset:_offset + FOURCC_MEMBER_COUNT]; | |
} | |
return self; | |
} | |
-(NSArray *)chunks { | |
UInt32 iterOffset = _start + FOURCC_MEMBER_COUNT + sizeof(UInt32) + FOURCC_MEMBER_COUNT; | |
NSMutableArray *retAry = [NSMutableArray array]; | |
while (iterOffset < _length) { | |
RiffChunk *aChunk = [_file _chunkAtOffset:iterOffset]; | |
[retAry addObject:aChunk]; | |
iterOffset += [aChunk length]+8; | |
if ([aChunk length] % 2) iterOffset++; | |
} | |
return [NSArray arrayWithArray:retAry]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment