Skip to content

Instantly share code, notes, and snippets.

@Ridwy
Created May 19, 2012 07:19
Show Gist options
  • Save Ridwy/2729849 to your computer and use it in GitHub Desktop.
Save Ridwy/2729849 to your computer and use it in GitHub Desktop.
Parsing RIFF File
/*
NSDictionary* parseRIFF(NSString* path)
parse RIFF file
General output dictionary
{
formType = {
chunkId = ... ;
chunkId = ... ;
formType = {
chunkId = ... ;
chunkId = ... ;
chunkId = (..., );
};
};
}
e.g.) If you parse *.wav file, then output dictionary is like this.
{
WAVE = {
INFO = {
ICOP = ... ;
ICRD = ... ;
};
fmt = ... ;
fact = ... ;
data = ... ;
};
}
If the file can’t be opened or there is an parsing error, this function returns nil.
*/
NSDictionary* parseChunk(FILE* file)
{
// read chunk id
char chunkId[5] = {0};
size_t readNum = fread(chunkId, 1, 4, file);
if (readNum != 4) return nil;
NSString* identifier = [NSString stringWithCString:chunkId encoding:NSASCIIStringEncoding];
if (!identifier) return nil;
// read chunk size
UInt32 size = 0;
readNum = fread(&size, 4, 1, file);
if (readNum != 1) return nil;
if ([identifier isEqualToString:@"RIFF"] || [identifier isEqualToString:@"LIST"]) {
errno = 0;
long long max = ftell(file) + size;
if (errno != 0) return nil;
// read form type
char formType[5] = {0};
readNum = fread(formType, 1, 4, file);
if (readNum != 4) return nil;
NSString* type = [NSString stringWithCString:formType encoding:NSASCIIStringEncoding];
if (!type) return nil;
// parse subchunks recursively
NSMutableDictionary* subchunks = [NSMutableDictionary dictionary];
NSMutableArray* repeatedIds = [NSMutableArray array];
while (ftell(file) < max && errno == 0) {
@autoreleasepool {
NSDictionary* chunk = parseChunk(file);
if (chunk) {
NSString* subchunkId = [[chunk allKeys] lastObject];
if ([[subchunks allKeys] containsObject:subchunkId]) {
// create NSArray that contains informations of chunks that have same ID
if ([repeatedIds containsObject:subchunkId]) {
// n-th time
[(NSMutableArray*)[subchunks objectForKey:subchunkId] addObject:[chunk objectForKey:subchunkId]];
} else {
// 2nd time
[repeatedIds addObject:subchunkId];
id firstValue = [subchunks objectForKey:subchunkId];
id secondValue = [chunk objectForKey:subchunkId];
[subchunks setObject:[NSMutableArray arrayWithObjects:firstValue, secondValue, nil] forKey:subchunkId];
}
} else {
// 1st time
[subchunks addEntriesFromDictionary:chunk];
}
} else {
subchunks = nil;
break;
}
}//@autoreleasepool
}
if (subchunks && errno == 0) {
return [NSDictionary dictionaryWithObject:subchunks forKey:type];
} else {
return nil;
}
} else {
// read chunk data & do something here instead of fseek()
int result = fseek(file, size, SEEK_CUR);
if (result != 0) return nil;
if (size & 1) fseek(file, 1, SEEK_CUR); // skip padding
return [NSDictionary dictionaryWithObject:[NSNull null] forKey:identifier];
}
}
NSDictionary* parseRIFF(NSString* path)
{
errno = 0;
FILE* file = fopen([path fileSystemRepresentation], "rb");
if (errno != 0) return nil;
NSDictionary* riffInfo = parseChunk(file);
fclose(file);
return riffInfo;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment