From 49cddface7698e5d9a046841c2527fab97df5c09 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Fri, 20 Jun 2025 19:42:43 -0700 Subject: [PATCH] Metadata: Add helper for optional values Add NSDictionary initWithOptionalObjects:forKeys:count: helper, to work around several places that may have been setting nil dictionary valies on placeholder dictionaries. Hopefully this fixes the crash someone logged recently. Signed-off-by: Christopher Snowhill --- Audio/CogAudio.xcodeproj/project.pbxproj | 8 ++++ Cog.xcodeproj/project.pbxproj | 6 +++ .../CueSheet.xcodeproj/project.pbxproj | 2 + Plugins/CueSheet/CueSheetMetadataReader.m | 40 ++++++++++++------- Plugins/HTTPSource/HTTPSource.m | 16 +++++++- .../HTTPSource.xcodeproj/project.pbxproj | 2 + Plugins/libvgmPlayer/libvgmMetadataReader.mm | 24 +++++++---- .../libvgmPlayer.xcodeproj/project.pbxproj | 2 + Plugins/minimp3/MP3Decoder.m | 16 +++++++- .../minimp3/minimp3.xcodeproj/project.pbxproj | 2 + Utils/NSDictionary+Optional.h | 7 ++++ Utils/NSDictionary+Optional.m | 15 +++++++ 12 files changed, 117 insertions(+), 23 deletions(-) create mode 100644 Utils/NSDictionary+Optional.h create mode 100644 Utils/NSDictionary+Optional.m diff --git a/Audio/CogAudio.xcodeproj/project.pbxproj b/Audio/CogAudio.xcodeproj/project.pbxproj index eb5454824..521dacf22 100644 --- a/Audio/CogAudio.xcodeproj/project.pbxproj +++ b/Audio/CogAudio.xcodeproj/project.pbxproj @@ -101,6 +101,8 @@ 83A349752D5C50A10096D530 /* DSPHRTFNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A349742D5C50A10096D530 /* DSPHRTFNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 83A349772D5C50B20096D530 /* DSPHRTFNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A349762D5C50B20096D530 /* DSPHRTFNode.m */; }; 83B74281289E027F005AAC28 /* CogAudio-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B74280289E027F005AAC28 /* CogAudio-Bridging-Header.h */; }; + 83CB56652E06464D003DD379 /* NSDictionary+Optional.h in Headers */ = {isa = PBXBuildFile; fileRef = 83CB56632E06464D003DD379 /* NSDictionary+Optional.h */; }; + 83CB56662E06464D003DD379 /* NSDictionary+Optional.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CB56642E06464D003DD379 /* NSDictionary+Optional.m */; }; 83F843202D5C6272008C123B /* HeadphoneFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F8431E2D5C6272008C123B /* HeadphoneFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 83F843212D5C6272008C123B /* HeadphoneFilter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 83F8431F2D5C6272008C123B /* HeadphoneFilter.mm */; }; 83F843232D5C66DA008C123B /* DSPEqualizerNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F843222D5C66DA008C123B /* DSPEqualizerNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -231,6 +233,8 @@ 83A349742D5C50A10096D530 /* DSPHRTFNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DSPHRTFNode.h; sourceTree = ""; }; 83A349762D5C50B20096D530 /* DSPHRTFNode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DSPHRTFNode.m; sourceTree = ""; }; 83B74280289E027F005AAC28 /* CogAudio-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CogAudio-Bridging-Header.h"; sourceTree = ""; }; + 83CB56632E06464D003DD379 /* NSDictionary+Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Optional.h"; path = "../Utils/NSDictionary+Optional.h"; sourceTree = SOURCE_ROOT; }; + 83CB56642E06464D003DD379 /* NSDictionary+Optional.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+Optional.m"; path = "../Utils/NSDictionary+Optional.m"; sourceTree = SOURCE_ROOT; }; 83F8431E2D5C6272008C123B /* HeadphoneFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HeadphoneFilter.h; sourceTree = ""; }; 83F8431F2D5C6272008C123B /* HeadphoneFilter.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = HeadphoneFilter.mm; sourceTree = ""; }; 83F843222D5C66DA008C123B /* DSPEqualizerNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DSPEqualizerNode.h; sourceTree = ""; }; @@ -427,6 +431,8 @@ 17D21CDC0B8BE5B400D1EBDE /* Utils */ = { isa = PBXGroup; children = ( + 83CB56632E06464D003DD379 /* NSDictionary+Optional.h */, + 83CB56642E06464D003DD379 /* NSDictionary+Optional.m */, 839065F22853338700636FBB /* dsd2float.h */, 8328995527CB51B700D7F028 /* SHA256Digest.h */, 8328995627CB51B700D7F028 /* SHA256Digest.m */, @@ -611,6 +617,7 @@ 83A3496D2D5C40490096D530 /* DSPFSurroundNode.h in Headers */, 83A3496B2D5C3F430096D530 /* DSPRubberbandNode.h in Headers */, 17D21CA50B8BE4BA00D1EBDE /* InputNode.h in Headers */, + 83CB56652E06464D003DD379 /* NSDictionary+Optional.h in Headers */, 833738EA2D5EA52500278628 /* DSPDownmixNode.h in Headers */, 83F843232D5C66DA008C123B /* DSPEqualizerNode.h in Headers */, 834A41A9287A90AB00EB9D9B /* freesurround_decoder.h in Headers */, @@ -765,6 +772,7 @@ 8EC122600B993BD500C5B3AD /* ConverterNode.m in Sources */, 835DD2672ACAF1D90057E319 /* OutputCoreAudio.m in Sources */, 83A349722D5C41810096D530 /* FSurroundFilter.mm in Sources */, + 83CB56662E06464D003DD379 /* NSDictionary+Optional.m in Sources */, 8E8D3D300CBAEE6E00135C1B /* AudioContainer.m in Sources */, B0575F300D687A4000411D77 /* Helper.m in Sources */, 835DD2742ACAF5AD0057E319 /* lpc.c in Sources */, diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index 26652c254..3d9805124 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -180,6 +180,7 @@ 83BC5AC320E4CE8D00631CD4 /* SpotlightPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = 178456C00F6320B5007E8021 /* SpotlightPanel.xib */; }; 83BC5AC420E4CE9000631CD4 /* Feedback.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17D1B1DA0F6330D400694C57 /* Feedback.xib */; }; 83BCB8DE17FC971300760340 /* FFMPEG.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = B09E94350D747F7B0064F138 /* FFMPEG.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 83CB565E2E064607003DD379 /* NSDictionary+Optional.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CB565D2E064607003DD379 /* NSDictionary+Optional.m */; }; 83D0380F24A40DFB004CF90F /* CogAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83D0380E24A40DF2004CF90F /* CogAssets.xcassets */; }; 83F9D8071A884C54007ABEC2 /* SilenceDecoder.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83F9D7F61A884B46007ABEC2 /* SilenceDecoder.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 83F9FFEF2D6EB75B00026576 /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 83F9FFEE2D6EB75B00026576 /* Sentry */; }; @@ -1041,6 +1042,8 @@ 83BC5AD820E4D0D900631CD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/SpotlightPanel.strings; sourceTree = ""; }; 83BC5ADA20E4D0E900631CD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Feedback.strings; sourceTree = ""; }; 83BC5ADC20E4D0EC00631CD4 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Feedback.strings; sourceTree = ""; }; + 83CB565C2E064607003DD379 /* NSDictionary+Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Optional.h"; sourceTree = ""; }; + 83CB565D2E064607003DD379 /* NSDictionary+Optional.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Optional.m"; sourceTree = ""; }; 83D0380E24A40DF2004CF90F /* CogAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = CogAssets.xcassets; sourceTree = ""; }; 83D3C5FC201C674D005564CB /* AdPlug.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AdPlug.xcodeproj; path = Plugins/AdPlug/AdPlug.xcodeproj; sourceTree = ""; }; 83E5EFAC1FFEF78100659F0F /* OpenMPT.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OpenMPT.xcodeproj; path = Plugins/OpenMPT/OpenMPT.xcodeproj; sourceTree = ""; }; @@ -1214,6 +1217,8 @@ 177EC0110B8BC2CF0000BC8C /* Utils */ = { isa = PBXGroup; children = ( + 83CB565C2E064607003DD379 /* NSDictionary+Optional.h */, + 83CB565D2E064607003DD379 /* NSDictionary+Optional.m */, 834A42C4287B01B600EB9D9B /* AudioChunk.h */, 8384912518080F2D00E7332D /* Logging.h */, 07E18DF10D62B38400BB0E11 /* NSArray+ShuffleUtils.h */, @@ -2581,6 +2586,7 @@ 839E876E2D5DA0AC00A13526 /* RubberbandEngineTransformer.m in Sources */, 838A33842D06CF4100D0D770 /* SpectrumWindowController.m in Sources */, 83B61E2829A82A0200CD0580 /* LyricsWindowController.m in Sources */, + 83CB565E2E064607003DD379 /* NSDictionary+Optional.m in Sources */, 56462EB20D634206000AB68C /* SpotlightPlaylistController.m in Sources */, 07E18DF30D62B38400BB0E11 /* NSArray+ShuffleUtils.m in Sources */, 56C63D910D647DF300EAE25A /* NSComparisonPredicate+CogPredicate.m in Sources */, diff --git a/Plugins/CueSheet/CueSheet.xcodeproj/project.pbxproj b/Plugins/CueSheet/CueSheet.xcodeproj/project.pbxproj index fecb6c61a..594a05e5c 100644 --- a/Plugins/CueSheet/CueSheet.xcodeproj/project.pbxproj +++ b/Plugins/CueSheet/CueSheet.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 838EE8BB29A8600900CD0580 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = ""; }; 839DA7D0274A2EA9001B18E5 /* AudioMetadataReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioMetadataReader.h; path = ../../Audio/AudioMetadataReader.h; sourceTree = ""; }; 839DA7D3274A2FD4001B18E5 /* NSDictionary+Merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Merge.h"; path = "../../Utils/NSDictionary+Merge.h"; sourceTree = ""; }; + 83CB56672E0649B4003DD379 /* NSDictionary+Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Optional.h"; path = "../../Utils/NSDictionary+Optional.h"; sourceTree = ""; }; 83D833AB2DF95A89009970AF /* CogAudio.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CogAudio.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 83F0E6B5287CAB4100D84594 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = ""; }; 8D5B49B6048680CD000E48DA /* CueSheet.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CueSheet.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -99,6 +100,7 @@ 832EE93A288F888600B03467 /* SandboxBroker.h */, 834A42B2287AF59900EB9D9B /* AudioChunk.h */, 839DA7D3274A2FD4001B18E5 /* NSDictionary+Merge.h */, + 83CB56672E0649B4003DD379 /* NSDictionary+Optional.h */, 839DA7D0274A2EA9001B18E5 /* AudioMetadataReader.h */, 8384912A180814D900E7332D /* Logging.h */, 8E8D423C0CBB0FF600135C1B /* Plugin.h */, diff --git a/Plugins/CueSheet/CueSheetMetadataReader.m b/Plugins/CueSheet/CueSheetMetadataReader.m index c42fae680..b52569ff1 100644 --- a/Plugins/CueSheet/CueSheetMetadataReader.m +++ b/Plugins/CueSheet/CueSheetMetadataReader.m @@ -13,6 +13,7 @@ #import "AudioMetadataReader.h" #import "NSDictionary+Merge.h" +#import "NSDictionary+Optional.h" @implementation CueSheetMetadataReader @@ -100,20 +101,31 @@ } + (NSDictionary *)processDataForTrack:(CueSheetTrack *)track { - NSMutableDictionary *cuesheetMetadata = [[NSMutableDictionary alloc] init]; - - if([track artist]) [cuesheetMetadata setValue:[track artist] forKey:@"artist"]; - if([track album]) [cuesheetMetadata setValue:[track album] forKey:@"album"]; - if([track title]) [cuesheetMetadata setValue:[track title] forKey:@"title"]; - if([[track track] intValue]) [cuesheetMetadata setValue:@([[track track] intValue]) forKey:@"track"]; - if([track genre]) [cuesheetMetadata setValue:[track genre] forKey:@"genre"]; - if([[track year] intValue]) [cuesheetMetadata setValue:@([[track year] intValue]) forKey:@"year"]; - if([track albumGain]) [cuesheetMetadata setValue:@([track albumGain]) forKey:@"replaygain_album_gain"]; - if([track albumPeak]) [cuesheetMetadata setValue:@([track albumPeak]) forKey:@"replaygain_album_peak"]; - if([track trackGain]) [cuesheetMetadata setValue:@([track trackGain]) forKey:@"replaygain_track_gain"]; - if([track trackPeak]) [cuesheetMetadata setValue:@([track trackPeak]) forKey:@"replaygain_track_peak"]; - - return [NSDictionary dictionaryWithDictionary:cuesheetMetadata]; + const NSString* keys[] = { + @"artist", + @"album", + @"title", + @"track", + @"genre", + @"year", + @"replaygain_album_gain", + @"replaygain_album_peak", + @"replaygain_track_gain", + @"replaygain_track_peak" + }; + const id values[] = { + [track artist], + [track album], + [track title], + @([[track track] intValue]), + [track genre], + @([[track year] intValue]), + @([track albumGain]), + @([track albumPeak]), + @([track trackGain]), + @([track trackPeak]) + }; + return [NSDictionary initWithOptionalObjects:values forKeys:keys count:sizeof(keys) / sizeof(keys[0])]; } @end diff --git a/Plugins/HTTPSource/HTTPSource.m b/Plugins/HTTPSource/HTTPSource.m index da1408236..634556ffe 100644 --- a/Plugins/HTTPSource/HTTPSource.m +++ b/Plugins/HTTPSource/HTTPSource.m @@ -11,6 +11,8 @@ #import "Logging.h" +#import "NSDictionary+Optional.h" + #import #import @@ -628,7 +630,19 @@ static void http_stream_reset(HTTPSource *fp) { } - (NSDictionary *)metadata { - return @{ @"genre": genre, @"album": album, @"artist": artist, @"title": title }; + const NSString* keys[] = { + @"genre", + @"album", + @"artist", + @"title" + }; + const id values[] = { + genre, + album, + artist, + title + }; + return [NSDictionary initWithOptionalObjects:values forKeys:keys count:sizeof(keys) / sizeof(keys[0])]; } - (BOOL)seekable { diff --git a/Plugins/HTTPSource/HTTPSource.xcodeproj/project.pbxproj b/Plugins/HTTPSource/HTTPSource.xcodeproj/project.pbxproj index 7c46bdf2c..a9c953f51 100644 --- a/Plugins/HTTPSource/HTTPSource.xcodeproj/project.pbxproj +++ b/Plugins/HTTPSource/HTTPSource.xcodeproj/project.pbxproj @@ -38,6 +38,7 @@ 8356BD1727B3B7340074E50C /* libcurl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurl.tbd; path = usr/lib/libcurl.tbd; sourceTree = SDKROOT; }; 83747C362862DC0D0021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 8384912F1808180000E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; + 83CB56682E064E50003DD379 /* NSDictionary+Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Optional.h"; path = "../../Utils/NSDictionary+Optional.h"; sourceTree = ""; }; 8D5B49B6048680CD000E48DA /* HTTPSource.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HTTPSource.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; @@ -91,6 +92,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 83CB56682E064E50003DD379 /* NSDictionary+Optional.h */, 834A42B9287AFAB500EB9D9B /* AudioChunk.h */, 8384912F1808180000E7332D /* Logging.h */, 17ADB6340B97A8B400257CA2 /* Plugin.h */, diff --git a/Plugins/libvgmPlayer/libvgmMetadataReader.mm b/Plugins/libvgmPlayer/libvgmMetadataReader.mm index d7baf95c8..3e64d08c6 100644 --- a/Plugins/libvgmPlayer/libvgmMetadataReader.mm +++ b/Plugins/libvgmPlayer/libvgmMetadataReader.mm @@ -12,6 +12,8 @@ #import "Logging.h" +#import "NSDictionary+Optional.h" + #import #import #import @@ -160,13 +162,21 @@ static std::string FCC2Str(UINT32 fcc) { DataLoader_Deinit(dLoad); free(fileData); - NSDictionary* dict = @{ @"codec": system, - @"album": album, - @"title": title, - @"artist": artist, - @"year": year }; - - return dict; + const NSString* keys[] = { + @"codec", + @"album", + @"title", + @"artist", + @"year" + }; + const id values[] = { + system, + album, + title, + artist, + year + }; + return [NSDictionary initWithOptionalObjects:values forKeys:keys count:sizeof(keys) / sizeof(keys[0])]; } @end diff --git a/Plugins/libvgmPlayer/libvgmPlayer.xcodeproj/project.pbxproj b/Plugins/libvgmPlayer/libvgmPlayer.xcodeproj/project.pbxproj index 44091eeb7..54a4b1f5a 100644 --- a/Plugins/libvgmPlayer/libvgmPlayer.xcodeproj/project.pbxproj +++ b/Plugins/libvgmPlayer/libvgmPlayer.xcodeproj/project.pbxproj @@ -47,6 +47,7 @@ 83747C312862DBE80021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 8384912E1808175400E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; 838EE8C829A8600B00CD0580 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = ""; }; + 83CB56692E064F48003DD379 /* NSDictionary+Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Optional.h"; path = "../../Utils/NSDictionary+Optional.h"; sourceTree = ""; }; 83F0E6C2287CAB4300D84594 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = ""; }; 83FAF8A518ADD4D100057CAF /* PlaylistController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlaylistController.h; path = ../../Playlist/PlaylistController.h; sourceTree = ""; }; 8D5B49B6048680CD000E48DA /* libvgmPlayer.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = libvgmPlayer.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -108,6 +109,7 @@ 08FB77AFFE84173DC02AAC07 /* Classes */ = { isa = PBXGroup; children = ( + 83CB56692E064F48003DD379 /* NSDictionary+Optional.h */, 834A42AC287AF18E00EB9D9B /* AudioChunk.h */, 17C8F33B0CBED3BE008D969D /* libvgmContainer.h */, 17C8F33C0CBED3BE008D969D /* libvgmContainer.mm */, diff --git a/Plugins/minimp3/MP3Decoder.m b/Plugins/minimp3/MP3Decoder.m index 46f23ebbf..4c186a1cc 100644 --- a/Plugins/minimp3/MP3Decoder.m +++ b/Plugins/minimp3/MP3Decoder.m @@ -14,6 +14,8 @@ #import "Logging.h" +#import "NSDictionary+Optional.h" + #import "id3tag.h" #import "CVbriHeader.h" @@ -376,7 +378,19 @@ static int mp3_seek_callback(uint64_t position, void *user_data) { } - (NSDictionary *)metadata { - return @{ @"artist": artist, @"album": album, @"title": title, @"genre": genre }; + const NSString* keys[] = { + @"artist", + @"album", + @"title", + @"genre" + }; + const id values[] = { + artist, + album, + title, + genre + }; + return [NSDictionary initWithOptionalObjects:values forKeys:keys count:sizeof(keys) / sizeof(keys[0])]; } + (NSArray *)fileTypes { diff --git a/Plugins/minimp3/minimp3.xcodeproj/project.pbxproj b/Plugins/minimp3/minimp3.xcodeproj/project.pbxproj index 1864102b9..58fd270b8 100644 --- a/Plugins/minimp3/minimp3.xcodeproj/project.pbxproj +++ b/Plugins/minimp3/minimp3.xcodeproj/project.pbxproj @@ -26,6 +26,7 @@ 83747C272862DB9F0021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = ""; }; 83B73B612D8FC0A900A57F08 /* minimp3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = minimp3.h; sourceTree = ""; }; 83B73B622D8FC0A900A57F08 /* minimp3_ex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = minimp3_ex.h; sourceTree = ""; }; + 83CB566A2E064FAC003DD379 /* NSDictionary+Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+Optional.h"; path = "../../Utils/NSDictionary+Optional.h"; sourceTree = ""; }; 83F97B6728600F9300A70B97 /* CVbriHeader.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CVbriHeader.c; sourceTree = ""; }; 83F97B6828600F9300A70B97 /* CVbriHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CVbriHeader.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -51,6 +52,7 @@ 834A42BB287AFB0700EB9D9B /* AudioChunk.h */, 8372C93A27C786DD00E250C9 /* HTTPSource.h */, 8372C93927C7866B00E250C9 /* Logging.h */, + 83CB566A2E064FAC003DD379 /* NSDictionary+Optional.h */, 8372C93827C7865A00E250C9 /* Plugin.h */, 8372C93327C7861300E250C9 /* MP3Decoder.h */, 8372C93427C7861300E250C9 /* MP3Decoder.m */, diff --git a/Utils/NSDictionary+Optional.h b/Utils/NSDictionary+Optional.h new file mode 100644 index 000000000..9b144e348 --- /dev/null +++ b/Utils/NSDictionary+Optional.h @@ -0,0 +1,7 @@ +#import + +@interface NSDictionary (Optional) + ++ (NSDictionary *)initWithOptionalObjects:(const id _Nonnull [_Nullable])objects forKeys:(id const[])keys count:(NSUInteger)cnt; + +@end diff --git a/Utils/NSDictionary+Optional.m b/Utils/NSDictionary+Optional.m new file mode 100644 index 000000000..ae5ea155c --- /dev/null +++ b/Utils/NSDictionary+Optional.m @@ -0,0 +1,15 @@ +#import "NSDictionary+Merge.h" + +@implementation NSDictionary (Optional) + ++ (NSDictionary *)initWithOptionalObjects:(const id _Nonnull [_Nullable])objects forKeys:(id const[])keys count:(NSUInteger)cnt { + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; + for(NSUInteger i = 0; i < cnt; ++i) { + if(keys[i] && objects[i]) { + [dictionary setObject:objects[i] forKey:keys[i]]; + } + } + return [NSDictionary dictionaryWithDictionary:dictionary]; +} + +@end