From 8cf37cadf338deb75c8510f10b2e627e5115b56d Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Tue, 24 May 2022 01:07:55 -0700 Subject: [PATCH] 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 --- Plugins/AdPlug/AdPlug/AdPlugMetadataReader.mm | 4 +- .../ArchiveSource/ArchiveContainer.m | 2 +- .../ArchiveSource/ArchiveSource.m | 2 +- Plugins/FFMPEG/FFMPEGDecoder.m | 52 +++++++++---------- Plugins/GME/GameMetadataReader.m | 12 ++--- .../HighlyComplete/HCDecoder.mm | 16 +++--- Plugins/Hively/Hively/HVLMetadataReader.m | 2 +- Plugins/MIDI/MIDI/MIDIMetadataReader.mm | 6 +-- .../OpenMPT.old/OpenMPT/OMPTMetadataReader.mm | 10 ++-- Plugins/OpenMPT/OpenMPT/OMPTMetadataReader.mm | 10 ++-- Plugins/libvgmPlayer/libvgmMetadataReader.mm | 6 +-- Plugins/sidplay/SidMetadataReader.mm | 4 +- Plugins/vgmstream/vgmstream/VGMDecoder.m | 4 +- 13 files changed, 65 insertions(+), 65 deletions(-) diff --git a/Plugins/AdPlug/AdPlug/AdPlugMetadataReader.mm b/Plugins/AdPlug/AdPlug/AdPlugMetadataReader.mm index 8a04753a5..bb51ca5f4 100644 --- a/Plugins/AdPlug/AdPlug/AdPlugMetadataReader.mm +++ b/Plugins/AdPlug/AdPlug/AdPlugMetadataReader.mm @@ -60,9 +60,9 @@ NSString *artist = @""; 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()) - artist = [NSString stringWithUTF8String:p_player->getauthor().c_str()]; + artist = guess_encoding_of_string(p_player->getauthor().c_str()); delete p_player; delete p_emu; diff --git a/Plugins/ArchiveSource/ArchiveSource/ArchiveContainer.m b/Plugins/ArchiveSource/ArchiveSource/ArchiveContainer.m index 8e804aaa5..181becc5a 100644 --- a/Plugins/ArchiveSource/ArchiveSource/ArchiveContainer.m +++ b/Plugins/ArchiveSource/ArchiveSource/ArchiveContainer.m @@ -53,7 +53,7 @@ static NSString *g_make_unpack_path(NSString *archive, NSString *file, NSString NSMutableArray *files = [NSMutableArray array]; 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]]) [files addObject:[NSURL URLWithDataRepresentation:[g_make_unpack_path([url path], name, @"fex") dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil]]; fex_next(fex); diff --git a/Plugins/ArchiveSource/ArchiveSource/ArchiveSource.m b/Plugins/ArchiveSource/ArchiveSource/ArchiveSource.m index bf82fe694..5573300f9 100644 --- a/Plugins/ArchiveSource/ArchiveSource/ArchiveSource.m +++ b/Plugins/ArchiveSource/ArchiveSource/ArchiveSource.m @@ -92,7 +92,7 @@ static BOOL g_parse_unpack_path(NSString *src, NSString **archive, NSString **fi } while(!fex_done(fex)) { - if([file isEqualToString:[NSString stringWithUTF8String:fex_name(fex)]]) + if([file isEqualToString:guess_encoding_of_string(fex_name(fex))]) break; fex_next(fex); } diff --git a/Plugins/FFMPEG/FFMPEGDecoder.m b/Plugins/FFMPEG/FFMPEGDecoder.m index 7b8aaa132..d44d5cda1 100644 --- a/Plugins/FFMPEG/FFMPEGDecoder.m +++ b/Plugins/FFMPEG/FFMPEGDecoder.m @@ -523,7 +523,7 @@ static uint8_t reverse_bits[0x100]; if(formatCtx->metadata) { while((tag = av_dict_get(formatCtx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { if(!strcasecmp(tag->key, "streamtitle")) { - NSString *artistTitle = [NSString stringWithUTF8String:tag->value]; + NSString *artistTitle = guess_encoding_of_string(tag->value); NSArray *splitValues = [artistTitle componentsSeparatedByString:@" - "]; _artist = @""; _title = [splitValues objectAtIndex:0]; @@ -532,37 +532,37 @@ static uint8_t reverse_bits[0x100]; _title = [splitValues objectAtIndex:1]; } } 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")) { - _genre = [NSString stringWithUTF8String:tag->value]; + _genre = guess_encoding_of_string(tag->value); } 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")) { - _albumartist = [NSString stringWithUTF8String:tag->value]; + _albumartist = guess_encoding_of_string(tag->value); } else if(!strcasecmp(tag->key, "artist")) { - _artist = [NSString stringWithUTF8String:tag->value]; + _artist = guess_encoding_of_string(tag->value); } else if(!strcasecmp(tag->key, "title")) { - _title = [NSString stringWithUTF8String:tag->value]; + _title = guess_encoding_of_string(tag->value); } else if(!strcasecmp(tag->key, "date")) { - NSString *dateString = [NSString stringWithUTF8String:tag->value]; + NSString *dateString = guess_encoding_of_string(tag->value); _year = @([dateString intValue]); } else if(!strcasecmp(tag->key, "track")) { - NSString *trackString = [NSString stringWithUTF8String:tag->value]; + NSString *trackString = guess_encoding_of_string(tag->value); _track = @([trackString intValue]); } else if(!strcasecmp(tag->key, "disc")) { - NSString *discString = [NSString stringWithUTF8String:tag->value]; + NSString *discString = guess_encoding_of_string(tag->value); _disc = @([discString intValue]); } 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]; } 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]; } 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]; } 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]; } } @@ -886,18 +886,18 @@ static uint8_t reverse_bits[0x100]; } - (NSDictionary *)properties { - return @{@"channels": [NSNumber numberWithInt:channels], - @"channelConfig": [NSNumber numberWithUnsignedInt:channelConfig], - @"bitsPerSample": [NSNumber numberWithInt:bitsPerSample], - @"Unsigned": [NSNumber numberWithBool:(bitsPerSample == 8)], - @"sampleRate": [NSNumber numberWithFloat:frequency], - @"floatingPoint": [NSNumber numberWithBool:floatingPoint], - @"totalFrames": [NSNumber numberWithDouble:totalFrames], - @"bitrate": [NSNumber numberWithInt:bitrate], - @"seekable": [NSNumber numberWithBool:seekable], - @"codec": [NSString stringWithUTF8String:avcodec_get_name(codecCtx->codec_id)], - @"endian": @"host", - @"encoding": lossy ? @"lossy" : @"lossless"}; + return @{ @"channels": [NSNumber numberWithInt:channels], + @"channelConfig": [NSNumber numberWithUnsignedInt:channelConfig], + @"bitsPerSample": [NSNumber numberWithInt:bitsPerSample], + @"Unsigned": [NSNumber numberWithBool:(bitsPerSample == 8)], + @"sampleRate": [NSNumber numberWithFloat:frequency], + @"floatingPoint": [NSNumber numberWithBool:floatingPoint], + @"totalFrames": [NSNumber numberWithDouble:totalFrames], + @"bitrate": [NSNumber numberWithInt:bitrate], + @"seekable": [NSNumber numberWithBool:seekable], + @"codec": guess_encoding_of_string(avcodec_get_name(codecCtx->codec_id)), + @"endian": @"host", + @"encoding": lossy ? @"lossy" : @"lossless" }; } - (NSDictionary *)metadata { diff --git a/Plugins/GME/GameMetadataReader.m b/Plugins/GME/GameMetadataReader.m index 99bd1faa6..e005cc70c 100644 --- a/Plugins/GME/GameMetadataReader.m +++ b/Plugins/GME/GameMetadataReader.m @@ -95,18 +95,18 @@ gme_delete(emu); - NSString *title = [NSString stringWithUTF8String:info->song]; + NSString *title = guess_encoding_of_string(info->song); if(!title || ![title length]) { // this is needed to distinguish between different tracks in NSF, for example // otherwise they will all be displayed as 'blahblah.nsf' in playlist title = [[url lastPathComponent] stringByAppendingFormat:@" [%d]", track_num]; } - NSDictionary *dict = @{@"genre": [NSString stringWithUTF8String:info->system], - @"album": [NSString stringWithUTF8String:info->game], - @"title": title, - @"artist": [NSString stringWithUTF8String:info->author], - @"track": [NSNumber numberWithInt:track_num + 1]}; + NSDictionary *dict = @{ @"genre": guess_encoding_of_string(info->system), + @"album": guess_encoding_of_string(info->game), + @"title": title, + @"artist": guess_encoding_of_string(info->author), + @"track": [NSNumber numberWithInt:track_num + 1] }; gme_free_info(info); diff --git a/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm b/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm index 4ffa54aa8..b3d8e667c 100644 --- a/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm +++ b/Plugins/HighlyComplete/HighlyComplete/HCDecoder.mm @@ -223,9 +223,9 @@ static int parse_time_crap(NSString *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; - NSString *tag = [NSString stringWithUTF8String:name]; + NSString *tag = guess_encoding_of_string(name); NSString *taglc = [tag lowercaseString]; - NSString *svalue = [NSString stringWithUTF8String:value]; + NSString *svalue = guess_encoding_of_string(value); if(svalue == nil) return 0; @@ -307,8 +307,8 @@ typedef struct { static int psf1_info(void *context, const char *name, const char *value) { struct psf1_load_state *state = (struct psf1_load_state *)context; - NSString *sname = [[NSString stringWithUTF8String:name] lowercaseString]; - NSString *svalue = [NSString stringWithUTF8String:value]; + NSString *sname = [guess_encoding_of_string(name) lowercaseString]; + NSString *svalue = guess_encoding_of_string(value); if(!state->refresh && [sname isEqualToString:@"_refresh"]) { 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) { struct twosf_loader_state *state = (struct twosf_loader_state *)context; - NSString *sname = [[NSString stringWithUTF8String:name] lowercaseString]; - NSString *svalue = [NSString stringWithUTF8String:value]; + NSString *sname = [guess_encoding_of_string(name) lowercaseString]; + NSString *svalue = guess_encoding_of_string(value); if([sname isEqualToString:@"_frames"]) { 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) { struct usf_loader_state *uUsf = (struct usf_loader_state *)context; - NSString *sname = [[NSString stringWithUTF8String:name] lowercaseString]; - NSString *svalue = [NSString stringWithUTF8String:value]; + NSString *sname = [guess_encoding_of_string(name) lowercaseString]; + NSString *svalue = guess_encoding_of_string(value); if([sname isEqualToString:@"_enablecompare"] && [svalue length]) uUsf->enablecompare = 1; diff --git a/Plugins/Hively/Hively/HVLMetadataReader.m b/Plugins/Hively/Hively/HVLMetadataReader.m index 610504d1c..e69de4761 100644 --- a/Plugins/Hively/Hively/HVLMetadataReader.m +++ b/Plugins/Hively/Hively/HVLMetadataReader.m @@ -48,7 +48,7 @@ if(!tune) 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); diff --git a/Plugins/MIDI/MIDI/MIDIMetadataReader.mm b/Plugins/MIDI/MIDI/MIDIMetadataReader.mm index 5b4f7d53b..360bb8bc0 100644 --- a/Plugins/MIDI/MIDI/MIDIMetadataReader.mm +++ b/Plugins/MIDI/MIDI/MIDIMetadataReader.mm @@ -62,18 +62,18 @@ midi_meta_data_item 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]; for(size_t i = 0; i < metadata.get_count(); ++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(remap_display_name && [name isEqualToString:@"display_name"]) name = @"title"; 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]; } } diff --git a/Plugins/OpenMPT.old/OpenMPT/OMPTMetadataReader.mm b/Plugins/OpenMPT.old/OpenMPT/OMPTMetadataReader.mm index a593b79c8..b7ca4867b 100644 --- a/Plugins/OpenMPT.old/OpenMPT/OMPTMetadataReader.mm +++ b/Plugins/OpenMPT.old/OpenMPT/OMPTMetadataReader.mm @@ -65,15 +65,15 @@ for(std::vector::iterator key = keys.begin(); key != keys.end(); ++key) { 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") - artist = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; + artist = guess_encoding_of_string(mod->get_metadata(*key).c_str()); /*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") - 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") - type = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; + type = guess_encoding_of_string(mod->get_metadata(*key).c_str()); } delete mod; diff --git a/Plugins/OpenMPT/OpenMPT/OMPTMetadataReader.mm b/Plugins/OpenMPT/OpenMPT/OMPTMetadataReader.mm index 4f5d6193d..1d08583d3 100644 --- a/Plugins/OpenMPT/OpenMPT/OMPTMetadataReader.mm +++ b/Plugins/OpenMPT/OpenMPT/OMPTMetadataReader.mm @@ -65,15 +65,15 @@ for(std::vector::iterator key = keys.begin(); key != keys.end(); ++key) { 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") - artist = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; + artist = guess_encoding_of_string(mod->get_metadata(*key).c_str()); /*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") - 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") - type = [NSString stringWithUTF8String:mod->get_metadata(*key).c_str()]; + type = guess_encoding_of_string(mod->get_metadata(*key).c_str()); } delete mod; diff --git a/Plugins/libvgmPlayer/libvgmMetadataReader.mm b/Plugins/libvgmPlayer/libvgmMetadataReader.mm index 4dfbc183d..a30f7a6a1 100644 --- a/Plugins/libvgmPlayer/libvgmMetadataReader.mm +++ b/Plugins/libvgmPlayer/libvgmMetadataReader.mm @@ -139,11 +139,11 @@ static std::string FCC2Str(UINT32 fcc) { const char* const* tagList = player->GetTags(); for(const char* const* t = tagList; *t; t += 2) { if(!strcmp(t[0], "TITLE")) - title = [NSString stringWithUTF8String:t[1]]; + title = guess_encoding_of_string(t[1]); else if(!strcmp(t[0], "ARTIST")) - artist = [NSString stringWithUTF8String:t[1]]; + artist = guess_encoding_of_string(t[1]); else if(!strcmp(t[0], "GAME")) - album = [NSString stringWithUTF8String:t[1]]; + album = guess_encoding_of_string(t[1]); else if(!strcmp(t[0], "DATE")) { char* end; unsigned long theYear = strtoul(t[1], &end, 10); diff --git a/Plugins/sidplay/SidMetadataReader.mm b/Plugins/sidplay/SidMetadataReader.mm index 93d6fdd08..fefd14e6e 100644 --- a/Plugins/sidplay/SidMetadataReader.mm +++ b/Plugins/sidplay/SidMetadataReader.mm @@ -52,9 +52,9 @@ const SidTuneInfo *info = tune->getInfo(); 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 *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; diff --git a/Plugins/vgmstream/vgmstream/VGMDecoder.m b/Plugins/vgmstream/vgmstream/VGMDecoder.m index 41efa7fc8..bcd979e59 100644 --- a/Plugins/vgmstream/vgmstream/VGMDecoder.m +++ b/Plugins/vgmstream/vgmstream/VGMDecoder.m @@ -115,7 +115,7 @@ static NSString *get_description_tag(const char *description, const char *tag, c tags = vgmstream_tags_init(&tag_key, &tag_val); vgmstream_tags_reset(tags, [filename UTF8String]); 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 + strlen("REPLAYGAIN_"), "TRACK_", strlen("TRACK_"))) { 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(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 { title = [[urlTrimmed URLByDeletingPathExtension] lastPathComponent]; }