@@ -556,20 +556,30 @@ public void Detect_MachO_64LE() {
556556 } finally { if ( File . Exists ( p ) ) File . Delete ( p ) ; }
557557 }
558558
559- [ Fact ]
560- public void Detect_Msg_Basic ( ) {
561- var p = Path . GetTempFileName ( ) ;
562- try {
563- var list = new List < byte > ( ) ;
564- list . AddRange ( new byte [ ] { 0xD0 , 0xCF , 0x11 , 0xE0 , 0xA1 , 0xB1 , 0x1A , 0xE1 } ) ;
565- list . AddRange ( new byte [ 128 ] ) ;
566- list . AddRange ( System . Text . Encoding . ASCII . GetBytes ( "__substg1.0_007D" ) ) ;
567- File . WriteAllBytes ( p , list . ToArray ( ) ) ;
568- var res = FI . Detect ( p ) ;
569- Assert . NotNull ( res ) ;
570- Assert . Equal ( "msg" , res ! . Extension ) ;
571- } finally { if ( File . Exists ( p ) ) File . Delete ( p ) ; }
572- }
559+ [ Fact ]
560+ public void Detect_Msg_Basic ( ) {
561+ var p = Path . GetTempFileName ( ) ;
562+ try {
563+ WriteSyntheticOleDirectoryFile ( p , "__substg1.0_007D" , "__properties_version1.0" ) ;
564+ var res = FI . Detect ( p ) ;
565+ Assert . NotNull ( res ) ;
566+ Assert . Equal ( "msg" , res ! . Extension ) ;
567+ } finally { if ( File . Exists ( p ) ) File . Delete ( p ) ; }
568+ }
569+
570+ [ Fact ]
571+ public void Detect_Msg_DoesNotMatch_OleFile_With_Marker_Bytes_Outside_DirectoryEntries ( ) {
572+ var p = Path . GetTempFileName ( ) ;
573+ try {
574+ var list = new List < byte > ( ) ;
575+ list . AddRange ( new byte [ ] { 0xD0 , 0xCF , 0x11 , 0xE0 , 0xA1 , 0xB1 , 0x1A , 0xE1 } ) ;
576+ list . AddRange ( new byte [ 128 ] ) ;
577+ list . AddRange ( System . Text . Encoding . ASCII . GetBytes ( "__substg1.0_007D" ) ) ;
578+ File . WriteAllBytes ( p , list . ToArray ( ) ) ;
579+ var res = FI . Detect ( p ) ;
580+ Assert . True ( res == null || ! string . Equals ( res . Extension , "msg" , StringComparison . OrdinalIgnoreCase ) ) ;
581+ } finally { if ( File . Exists ( p ) ) File . Delete ( p ) ; }
582+ }
573583
574584 [ Fact ]
575585 public void Classify_ContentKind_Works ( ) {
@@ -599,7 +609,7 @@ public void Guess_Zip_Subtypes_Jar() {
599609 }
600610
601611 [ Fact ]
602- public void Guess_Zip_Subtypes_Epub ( ) {
612+ public void Guess_Zip_Subtypes_Epub ( ) {
603613 var p = Path . GetTempFileName ( ) ;
604614 var zip = p + ".zip" ;
605615 try {
@@ -633,6 +643,57 @@ public void Guess_Zip_Subtypes_Vsix() {
633643 } finally { if ( File . Exists ( p ) ) File . Delete ( p ) ; if ( File . Exists ( zip ) ) File . Delete ( zip ) ; }
634644 }
635645
646+ private static void WriteSyntheticOleDirectoryFile ( string path , params string [ ] directoryNames )
647+ {
648+ var header = new byte [ 512 ] ;
649+ var sig = new byte [ ] { 0xD0 , 0xCF , 0x11 , 0xE0 , 0xA1 , 0xB1 , 0x1A , 0xE1 } ;
650+ Array . Copy ( sig , 0 , header , 0 , sig . Length ) ;
651+ header [ 0x1E ] = 0x09 ;
652+ header [ 0x1F ] = 0x00 ;
653+ // Our mini CFBF reader maps sector N to offset 512 + ((N + 1) * 512),
654+ // so FAT sector SID 0 lives at 1024 and directory sector SID 2 lives at 2048.
655+ WriteLe32 ( header , 0x2C , 1 ) ;
656+ WriteLe32 ( header , 0x30 , 2 ) ;
657+ WriteLe32 ( header , 0x4C , 0 ) ;
658+
659+ var fat = new byte [ 512 ] ;
660+ const int ENDOFCHAIN = unchecked ( ( int ) 0xFFFFFFFE ) ;
661+ WriteLe32 ( fat , 2 * 4 , ENDOFCHAIN ) ;
662+
663+ var dir = new byte [ 512 ] ;
664+ for ( int i = 0 ; i < directoryNames . Length && i < 4 ; i ++ )
665+ {
666+ WriteDirName ( dir , i * 128 , directoryNames [ i ] ) ;
667+ }
668+
669+ using var fs = File . Create ( path ) ;
670+ fs . Write ( header , 0 , header . Length ) ;
671+ fs . Position = 1024 ;
672+ fs . Write ( fat , 0 , fat . Length ) ;
673+ fs . Position = 2048 ;
674+ fs . Write ( dir , 0 , dir . Length ) ;
675+
676+ static void WriteDirName ( byte [ ] buf , int offset , string name )
677+ {
678+ var bytes = System . Text . Encoding . Unicode . GetBytes ( name + "\0 " ) ;
679+ Array . Copy ( bytes , 0 , buf , offset , Math . Min ( bytes . Length , 64 ) ) ;
680+ ushort len = ( ushort ) Math . Min ( bytes . Length , 128 ) ;
681+ buf [ offset + 0x40 ] = ( byte ) ( len & 0xFF ) ;
682+ buf [ offset + 0x41 ] = ( byte ) ( ( len >> 8 ) & 0xFF ) ;
683+ }
684+
685+ static void WriteLe32 ( byte [ ] buffer , int offset , int value )
686+ {
687+ unchecked
688+ {
689+ buffer [ offset ] = ( byte ) ( value & 0xFF ) ;
690+ buffer [ offset + 1 ] = ( byte ) ( ( value >> 8 ) & 0xFF ) ;
691+ buffer [ offset + 2 ] = ( byte ) ( ( value >> 16 ) & 0xFF ) ;
692+ buffer [ offset + 3 ] = ( byte ) ( ( value >> 24 ) & 0xFF ) ;
693+ }
694+ }
695+ }
696+
636697 [ Fact ]
637698 public void Analyze_Zip_With_Inner_Zip_Flags_Nested_Archive_Subtype ( ) {
638699 var p = Path . GetTempFileName ( ) ;
0 commit comments