Unicode metadata: Change most logic to use guesser

Most file formats the player supports may or may not have UTF-8 safe
strings in their metadata. This should not be assumed to be UTF-8, and
when it is assumed, it results in nil NSString objects, which results in
inline initializers crashing due to uncaught exceptions.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
swiftingly
Christopher Snowhill 2022-05-24 01:07:55 -07:00
parent f7dc6beda1
commit 8cf37cadf3
13 changed files with 65 additions and 65 deletions

View File

@ -60,9 +60,9 @@
NSString *artist = @""; NSString *artist = @"";
if(!p_player->gettitle().empty()) if(!p_player->gettitle().empty())
title = [NSString stringWithUTF8String:p_player->gettitle().c_str()]; title = guess_encoding_of_string(p_player->gettitle().c_str());
if(!p_player->getauthor().empty()) if(!p_player->getauthor().empty())
artist = [NSString stringWithUTF8String:p_player->getauthor().c_str()]; artist = guess_encoding_of_string(p_player->getauthor().c_str());
delete p_player; delete p_player;
delete p_emu; delete p_emu;

View File

@ -53,7 +53,7 @@ static NSString *g_make_unpack_path(NSString *archive, NSString *file, NSString
NSMutableArray *files = [NSMutableArray array]; NSMutableArray *files = [NSMutableArray array];
while(!fex_done(fex)) { while(!fex_done(fex)) {
NSString *name = [NSString stringWithUTF8String:fex_name(fex)]; NSString *name = guess_encoding_of_string(fex_name(fex));
if([[NSClassFromString(@"AudioPlayer") fileTypes] containsObject:[[name pathExtension] lowercaseString]]) if([[NSClassFromString(@"AudioPlayer") fileTypes] containsObject:[[name pathExtension] lowercaseString]])
[files addObject:[NSURL URLWithDataRepresentation:[g_make_unpack_path([url path], name, @"fex") dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil]]; [files addObject:[NSURL URLWithDataRepresentation:[g_make_unpack_path([url path], name, @"fex") dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil]];
fex_next(fex); fex_next(fex);

View File

@ -92,7 +92,7 @@ static BOOL g_parse_unpack_path(NSString *src, NSString **archive, NSString **fi
} }
while(!fex_done(fex)) { while(!fex_done(fex)) {
if([file isEqualToString:[NSString stringWithUTF8String:fex_name(fex)]]) if([file isEqualToString:guess_encoding_of_string(fex_name(fex))])
break; break;
fex_next(fex); fex_next(fex);
} }

View File

@ -523,7 +523,7 @@ static uint8_t reverse_bits[0x100];
if(formatCtx->metadata) { if(formatCtx->metadata) {
while((tag = av_dict_get(formatCtx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { while((tag = av_dict_get(formatCtx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
if(!strcasecmp(tag->key, "streamtitle")) { if(!strcasecmp(tag->key, "streamtitle")) {
NSString *artistTitle = [NSString stringWithUTF8String:tag->value]; NSString *artistTitle = guess_encoding_of_string(tag->value);
NSArray *splitValues = [artistTitle componentsSeparatedByString:@" - "]; NSArray *splitValues = [artistTitle componentsSeparatedByString:@" - "];
_artist = @""; _artist = @"";
_title = [splitValues objectAtIndex:0]; _title = [splitValues objectAtIndex:0];
@ -532,37 +532,37 @@ static uint8_t reverse_bits[0x100];
_title = [splitValues objectAtIndex:1]; _title = [splitValues objectAtIndex:1];
} }
} else if(!strcasecmp(tag->key, "icy-url")) { } else if(!strcasecmp(tag->key, "icy-url")) {
_album = [NSString stringWithUTF8String:tag->value]; _album = guess_encoding_of_string(tag->value);
} else if(!strcasecmp(tag->key, "icy-genre")) { } else if(!strcasecmp(tag->key, "icy-genre")) {
_genre = [NSString stringWithUTF8String:tag->value]; _genre = guess_encoding_of_string(tag->value);
} else if(!strcasecmp(tag->key, "album")) { } else if(!strcasecmp(tag->key, "album")) {
_album = [NSString stringWithUTF8String:tag->value]; _album = guess_encoding_of_string(tag->value);
} else if(!strcasecmp(tag->key, "album_artist")) { } else if(!strcasecmp(tag->key, "album_artist")) {
_albumartist = [NSString stringWithUTF8String:tag->value]; _albumartist = guess_encoding_of_string(tag->value);
} else if(!strcasecmp(tag->key, "artist")) { } else if(!strcasecmp(tag->key, "artist")) {
_artist = [NSString stringWithUTF8String:tag->value]; _artist = guess_encoding_of_string(tag->value);
} else if(!strcasecmp(tag->key, "title")) { } else if(!strcasecmp(tag->key, "title")) {
_title = [NSString stringWithUTF8String:tag->value]; _title = guess_encoding_of_string(tag->value);
} else if(!strcasecmp(tag->key, "date")) { } else if(!strcasecmp(tag->key, "date")) {
NSString *dateString = [NSString stringWithUTF8String:tag->value]; NSString *dateString = guess_encoding_of_string(tag->value);
_year = @([dateString intValue]); _year = @([dateString intValue]);
} else if(!strcasecmp(tag->key, "track")) { } else if(!strcasecmp(tag->key, "track")) {
NSString *trackString = [NSString stringWithUTF8String:tag->value]; NSString *trackString = guess_encoding_of_string(tag->value);
_track = @([trackString intValue]); _track = @([trackString intValue]);
} else if(!strcasecmp(tag->key, "disc")) { } else if(!strcasecmp(tag->key, "disc")) {
NSString *discString = [NSString stringWithUTF8String:tag->value]; NSString *discString = guess_encoding_of_string(tag->value);
_disc = @([discString intValue]); _disc = @([discString intValue]);
} else if(!strcasecmp(tag->key, "replaygain_album_gain")) { } else if(!strcasecmp(tag->key, "replaygain_album_gain")) {
NSString *rgValue = [NSString stringWithUTF8String:tag->value]; NSString *rgValue = guess_encoding_of_string(tag->value);
_replayGainAlbumGain = [rgValue floatValue]; _replayGainAlbumGain = [rgValue floatValue];
} else if(!strcasecmp(tag->key, "replaygain_album_peak")) { } else if(!strcasecmp(tag->key, "replaygain_album_peak")) {
NSString *rgValue = [NSString stringWithUTF8String:tag->value]; NSString *rgValue = guess_encoding_of_string(tag->value);
_replayGainAlbumPeak = [rgValue floatValue]; _replayGainAlbumPeak = [rgValue floatValue];
} else if(!strcasecmp(tag->key, "replaygain_track_gain")) { } else if(!strcasecmp(tag->key, "replaygain_track_gain")) {
NSString *rgValue = [NSString stringWithUTF8String:tag->value]; NSString *rgValue = guess_encoding_of_string(tag->value);
_replayGainTrackGain = [rgValue floatValue]; _replayGainTrackGain = [rgValue floatValue];
} else if(!strcasecmp(tag->key, "replaygain_track_peak")) { } else if(!strcasecmp(tag->key, "replaygain_track_peak")) {
NSString *rgValue = [NSString stringWithUTF8String:tag->value]; NSString *rgValue = guess_encoding_of_string(tag->value);
_replayGainTrackPeak = [rgValue floatValue]; _replayGainTrackPeak = [rgValue floatValue];
} }
} }
@ -886,18 +886,18 @@ static uint8_t reverse_bits[0x100];
} }
- (NSDictionary *)properties { - (NSDictionary *)properties {
return @{@"channels": [NSNumber numberWithInt:channels], return @{ @"channels": [NSNumber numberWithInt:channels],
@"channelConfig": [NSNumber numberWithUnsignedInt:channelConfig], @"channelConfig": [NSNumber numberWithUnsignedInt:channelConfig],
@"bitsPerSample": [NSNumber numberWithInt:bitsPerSample], @"bitsPerSample": [NSNumber numberWithInt:bitsPerSample],
@"Unsigned": [NSNumber numberWithBool:(bitsPerSample == 8)], @"Unsigned": [NSNumber numberWithBool:(bitsPerSample == 8)],
@"sampleRate": [NSNumber numberWithFloat:frequency], @"sampleRate": [NSNumber numberWithFloat:frequency],
@"floatingPoint": [NSNumber numberWithBool:floatingPoint], @"floatingPoint": [NSNumber numberWithBool:floatingPoint],
@"totalFrames": [NSNumber numberWithDouble:totalFrames], @"totalFrames": [NSNumber numberWithDouble:totalFrames],
@"bitrate": [NSNumber numberWithInt:bitrate], @"bitrate": [NSNumber numberWithInt:bitrate],
@"seekable": [NSNumber numberWithBool:seekable], @"seekable": [NSNumber numberWithBool:seekable],
@"codec": [NSString stringWithUTF8String:avcodec_get_name(codecCtx->codec_id)], @"codec": guess_encoding_of_string(avcodec_get_name(codecCtx->codec_id)),
@"endian": @"host", @"endian": @"host",
@"encoding": lossy ? @"lossy" : @"lossless"}; @"encoding": lossy ? @"lossy" : @"lossless" };
} }
- (NSDictionary *)metadata { - (NSDictionary *)metadata {

View File

@ -95,18 +95,18 @@
gme_delete(emu); gme_delete(emu);
NSString *title = [NSString stringWithUTF8String:info->song]; NSString *title = guess_encoding_of_string(info->song);
if(!title || ![title length]) { if(!title || ![title length]) {
// this is needed to distinguish between different tracks in NSF, for example // this is needed to distinguish between different tracks in NSF, for example
// otherwise they will all be displayed as 'blahblah.nsf' in playlist // otherwise they will all be displayed as 'blahblah.nsf' in playlist
title = [[url lastPathComponent] stringByAppendingFormat:@" [%d]", track_num]; title = [[url lastPathComponent] stringByAppendingFormat:@" [%d]", track_num];
} }
NSDictionary *dict = @{@"genre": [NSString stringWithUTF8String:info->system], NSDictionary *dict = @{ @"genre": guess_encoding_of_string(info->system),
@"album": [NSString stringWithUTF8String:info->game], @"album": guess_encoding_of_string(info->game),
@"title": title, @"title": title,
@"artist": [NSString stringWithUTF8String:info->author], @"artist": guess_encoding_of_string(info->author),
@"track": [NSNumber numberWithInt:track_num + 1]}; @"track": [NSNumber numberWithInt:track_num + 1] };
gme_free_info(info); gme_free_info(info);

View File

@ -223,9 +223,9 @@ static int parse_time_crap(NSString *value) {
static int psf_info_meta(void *context, const char *name, const char *value) { static int psf_info_meta(void *context, const char *name, const char *value) {
struct psf_info_meta_state *state = (struct psf_info_meta_state *)context; struct psf_info_meta_state *state = (struct psf_info_meta_state *)context;
NSString *tag = [NSString stringWithUTF8String:name]; NSString *tag = guess_encoding_of_string(name);
NSString *taglc = [tag lowercaseString]; NSString *taglc = [tag lowercaseString];
NSString *svalue = [NSString stringWithUTF8String:value]; NSString *svalue = guess_encoding_of_string(value);
if(svalue == nil) if(svalue == nil)
return 0; return 0;
@ -307,8 +307,8 @@ typedef struct {
static int psf1_info(void *context, const char *name, const char *value) { static int psf1_info(void *context, const char *name, const char *value) {
struct psf1_load_state *state = (struct psf1_load_state *)context; struct psf1_load_state *state = (struct psf1_load_state *)context;
NSString *sname = [[NSString stringWithUTF8String:name] lowercaseString]; NSString *sname = [guess_encoding_of_string(name) lowercaseString];
NSString *svalue = [NSString stringWithUTF8String:value]; NSString *svalue = guess_encoding_of_string(value);
if(!state->refresh && [sname isEqualToString:@"_refresh"]) { if(!state->refresh && [sname isEqualToString:@"_refresh"]) {
state->refresh = [svalue intValue]; state->refresh = [svalue intValue];
@ -808,8 +808,8 @@ static int twosf_loader(void *context, const uint8_t *exe, size_t exe_size,
static int twosf_info(void *context, const char *name, const char *value) { static int twosf_info(void *context, const char *name, const char *value) {
struct twosf_loader_state *state = (struct twosf_loader_state *)context; struct twosf_loader_state *state = (struct twosf_loader_state *)context;
NSString *sname = [[NSString stringWithUTF8String:name] lowercaseString]; NSString *sname = [guess_encoding_of_string(name) lowercaseString];
NSString *svalue = [NSString stringWithUTF8String:value]; NSString *svalue = guess_encoding_of_string(value);
if([sname isEqualToString:@"_frames"]) { if([sname isEqualToString:@"_frames"]) {
state->initial_frames = [svalue intValue]; state->initial_frames = [svalue intValue];
@ -844,8 +844,8 @@ static int usf_loader(void *context, const uint8_t *exe, size_t exe_size,
static int usf_info(void *context, const char *name, const char *value) { static int usf_info(void *context, const char *name, const char *value) {
struct usf_loader_state *uUsf = (struct usf_loader_state *)context; struct usf_loader_state *uUsf = (struct usf_loader_state *)context;
NSString *sname = [[NSString stringWithUTF8String:name] lowercaseString]; NSString *sname = [guess_encoding_of_string(name) lowercaseString];
NSString *svalue = [NSString stringWithUTF8String:value]; NSString *svalue = guess_encoding_of_string(value);
if([sname isEqualToString:@"_enablecompare"] && [svalue length]) if([sname isEqualToString:@"_enablecompare"] && [svalue length])
uUsf->enablecompare = 1; uUsf->enablecompare = 1;

View File

@ -48,7 +48,7 @@
if(!tune) if(!tune)
return nil; return nil;
NSString *title = [[NSString stringWithUTF8String:tune->ht_Name] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSString *title = [guess_encoding_of_string(tune->ht_Name) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
hvl_FreeTune(tune); hvl_FreeTune(tune);

View File

@ -62,18 +62,18 @@
midi_meta_data_item item; midi_meta_data_item item;
bool remap_display_name = !metadata.get_item("title", item); bool remap_display_name = !metadata.get_item("title", item);
NSArray *allowedKeys = @[@"title", @"artist", @"album", @"year"]; NSArray *allowedKeys = @[@"title", @"artist", @"albumartist", @"album", @"year", @"genre"];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:10]; NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:10];
for(size_t i = 0; i < metadata.get_count(); ++i) { for(size_t i = 0; i < metadata.get_count(); ++i) {
const midi_meta_data_item &item = metadata[i]; const midi_meta_data_item &item = metadata[i];
NSString *name = [[NSString stringWithUTF8String:item.m_name.c_str()] lowercaseString]; NSString *name = [guess_encoding_of_string(item.m_name.c_str()) lowercaseString];
if(![name isEqualToString:@"type"]) { if(![name isEqualToString:@"type"]) {
if(remap_display_name && [name isEqualToString:@"display_name"]) if(remap_display_name && [name isEqualToString:@"display_name"])
name = @"title"; name = @"title";
if([allowedKeys containsObject:name]) if([allowedKeys containsObject:name])
[dict setObject:[NSString stringWithUTF8String:item.m_value.c_str()] forKey:name]; [dict setObject:guess_encoding_of_string(item.m_value.c_str()) forKey:name];
} }
} }

View File

@ -65,15 +65,15 @@
for(std::vector<std::string>::iterator key = keys.begin(); key != keys.end(); ++key) { for(std::vector<std::string>::iterator key = keys.begin(); key != keys.end(); ++key) {
if(*key == "title") if(*key == "title")
title = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; title = guess_encoding_of_string(mod->get_metadata(*key).c_str());
else if(*key == "artist") else if(*key == "artist")
artist = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; artist = guess_encoding_of_string(mod->get_metadata(*key).c_str());
/*else if ( *key == "message" ) /*else if ( *key == "message" )
comment = [NSString stringWithUTF8String: mod->get_metadata( *key ).c_str()];*/ comment = guess_encoding_of_string(mod->get_metadata( *key ).c_str());*/
else if(*key == "date") else if(*key == "date")
date = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; date = guess_encoding_of_string(mod->get_metadata(*key).c_str());
else if(*key == "type_long") else if(*key == "type_long")
type = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; type = guess_encoding_of_string(mod->get_metadata(*key).c_str());
} }
delete mod; delete mod;

View File

@ -65,15 +65,15 @@
for(std::vector<std::string>::iterator key = keys.begin(); key != keys.end(); ++key) { for(std::vector<std::string>::iterator key = keys.begin(); key != keys.end(); ++key) {
if(*key == "title") if(*key == "title")
title = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; title = guess_encoding_of_string(mod->get_metadata(*key).c_str());
else if(*key == "artist") else if(*key == "artist")
artist = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; artist = guess_encoding_of_string(mod->get_metadata(*key).c_str());
/*else if ( *key == "message" ) /*else if ( *key == "message" )
comment = [NSString stringWithUTF8String: mod->get_metadata( *key ).c_str()];*/ comment = guess_encoding_of_string(mod->get_metadata( *key ).c_str());*/
else if(*key == "date") else if(*key == "date")
date = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; date = guess_encoding_of_string(mod->get_metadata(*key).c_str());
else if(*key == "type_long") else if(*key == "type_long")
type = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; type = guess_encoding_of_string(mod->get_metadata(*key).c_str());
} }
delete mod; delete mod;

View File

@ -139,11 +139,11 @@ static std::string FCC2Str(UINT32 fcc) {
const char* const* tagList = player->GetTags(); const char* const* tagList = player->GetTags();
for(const char* const* t = tagList; *t; t += 2) { for(const char* const* t = tagList; *t; t += 2) {
if(!strcmp(t[0], "TITLE")) if(!strcmp(t[0], "TITLE"))
title = [NSString stringWithUTF8String:t[1]]; title = guess_encoding_of_string(t[1]);
else if(!strcmp(t[0], "ARTIST")) else if(!strcmp(t[0], "ARTIST"))
artist = [NSString stringWithUTF8String:t[1]]; artist = guess_encoding_of_string(t[1]);
else if(!strcmp(t[0], "GAME")) else if(!strcmp(t[0], "GAME"))
album = [NSString stringWithUTF8String:t[1]]; album = guess_encoding_of_string(t[1]);
else if(!strcmp(t[0], "DATE")) { else if(!strcmp(t[0], "DATE")) {
char* end; char* end;
unsigned long theYear = strtoul(t[1], &end, 10); unsigned long theYear = strtoul(t[1], &end, 10);

View File

@ -52,9 +52,9 @@
const SidTuneInfo *info = tune->getInfo(); const SidTuneInfo *info = tune->getInfo();
unsigned int count = info->numberOfInfoStrings(); unsigned int count = info->numberOfInfoStrings();
NSString *title = count >= 1 ? [[NSString stringWithUTF8String:info->infoString(0)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] : @""; NSString *title = count >= 1 ? [guess_encoding_of_string(info->infoString(0)) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] : @"";
NSString *titletag = info->songs() > 1 ? @"album" : @"title"; NSString *titletag = info->songs() > 1 ? @"album" : @"title";
NSString *artist = count >= 2 ? [[NSString stringWithUTF8String:info->infoString(1)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] : @""; NSString *artist = count >= 2 ? [guess_encoding_of_string(info->infoString(1)) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] : @"";
delete tune; delete tune;

View File

@ -115,7 +115,7 @@ static NSString *get_description_tag(const char *description, const char *tag, c
tags = vgmstream_tags_init(&tag_key, &tag_val); tags = vgmstream_tags_init(&tag_key, &tag_val);
vgmstream_tags_reset(tags, [filename UTF8String]); vgmstream_tags_reset(tags, [filename UTF8String]);
while(vgmstream_tags_next_tag(tags, tagFile)) { while(vgmstream_tags_next_tag(tags, tagFile)) {
NSString *value = [NSString stringWithUTF8String:tag_val]; NSString *value = guess_encoding_of_string(tag_val);
if(!strncasecmp(tag_key, "REPLAYGAIN_", strlen("REPLAYGAIN_"))) { if(!strncasecmp(tag_key, "REPLAYGAIN_", strlen("REPLAYGAIN_"))) {
if(!strncasecmp(tag_key + strlen("REPLAYGAIN_"), "TRACK_", strlen("TRACK_"))) { if(!strncasecmp(tag_key + strlen("REPLAYGAIN_"), "TRACK_", strlen("TRACK_"))) {
if(!strcasecmp(tag_key + strlen("REPLAYGAIN_TRACK_"), "GAIN")) { if(!strcasecmp(tag_key + strlen("REPLAYGAIN_TRACK_"), "GAIN")) {
@ -167,7 +167,7 @@ static NSString *get_description_tag(const char *description, const char *tag, c
if([title isEqualToString:@""]) { if([title isEqualToString:@""]) {
if(stream->num_streams > 1) { if(stream->num_streams > 1) {
title = [NSString stringWithFormat:@"%@ - %s", [[urlTrimmed URLByDeletingPathExtension] lastPathComponent], stream->stream_name]; title = [NSString stringWithFormat:@"%@ - %@", [[urlTrimmed URLByDeletingPathExtension] lastPathComponent], guess_encoding_of_string(stream->stream_name)];
} else { } else {
title = [[urlTrimmed URLByDeletingPathExtension] lastPathComponent]; title = [[urlTrimmed URLByDeletingPathExtension] lastPathComponent];
} }