Created
May 19, 2012 07:19
-
-
Save Ridwy/2729849 to your computer and use it in GitHub Desktop.
Parsing RIFF File
This file contains hidden or 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
/* | |
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