@@ -654,48 +654,80 @@ private static bool IsMp4Brand(ReadOnlySpan<byte> brand)
654654
655655 private static string ? DetectZipBasedType ( ReadOnlySpan < byte > header )
656656 {
657- var ascii = Encoding . ASCII . GetString ( header ) ;
658-
659- if ( ascii . Contains ( "mimetypeapplication/epub+zip" , StringComparison . OrdinalIgnoreCase ) )
657+ // Patterns to search for (ASCII, case-insensitive)
658+ ReadOnlySpan < byte > epubPattern = "mimetypeapplication/epub+zip"u8 ;
659+ if ( ContainsAsciiIgnoreCase ( header , epubPattern ) )
660660 {
661661 return "application/epub+zip" ;
662662 }
663663
664- if ( ascii . Contains ( "mimetypeapplication/vnd.oasis.opendocument.text" , StringComparison . OrdinalIgnoreCase ) )
664+ ReadOnlySpan < byte > odtPattern = "mimetypeapplication/vnd.oasis.opendocument.text"u8 ;
665+ if ( ContainsAsciiIgnoreCase ( header , odtPattern ) )
665666 {
666667 return "application/vnd.oasis.opendocument.text" ;
667668 }
668669
669- if ( ascii . Contains ( "mimetypeapplication/vnd.oasis.opendocument.spreadsheet" , StringComparison . OrdinalIgnoreCase ) )
670+ ReadOnlySpan < byte > odsPattern = "mimetypeapplication/vnd.oasis.opendocument.spreadsheet"u8 ;
671+ if ( ContainsAsciiIgnoreCase ( header , odsPattern ) )
670672 {
671673 return "application/vnd.oasis.opendocument.spreadsheet" ;
672674 }
673675
674- if ( ascii . Contains ( "mimetypeapplication/vnd.oasis.opendocument.presentation" , StringComparison . OrdinalIgnoreCase ) )
676+ ReadOnlySpan < byte > odpPattern = "mimetypeapplication/vnd.oasis.opendocument.presentation"u8 ;
677+ if ( ContainsAsciiIgnoreCase ( header , odpPattern ) )
675678 {
676679 return "application/vnd.oasis.opendocument.presentation" ;
677680 }
678681
679- if ( ascii . Contains ( "word/" , StringComparison . OrdinalIgnoreCase ) )
682+ ReadOnlySpan < byte > wordPattern = "word/"u8 ;
683+ if ( ContainsAsciiIgnoreCase ( header , wordPattern ) )
680684 {
681685 return "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ;
682686 }
683687
684- if ( ascii . Contains ( "xl/" , StringComparison . OrdinalIgnoreCase ) )
688+ ReadOnlySpan < byte > xlPattern = "xl/"u8 ;
689+ if ( ContainsAsciiIgnoreCase ( header , xlPattern ) )
685690 {
686691 return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ;
687692 }
688693
689- if ( ascii . Contains ( "ppt/" , StringComparison . OrdinalIgnoreCase ) )
694+ ReadOnlySpan < byte > pptPattern = "ppt/"u8 ;
695+ if ( ContainsAsciiIgnoreCase ( header , pptPattern ) )
690696 {
691697 return "application/vnd.openxmlformats-officedocument.presentationml.presentation" ;
692698 }
693699
694- if ( ascii . Contains ( "AndroidManifest.xml" , StringComparison . OrdinalIgnoreCase ) )
700+ ReadOnlySpan < byte > androidManifestPattern = "AndroidManifest.xml"u8 ;
701+ if ( ContainsAsciiIgnoreCase ( header , androidManifestPattern ) )
695702 {
696703 return "application/vnd.android.package-archive" ;
697704 }
698705
699706 return null ;
700707 }
708+
709+ // Helper: case-insensitive ASCII search for pattern in span
710+ private static bool ContainsAsciiIgnoreCase ( ReadOnlySpan < byte > span , ReadOnlySpan < byte > pattern )
711+ {
712+ if ( pattern . Length == 0 || pattern . Length > span . Length )
713+ return false ;
714+
715+ for ( int i = 0 ; i <= span . Length - pattern . Length ; i ++ )
716+ {
717+ int j = 0 ;
718+ for ( ; j < pattern . Length ; j ++ )
719+ {
720+ byte a = span [ i + j ] ;
721+ byte b = pattern [ j ] ;
722+ // ASCII case-insensitive compare
723+ if ( a >= ( byte ) 'A' && a <= ( byte ) 'Z' ) a = ( byte ) ( a + 32 ) ;
724+ if ( b >= ( byte ) 'A' && b <= ( byte ) 'Z' ) b = ( byte ) ( b + 32 ) ;
725+ if ( a != b )
726+ break ;
727+ }
728+ if ( j == pattern . Length )
729+ return true ;
730+ }
731+ return false ;
732+ }
701733}
0 commit comments