@@ -2759,23 +2759,63 @@ static void ram_state_to_file(void)
27592759 command_event (CMD_EVENT_RAM_STATE_TO_FILE , state_path );
27602760}
27612761
2762+ /**
2763+ * Compute DJB2 hash of a short string, lowercasing ASCII on the fly.
2764+ * Assumes ext points to a valid, short (extension-length) string.
2765+ */
2766+ static INLINE uint32_t djb2_calculate_lower (const char * s )
2767+ {
2768+ uint32_t h = 5381 ;
2769+ for (; * s ; s ++ )
2770+ {
2771+ unsigned char c = (unsigned char )* s ;
2772+ /* Branchless ASCII tolower: set bit 5 if uppercase letter */
2773+ c |= ((unsigned int )c - 'A' < 26u ) ? 0x20 : 0x00 ;
2774+ h = (h << 5 ) + h + c ;
2775+ }
2776+ return h ;
2777+ }
2778+
27622779enum rarch_content_type path_is_media_type (const char * path )
27632780{
2764- char ext_lower [16 ];
2765- strlcpy (ext_lower , path_get_extension (path ), sizeof (ext_lower ));
2781+ const char * ext ;
2782+
2783+ if (!path || !* path )
2784+ return RARCH_CONTENT_NONE ;
27662785
2767- string_to_lower (ext_lower );
2786+ /* Fast streaming-protocol check: switch on first char to avoid
2787+ * testing all prefixes linearly. Only fall through on match. */
2788+ switch (path [0 ])
2789+ {
2790+ case 'u' :
2791+ if (string_starts_with_size (path , "udp://" , STRLEN_CONST ("udp://" )))
2792+ return RARCH_CONTENT_MOVIE ;
2793+ break ;
2794+ case 'h' :
2795+ if ( string_starts_with_size (path , "http://" , STRLEN_CONST ("http://" ))
2796+ || string_starts_with_size (path , "https://" , STRLEN_CONST ("https://" )))
2797+ return RARCH_CONTENT_MOVIE ;
2798+ break ;
2799+ case 't' :
2800+ if (string_starts_with_size (path , "tcp://" , STRLEN_CONST ("tcp://" )))
2801+ return RARCH_CONTENT_MOVIE ;
2802+ break ;
2803+ case 'r' :
2804+ if ( string_starts_with_size (path , "rtmp://" , STRLEN_CONST ("rtmp://" ))
2805+ || string_starts_with_size (path , "rtp://" , STRLEN_CONST ("rtp://" )))
2806+ return RARCH_CONTENT_MOVIE ;
2807+ break ;
2808+ default :
2809+ break ;
2810+ }
27682811
2769- /* hack, to detect livestreams so the ffmpeg core can be started */
2770- if ( string_starts_with_size (path , "udp://" , STRLEN_CONST ("udp://" ))
2771- || string_starts_with_size (path , "http://" , STRLEN_CONST ("http://" ))
2772- || string_starts_with_size (path , "https://" , STRLEN_CONST ("https://" ))
2773- || string_starts_with_size (path , "tcp://" , STRLEN_CONST ("tcp://" ))
2774- || string_starts_with_size (path , "rtmp://" , STRLEN_CONST ("rtmp://" ))
2775- || string_starts_with_size (path , "rtp://" , STRLEN_CONST ("rtp://" )))
2776- return RARCH_CONTENT_MOVIE ;
2812+ ext = path_get_extension (path );
2813+ if (!ext || !* ext )
2814+ return RARCH_CONTENT_NONE ;
27772815
2778- switch (msg_hash_to_file_type (msg_hash_calculate (ext_lower )))
2816+ /* Hash the extension directly, lowercasing during hashing —
2817+ * eliminates strlcpy, string_to_lower, and the stack buffer. */
2818+ switch (msg_hash_to_file_type (djb2_calculate_lower (ext )))
27792819 {
27802820#if defined(HAVE_FFMPEG ) || defined(HAVE_MPV )
27812821 case FILE_TYPE_OGM :
@@ -2831,7 +2871,6 @@ enum rarch_content_type path_is_media_type(const char *path)
28312871 case FILE_TYPE_BMP :
28322872 return RARCH_CONTENT_IMAGE ;
28332873#endif
2834- case FILE_TYPE_NONE :
28352874 default :
28362875 break ;
28372876 }
0 commit comments