Skip to content

Instantly share code, notes, and snippets.

@iluvcapra
Created March 28, 2009 08:06
Show Gist options
  • Save iluvcapra/87059 to your computer and use it in GitHub Desktop.
Save iluvcapra/87059 to your computer and use it in GitHub Desktop.
//
// 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