- Timestamp:
- 2021-02-26T19:39:51+13:00 (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone2/perllib/cpan/Image/ExifTool/EXE.pm
r24107 r34921 5 5 # 6 6 # Revisions: 2008/08/28 - P. Harvey Created 7 # 2011/07/12 - P. Harvey Added CHM (ok, not EXE, but it fits here) 7 8 # 8 9 # References: 1) http://www.openwatcom.org/ftp/devel/docs/pecoff.pdf … … 21 22 use Image::ExifTool qw(:DataAccess :Utils); 22 23 23 $VERSION = '1. 04';24 $VERSION = '1.17'; 24 25 25 26 sub ProcessPEResources($$); … … 49 50 23 => 'HTML', 50 51 24 => 'Manifest', 52 ); 53 54 my %languageCode = ( 55 Notes => q{ 56 See L<https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid> 57 for the full list of Microsoft language codes. 58 }, 59 '0000' => 'Neutral', 60 '007F' => 'Invariant', 61 '0400' => 'Process default', 62 '0401' => 'Arabic', 63 '0402' => 'Bulgarian', 64 '0403' => 'Catalan', 65 '0404' => 'Chinese (Traditional)', 66 '0405' => 'Czech', 67 '0406' => 'Danish', 68 '0407' => 'German', 69 '0408' => 'Greek', 70 '0409' => 'English (U.S.)', 71 '040A' => 'Spanish (Castilian)', 72 '040B' => 'Finnish', 73 '040C' => 'French', 74 '040D' => 'Hebrew', 75 '040E' => 'Hungarian', 76 '040F' => 'Icelandic', 77 '0410' => 'Italian', 78 '0411' => 'Japanese', 79 '0412' => 'Korean', 80 '0413' => 'Dutch', 81 '0414' => 'Norwegian (Bokml)', 82 '0415' => 'Polish', 83 '0416' => 'Portuguese (Brazilian)', 84 '0417' => 'Rhaeto-Romanic', 85 '0418' => 'Romanian', 86 '0419' => 'Russian', 87 '041A' => 'Croato-Serbian (Latin)', 88 '041B' => 'Slovak', 89 '041C' => 'Albanian', 90 '041D' => 'Swedish', 91 '041E' => 'Thai', 92 '041F' => 'Turkish', 93 '0420' => 'Urdu', 94 # 0421-0493 ref 6 95 '0421' => 'Indonesian', 96 '0422' => 'Ukrainian', 97 '0423' => 'Belarusian', 98 '0424' => 'Slovenian', 99 '0425' => 'Estonian', 100 '0426' => 'Latvian', 101 '0427' => 'Lithuanian', 102 '0428' => 'Maori', 103 '0429' => 'Farsi', 104 '042a' => 'Vietnamese', 105 '042b' => 'Armenian', 106 '042c' => 'Azeri', 107 '042d' => 'Basque', 108 '042e' => 'Sorbian', 109 '042f' => 'Macedonian', 110 '0430' => 'Sutu', 111 '0431' => 'Tsonga', 112 '0432' => 'Tswana', 113 '0433' => 'Venda', 114 '0434' => 'Xhosa', 115 '0435' => 'Zulu', 116 '0436' => 'Afrikaans', 117 '0437' => 'Georgian', 118 '0438' => 'Faeroese', 119 '0439' => 'Hindi', 120 '043a' => 'Maltese', 121 '043b' => 'Saami', 122 '043c' => 'Gaelic', 123 '043e' => 'Malay', 124 '043f' => 'Kazak', 125 '0440' => 'Kyrgyz', 126 '0441' => 'Swahili', 127 '0443' => 'Uzbek', 128 '0444' => 'Tatar', 129 '0445' => 'Bengali', 130 '0446' => 'Punjabi', 131 '0447' => 'Gujarati', 132 '0448' => 'Oriya', 133 '0449' => 'Tamil', 134 '044a' => 'Telugu', 135 '044b' => 'Kannada', 136 '044c' => 'Malayalam', 137 '044d' => 'Assamese', 138 '044e' => 'Marathi', 139 '044f' => 'Sanskrit', 140 '0450' => 'Mongolian', 141 '0456' => 'Galician', 142 '0457' => 'Konkani', 143 '0458' => 'Manipuri', 144 '0459' => 'Sindhi', 145 '045a' => 'Syriac', 146 '0460' => 'Kashmiri', 147 '0461' => 'Nepali', 148 '0465' => 'Divehi', 149 '047f' => 'Invariant', 150 '048f' => 'Esperanto', 151 '0490' => 'Walon', 152 '0491' => 'Cornish', 153 '0492' => 'Welsh', 154 '0493' => 'Breton', 155 '0800' => 'Neutral 2', 156 '0804' => 'Chinese (Simplified)', 157 '0807' => 'German (Swiss)', 158 '0809' => 'English (British)', 159 '080A' => 'Spanish (Mexican)', 160 '080C' => 'French (Belgian)', 161 '0810' => 'Italian (Swiss)', 162 '0813' => 'Dutch (Belgian)', 163 '0814' => 'Norwegian (Nynorsk)', 164 '0816' => 'Portuguese', 165 '081A' => 'Serbo-Croatian (Cyrillic)', 166 '0C07' => 'German (Austrian)', 167 '0C09' => 'English (Australian)', 168 '0C0A' => 'Spanish (Modern)', 169 '0C0C' => 'French (Canadian)', 170 '1009' => 'English (Canadian)', 171 '100C' => 'French (Swiss)', 51 172 ); 52 173 … … 102 223 PrintConv => '$self->ConvertDateTime($val)', 103 224 }, 225 9 => { 226 Name => 'ImageFileCharacteristics', 227 # ref https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_image_file_header 228 PrintConv => { BITMASK => { 229 0 => 'No relocs', 230 1 => 'Executable', 231 2 => 'No line numbers', 232 3 => 'No symbols', 233 4 => 'Aggressive working-set trim', 234 5 => 'Large address aware', 235 7 => 'Bytes reversed lo', 236 8 => '32-bit', 237 9 => 'No debug', 238 10 => 'Removable run from swap', 239 11 => 'Net run from swap', 240 12 => 'System file', 241 13 => 'DLL', 242 14 => 'Uniprocessor only', 243 15 => 'Bytes reversed hi', 244 }}, 245 }, 104 246 10 => { 105 247 Name => 'PEType', 106 248 PrintHex => 1, 107 249 PrintConv => { 250 0x107 => 'ROM Image', 108 251 0x10b => 'PE32', 109 252 0x20b => 'PE32+', … … 154 297 2 => 'Windows GUI', 155 298 3 => 'Windows command line', 156 5 => 'OS/2 Command line', #5299 5 => 'OS/2 command line', #5 157 300 7 => 'POSIX command line', 158 301 9 => 'Windows CE GUI', … … 259 402 }, 260 403 LanguageCode => { 261 Notes => ' extracted from the StringFileInfo value',404 Notes => 'Windows code page; extracted from the StringFileInfo value', 262 405 # ref http://techsupt.winbatch.com/TS/T000001050F49.html 263 406 # (also see http://support.bigfix.com/fixlet/documents/WinInspectors-2006-08-10.pdf) … … 265 408 # (not a complete set) 266 409 PrintString => 1, 267 PrintConv => { 268 '0000' => 'Neutral', 269 '007F' => 'Invariant', 270 '0400' => 'Process default', 271 '0401' => 'Arabic', 272 '0402' => 'Bulgarian', 273 '0403' => 'Catalan', 274 '0404' => 'Chinese (Traditional)', 275 '0405' => 'Czech', 276 '0406' => 'Danish', 277 '0407' => 'German', 278 '0408' => 'Greek', 279 '0409' => 'English (U.S.)', 280 '040A' => 'Spanish (Castilian)', 281 '040B' => 'Finnish', 282 '040C' => 'French', 283 '040D' => 'Hebrew', 284 '040E' => 'Hungarian', 285 '040F' => 'Icelandic', 286 '0410' => 'Italian', 287 '0411' => 'Japanese', 288 '0412' => 'Korean', 289 '0413' => 'Dutch', 290 '0414' => 'Norwegian (Bokml)', 291 '0415' => 'Polish', 292 '0416' => 'Portuguese (Brazilian)', 293 '0417' => 'Rhaeto-Romanic', 294 '0418' => 'Romanian', 295 '0419' => 'Russian', 296 '041A' => 'Croato-Serbian (Latin)', 297 '041B' => 'Slovak', 298 '041C' => 'Albanian', 299 '041D' => 'Swedish', 300 '041E' => 'Thai', 301 '041F' => 'Turkish', 302 '0420' => 'Urdu', 303 # 0421-0493 ref 6 304 '0421' => 'Indonesian', 305 '0422' => 'Ukrainian', 306 '0423' => 'Belarusian', 307 '0424' => 'Slovenian', 308 '0425' => 'Estonian', 309 '0426' => 'Latvian', 310 '0427' => 'Lithuanian', 311 '0428' => 'Maori', 312 '0429' => 'Farsi', 313 '042a' => 'Vietnamese', 314 '042b' => 'Armenian', 315 '042c' => 'Azeri', 316 '042d' => 'Basque', 317 '042e' => 'Sorbian', 318 '042f' => 'Macedonian', 319 '0430' => 'Sutu', 320 '0431' => 'Tsonga', 321 '0432' => 'Tswana', 322 '0433' => 'Venda', 323 '0434' => 'Xhosa', 324 '0435' => 'Zulu', 325 '0436' => 'Afrikaans', 326 '0437' => 'Georgian', 327 '0438' => 'Faeroese', 328 '0439' => 'Hindi', 329 '043a' => 'Maltese', 330 '043b' => 'Saami', 331 '043c' => 'Gaelic', 332 '043e' => 'Malay', 333 '043f' => 'Kazak', 334 '0440' => 'Kyrgyz', 335 '0441' => 'Swahili', 336 '0443' => 'Uzbek', 337 '0444' => 'Tatar', 338 '0445' => 'Bengali', 339 '0446' => 'Punjabi', 340 '0447' => 'Gujarati', 341 '0448' => 'Oriya', 342 '0449' => 'Tamil', 343 '044a' => 'Telugu', 344 '044b' => 'Kannada', 345 '044c' => 'Malayalam', 346 '044d' => 'Assamese', 347 '044e' => 'Marathi', 348 '044f' => 'Sanskrit', 349 '0450' => 'Mongolian', 350 '0456' => 'Galician', 351 '0457' => 'Konkani', 352 '0458' => 'Manipuri', 353 '0459' => 'Sindhi', 354 '045a' => 'Syriac', 355 '0460' => 'Kashmiri', 356 '0461' => 'Nepali', 357 '0465' => 'Divehi', 358 '047f' => 'Invariant', 359 '048f' => 'Esperanto', 360 '0490' => 'Walon', 361 '0491' => 'Cornish', 362 '0492' => 'Welsh', 363 '0493' => 'Breton', 364 '0800' => 'Neutral 2', 365 '0804' => 'Chinese (Simplified)', 366 '0807' => 'German (Swiss)', 367 '0809' => 'English (British)', 368 '080A' => 'Spanish (Mexican)', 369 '080C' => 'French (Belgian)', 370 '0810' => 'Italian (Swiss)', 371 '0813' => 'Dutch (Belgian)', 372 '0814' => 'Norwegian (Nynorsk)', 373 '0816' => 'Portuguese', 374 '081A' => 'Serbo-Croatian (Cyrillic)', 375 '0C07' => 'German (Austrian)', 376 '0C09' => 'English (Australian)', 377 '0C0A' => 'Spanish (Modern)', 378 '0C0C' => 'French (Canadian)', 379 '1009' => 'English (Canadian)', 380 '100C' => 'French (Swiss)', 381 }, 410 SeparateTable => 1, 411 PrintConv => \%languageCode, 382 412 }, 383 413 CharacterSet => { … … 412 442 LegalCopyright => { }, 413 443 LegalTrademarks => { }, 414 OriginalFilename=> { },444 OriginalFilename=> { Name => 'OriginalFileName' }, 415 445 PrivateBuild => { }, 416 446 ProductName => { }, … … 595 625 8 => 'Dynamically bound bundle', 596 626 9 => 'Shared library stub for static linking', 627 # (the following from Apple loader.h header file) 628 10 => 'Debug information', 629 11 => 'x86_64 kexts', 597 630 }, 631 }, 632 6 => { 633 Name => 'ObjectFlags', 634 PrintHex => 1, 635 # ref Apple loader.h header file 636 PrintConv => { BITMASK => { 637 0 => 'No undefs', 638 1 => 'Incrementa link', 639 2 => 'Dyld link', 640 3 => 'Bind at load', 641 4 => 'Prebound', 642 5 => 'Split segs', 643 6 => 'Lazy init', 644 7 => 'Two level', 645 8 => 'Force flat', 646 9 => 'No multi defs', 647 10 => 'No fix prebinding', 648 11 => 'Prebindable', 649 12 => 'All mods bound', 650 13 => 'Subsections via symbols', 651 14 => 'Canonical', 652 15 => 'Weak defines', 653 16 => 'Binds to weak', 654 17 => 'Allow stack execution', 655 18 => 'Dead strippable dylib', 656 19 => 'Root safe', 657 20 => 'No reexported dylibs', 658 21 => 'Random address', 659 }}, 598 660 }, 599 661 ); … … 699 761 ); 700 762 763 # Information extracted from static library archives 764 # (ref http://opensource.apple.com//source/xnu/xnu-1456.1.26/EXTERNAL_HEADERS/ar.h) 765 %Image::ExifTool::EXE::AR = ( 766 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 767 GROUPS => { 2 => 'Other' }, 768 NOTES => q{ 769 Information extracted from static libraries. 770 }, 771 # 0 string[16] ar_name 772 16 => { 773 Name => 'CreateDate', 774 Groups => { 2 => 'Time' }, 775 Format => 'string[12]', 776 ValueConv => 'ConvertUnixTime($val,1)', 777 PrintConv => '$self->ConvertDateTime($val)', 778 }, 779 # 28 string[6] ar_uid 780 # 34 string[6] ar_gid 781 # 40 string[8] ar_mode 782 # 48 string[10] ar_size 783 # 58 string[2] terminator "`\n" 784 ); 785 786 # Microsoft compiled help format (ref http://www.russotto.net/chm/chmformat.html) 787 %Image::ExifTool::EXE::CHM = ( 788 PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, 789 GROUPS => { 2 => 'Other' }, 790 NOTES => 'Tags extracted from Microsoft Compiled HTML files.', 791 FORMAT => 'int32u', 792 1 => { Name => 'CHMVersion' }, 793 # 2 - total header length 794 # 3 - 1 795 # 4 - low bits of date/time value plus 42 (ref http://www.nongnu.org/chmspec/latest/ITSF.html) 796 5 => { 797 Name => 'LanguageCode', 798 SeparateTable => 1, 799 ValueConv => 'sprintf("%.4X", $val)', 800 PrintConv => \%languageCode, 801 }, 802 ); 803 804 #------------------------------------------------------------------------------ 805 # Extract information from a CHM file 806 # Inputs: 0) ExifTool object reference, 1) dirInfo reference 807 # Returns: 1 on success, 0 if this wasn't a valid CHM file 808 sub ProcessCHM($$) 809 { 810 my ($et, $dirInfo) = @_; 811 my $raf = $$dirInfo{RAF}; 812 my $buff; 813 814 return 0 unless $raf->Read($buff, 56) == 56 and 815 $buff =~ /^ITSF.{20}\x10\xfd\x01\x7c\xaa\x7b\xd0\x11\x9e\x0c\0\xa0\xc9\x22\xe6\xec/s; 816 my $tagTablePtr = GetTagTable('Image::ExifTool::EXE::CHM'); 817 $et->SetFileType(); 818 SetByteOrder('II'); 819 $et->ProcessDirectory({ DataPt => \$buff }, $tagTablePtr); 820 return 1; 821 } 822 701 823 #------------------------------------------------------------------------------ 702 824 # Read Unicode string (null terminated) from resource 703 # Inputs: 0) data ref, 1) start offset, 2) optional ExifTool object ref825 # Inputs: 0) data ref, 1) start offset, 2) data end, 3) optional ExifTool object ref 704 826 # Returns: 0) Unicode string translated to UTF8, or current CharSet with ExifTool ref 705 827 # 1) end pos (rounded up to nearest 4 bytes) 706 sub ReadUnicodeStr($$ ;$)828 sub ReadUnicodeStr($$$;$) 707 829 { 708 my ($dataPt, $pos, $e xifTool) = @_;709 my $len = length $$dataPt;830 my ($dataPt, $pos, $end, $et) = @_; 831 $end = length $$dataPt if $end > length $$dataPt; # (be safe) 710 832 my $str = ''; 711 while ($pos + 2 <= $ len) {833 while ($pos + 2 <= $end) { 712 834 my $ch = substr($$dataPt, $pos, 2); 713 835 $pos += 2; … … 716 838 } 717 839 $pos += 2 if $pos & 0x03; 718 my $to = $e xifTool ? $exifTool->Options('Charset') : 'UTF8';840 my $to = $et ? $et->Options('Charset') : 'UTF8'; 719 841 return (Image::ExifTool::Decode(undef,$str,'UCS2','II',$to), $pos); 720 842 } … … 726 848 sub ProcessPEVersion($$) 727 849 { 728 my ($e xifTool, $dirInfo) = @_;850 my ($et, $dirInfo) = @_; 729 851 my $dataPt = $$dirInfo{DataPt}; 730 852 my $pos = $$dirInfo{DirStart}; … … 740 862 $type = Get16u($dataPt, $pos + 4); 741 863 return 0 unless $len or $valLen; # prevent possible infinite loop 742 ($string, $strEnd) = ReadUnicodeStr($dataPt, $pos + 6 );864 ($string, $strEnd) = ReadUnicodeStr($dataPt, $pos + 6, $pos + $len); 743 865 return 0 if $strEnd + $valLen > $end; 744 866 unless ($index or $string eq 'VS_VERSION_INFO') { 745 $e xifTool->Warn('Invalid Version Info block');867 $et->Warn('Invalid Version Info block'); 746 868 return 0; 747 869 } … … 751 873 $$dirInfo{DirLen} = $valLen; 752 874 my $subTablePtr = GetTagTable('Image::ExifTool::EXE::PEVersion'); 753 $e xifTool->ProcessDirectory($dirInfo, $subTablePtr);875 $et->ProcessDirectory($dirInfo, $subTablePtr); 754 876 $pos = $strEnd + $valLen; 755 877 } elsif ($string eq 'StringFileInfo' and $valLen == 0) { … … 762 884 $valLen = Get16u($dataPt, $pt + 2); 763 885 # $type = Get16u($dataPt, $pt + 4); 886 my $entryEnd = $pt + $len; 764 887 # get tag ID (converted to UTF8) 765 ($string, $pt) = ReadUnicodeStr($dataPt, $pt + 6 );888 ($string, $pt) = ReadUnicodeStr($dataPt, $pt + 6, $entryEnd); 766 889 unless ($index) { 767 890 # separate the language code and character set … … 774 897 $string = substr($string, 0, 4); 775 898 } 776 $e xifTool->HandleTag($tagTablePtr, 'LanguageCode', uc $string);777 $e xifTool->HandleTag($tagTablePtr, 'CharacterSet', uc $char) if $char;899 $et->HandleTag($tagTablePtr, 'LanguageCode', uc $string); 900 $et->HandleTag($tagTablePtr, 'CharacterSet', uc $char) if $char; 778 901 next; 779 902 } … … 784 907 $name =~ tr/-_a-zA-Z0-9//dc; # remove illegal characters 785 908 next unless length $name; 786 Image::ExifTool::AddTagToTable($tagTablePtr, $tag, { Name => $name });909 AddTagToTable($tagTablePtr, $tag, { Name => $name }); 787 910 } 788 911 # get tag value (converted to current Charset) 789 912 if ($valLen) { 790 ($string, $pt) = ReadUnicodeStr($dataPt, $pt, $e xifTool);913 ($string, $pt) = ReadUnicodeStr($dataPt, $pt, $entryEnd, $et); 791 914 } else { 792 915 $string = ''; 793 916 } 794 $exifTool->HandleTag($tagTablePtr, $tag, $string); 917 $et->HandleTag($tagTablePtr, $tag, $string); 918 # step to next entry (padded to an even word) 919 $pt = ($entryEnd + 3) & 0xfffffffc; 795 920 } 796 921 } else { … … 808 933 sub ProcessPEResources($$) 809 934 { 810 my ($e xifTool, $dirInfo) = @_;935 my ($et, $dirInfo) = @_; 811 936 my $raf = $$dirInfo{RAF}; 812 937 my $base = $$dirInfo{Base}; 813 938 my $dirStart = $$dirInfo{DirStart} + $base; 814 939 my $level = $$dirInfo{Level} || 0; 815 my $verbose = $e xifTool->Options('Verbose');940 my $verbose = $et->Options('Verbose'); 816 941 my ($buff, $buf2, $item); 817 942 … … 833 958 # ignore everything but the Version resource unless verbose 834 959 if ($verbose) { 835 $e xifTool->VPrint(0, "$resType resource:\n");960 $et->VPrint(0, "$resType resource:\n"); 836 961 } else { 837 962 next unless $resType eq 'Version'; … … 843 968 $$dirInfo{DirStart} = $entryPos & 0x7fffffff; 844 969 $$dirInfo{Level} = $level + 1; 845 ProcessPEResources($e xifTool, $dirInfo) or return 0;970 ProcessPEResources($et, $dirInfo) or return 0; 846 971 --$$dirInfo{Level}; 847 972 } elsif ($$dirInfo{ResType} eq 'Version' and $level == 2 and … … 863 988 return 0 unless $filePos; 864 989 $raf->Seek($filePos, 0) and $raf->Read($buf2, $len) == $len or return 0; 865 ProcessPEVersion($e xifTool, {990 ProcessPEVersion($et, { 866 991 DataPt => \$buf2, 867 992 DataLen => $len, 868 993 DirStart => 0, 869 994 DirLen => $len, 870 }) or $e xifTool->Warn('Possibly corrupt Version resource');995 }) or $et->Warn('Possibly corrupt Version resource'); 871 996 $$dirInfo{GotVersion} = 1; # set flag so we don't do this again 872 997 } … … 881 1006 sub ProcessPEDict($$) 882 1007 { 883 my ($e xifTool, $dirInfo) = @_;1008 my ($et, $dirInfo) = @_; 884 1009 my $raf = $$dirInfo{RAF}; 885 1010 my $dataPt = $$dirInfo{DataPt}; 886 1011 my $dirLen = length($$dataPt); 887 my ($pos, @sections, %dirInfo );1012 my ($pos, @sections, %dirInfo, $rsrcFound); 888 1013 889 1014 # loop through all sections … … 895 1020 # remember the section offsets for the VirtualAddress lookup later 896 1021 push @sections, { Base => $offset, Size => $size, VirtualAddress => $va }; 897 # save details of the first resource section 1022 # save details of the first resource section (or .text if .rsrc not found, ref forum11465) 1023 next unless ($name eq ".rsrc\0\0\0" and not $rsrcFound and defined($rsrcFound = 1)) or 1024 ($name eq ".text\0\0\0" and not %dirInfo); 898 1025 %dirInfo = ( 899 1026 RAF => $raf, … … 902 1029 DirLen => $size, 903 1030 Sections => \@sections, 904 ) if $name eq ".rsrc\0\0\0" and not %dirInfo;1031 ); 905 1032 } 906 1033 # process the first resource section 907 ProcessPEResources($e xifTool, \%dirInfo) or return 0 if %dirInfo;1034 ProcessPEResources($et, \%dirInfo) or return 0 if %dirInfo; 908 1035 return 1; 1036 } 1037 1038 #------------------------------------------------------------------------------ 1039 # Override file type if necessary for Mach object files and libraries 1040 # Inputs: 0) ExifTool ref, 1) ObjectFileType number, 2) flag for fat binary 1041 my %machOverride = ( 1042 1 => [ 'object file', 'O' ], 1043 6 => [ 'dynamic link library', 'DYLIB' ], 1044 8 => [ 'dynamic bound bundle', 'DYLIB' ], 1045 9 => [ 'dynamic link library stub', 'DYLIB' ], 1046 ); 1047 sub MachOverride($$;$) 1048 { 1049 my ($et, $objType, $fat) = @_; 1050 my $override = $machOverride{$objType}; 1051 if ($override) { 1052 my $desc = 'Mach-O ' . ($fat ? 'fat ' : '') . $$override[0]; 1053 $et->OverrideFileType($desc, undef, $$override[1]); 1054 } 1055 } 1056 1057 #------------------------------------------------------------------------------ 1058 # Extract tags from Mach header 1059 # Inputs: 0) ExifTool ref, 1) data ref, 2) flag to extract object type 1060 # Returns: true if Mach header was found 1061 # Mach type based on magic number 1062 # [bit depth, byte order starting with "Little" or "Big"] 1063 my %machType = ( 1064 "\xfe\xed\xfa\xce" => ['32 bit', 'Big endian'], 1065 "\xce\xfa\xed\xfe" => ['32 bit', 'Little endian'], 1066 "\xfe\xed\xfa\xcf" => ['64 bit', 'Big endian'], 1067 "\xcf\xfa\xed\xfe" => ['64 bit', 'Little endian'], 1068 ); 1069 sub ExtractMachTags($$;$) 1070 { 1071 my ($et, $dataPt, $doObj) = @_; 1072 # get information about mach header based on the magic number (first 4 bytes) 1073 my $info = $machType{substr($$dataPt, 0, 4)}; 1074 if ($info) { 1075 # Mach header structure: 1076 # 0 int32u magic 1077 # 4 int32u cputype 1078 # 8 int32u cpusubtype 1079 # 12 int32u filetype 1080 # 16 int32u ncmds 1081 # 20 int32u sizeofcmds 1082 # 24 int32u flags 1083 my $tagTablePtr = GetTagTable('Image::ExifTool::EXE::MachO'); 1084 SetByteOrder($$info[1]); 1085 my $cpuType = Get32s($dataPt, 4); 1086 my $subType = Get32s($dataPt, 8); 1087 $et->HandleTag($tagTablePtr, 0, $$info[0]); 1088 $et->HandleTag($tagTablePtr, 1, $$info[1]); 1089 $et->HandleTag($tagTablePtr, 3, $cpuType); 1090 $et->HandleTag($tagTablePtr, 4, "$cpuType $subType"); 1091 if ($doObj) { 1092 my $objType = Get32u($dataPt, 12); 1093 my $flags = Get32u($dataPt, 24); 1094 $et->HandleTag($tagTablePtr, 5, $objType); 1095 $et->HandleTag($tagTablePtr, 6, $flags); 1096 # override file type if this is an object file or library 1097 MachOverride($et, $objType); 1098 } else { # otherwise this was a static library 1099 $et->OverrideFileType('Mach-O static library', undef, 'A'); 1100 } 1101 return 1; 1102 } 1103 return 0; 909 1104 } 910 1105 … … 915 1110 sub ProcessEXE($$) 916 1111 { 917 my ($e xifTool, $dirInfo) = @_;1112 my ($et, $dirInfo) = @_; 918 1113 my $raf = $$dirInfo{RAF}; 919 my ($buff, $buf2, $type, $ tagTablePtr, %dirInfo);1114 my ($buff, $buf2, $type, $mime, $ext, $tagTablePtr, %dirInfo); 920 1115 921 1116 my $size = $raf->Read($buff, 0x40) or return 0; 1117 my $fast3 = $$et{OPTIONS}{FastScan} && $$et{OPTIONS}{FastScan} == 3; 922 1118 # 923 1119 # DOS and Windows EXE … … 927 1123 # validate DOS header 928 1124 # (ref http://www.delphidabbler.com/articles?article=8&part=2) 929 # 0 magic : int16u #Magic number ("MZ")930 # 2 cblp : int16u #Bytes on last page of file931 # 4 cp : int16u #Pages in file932 # 6 crlc : int16u #Relocations933 # 8 cparhdr : int16u #Size of header in paragraphs934 # 10 minalloc: int16u #Minimum extra paragraphs needed935 # 12 maxalloc: int16u #Maximum extra paragraphs needed936 # 14 ss : int16u #Initial (relative) SS value937 # 16 sp : int16u #Initial SP value938 # 18 csum : int16u #Checksum939 # 20 ip : int16u #Initial IP value940 # 22 cs : int16u #Initial (relative) CS value941 # 24 lfarlc : int16u #Address of relocation table942 # 26 ovno : int16u #Overlay number943 # 28 res : int16u[4] #Reserved words944 # 36 oemid : int16u #OEM identifier (for oeminfo)945 # 38 oeminfo : int16u #OEM info; oemid specific946 # 40 res2 : int16u[10]#Reserved words947 # 60 lfanew : int32u; #File address of new exe header1125 # 0 int16u magic - Magic number ("MZ") 1126 # 2 int16u cblp - Bytes on last page of file 1127 # 4 int16u cp - Pages in file 1128 # 6 int16u crlc - Relocations 1129 # 8 int16u cparhdr - Size of header in paragraphs 1130 # 10 int16u minalloc - Minimum extra paragraphs needed 1131 # 12 int16u maxalloc - Maximum extra paragraphs needed 1132 # 14 int16u ss - Initial (relative) SS value 1133 # 16 int16u sp - Initial SP value 1134 # 18 int16u csum - Checksum 1135 # 20 int16u ip - Initial IP value 1136 # 22 int16u cs - Initial (relative) CS value 1137 # 24 int16u lfarlc - Address of relocation table 1138 # 26 int16u ovno - Overlay number 1139 # 28 int16u[4] res - Reserved words 1140 # 36 int16u oemid - OEM identifier (for oeminfo) 1141 # 38 int16u oeminfo - OEM info; oemid specific 1142 # 40 int16u[10] res2 - Reserved words 1143 # 60 int32u; lfanew - File address of new exe header 948 1144 SetByteOrder('II'); 949 1145 my ($cblp, $cp, $lfarlc, $lfanew) = unpack('x2v2x18vx34V', $buff); 950 1146 my $fileSize = ($cp - ($cblp ? 1 : 0)) * 512 + $cblp; 951 return 0 if $fileSize < 0x40 or $fileSize < $lfarlc;952 # read the Windows PE header953 if ($lfarlc == 0x40 and $fileSize > $lfanew + 2 and954 # read the Windows NE, PE or LE (virtual device driver) header955 $raf->Seek($lfanew, 0) and $raf->Read($buff, 0x40) and956 $buff =~ /^(NE|PE|LE)/)957 {1147 #(patch to accommodate observed 64-bit files) 1148 #return 0 if $fileSize < 0x40 or $fileSize < $lfarlc; 1149 #return 0 if $fileSize < 0x40; (changed to warning in ExifTool 12.08) 1150 $et->Warn('Invalid file size in DOS header') if $fileSize < 0x40; 1151 # read the Windows NE, PE or LE (virtual device driver) header 1152 #if ($lfarlc == 0x40 and $fileSize > $lfanew + 2 and ... 1153 if ($raf->Seek($lfanew, 0) and $raf->Read($buff, 0x40) and $buff =~ /^(NE|PE|LE)/) { 958 1154 if ($1 eq 'NE') { 959 1155 if ($size >= 0x40) { # NE header is 64 bytes (ref 2) 960 1156 # check for DLL 961 1157 my $appFlags = Get16u(\$buff, 0x0c); 962 $type = 'Win16 ' . ($appFlags & 0x80 ? 'DLL' : 'EXE'); 1158 $ext = $appFlags & 0x80 ? 'DLL' : 'EXE'; 1159 $type = "Win16 $ext"; 963 1160 # offset 0x02 is 2 bytes with linker version and revision numbers 964 1161 # offset 0x36 is executable type (2 = Windows) … … 974 1171 # 22 int16u Characteristics 975 1172 if ($size >= 24) { # PE header is 24 bytes (plus optional header) 976 my $flags = Get16u(\$buff, 22); 977 $exifTool->SetFileType('Win32 ' . ($flags & 0x2000 ? 'DLL' : 'EXE')); 1173 my $mach = Get16u(\$buff, 4); # MachineType 1174 my $flags = Get16u(\$buff, 22); # ImageFileCharacteristics 1175 my $machine = $Image::ExifTool::EXE::Main{0}{PrintConv}{$mach} || ''; 1176 my $winType = $machine =~ /64/ ? 'Win64' : 'Win32'; 1177 $ext = $flags & 0x2000 ? 'DLL' : 'EXE'; 1178 $et->SetFileType("$winType $ext", undef, $ext); 1179 return 1 if $fast3; 978 1180 # read the rest of the optional header if necessary 979 1181 my $optSize = Get16u(\$buff, 20); … … 984 1186 $size += $more; 985 1187 my $magic = Get16u(\$buff, 24); 986 # verify PE 32/PE32+magic number987 unless ($magic == 0x10 b or $magic == 0x20b) {988 $e xifTool->Warn('Unknown PE magic number');1188 # verify PE magic number 1189 unless ($magic == 0x107 or $magic == 0x10b or $magic == 0x20b) { 1190 $et->Warn('Unknown PE magic number'); 989 1191 return 1; 990 1192 } 1193 # --> 64-bit if $magic is 0x20b ???? 991 1194 } else { 992 $e xifTool->Warn('Error reading optional header');1195 $et->Warn('Error reading optional header'); 993 1196 } 994 1197 } … … 1000 1203 DataLen => $size, 1001 1204 DirStart => 4, 1002 DirLen => $size ,1205 DirLen => $size - 4, 1003 1206 ); 1004 $e xifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);1207 $et->ProcessDirectory(\%dirInfo, $tagTablePtr); 1005 1208 # process data dictionary 1006 1209 my $num = Get16u(\$buff, 6); # NumberOfSections … … 1010 1213 DataPt => \$buff, 1011 1214 ); 1012 ProcessPEDict($e xifTool, \%dirInfo) or $exifTool->Warn('Error processing PE data dictionary');1215 ProcessPEDict($et, \%dirInfo) or $et->Warn('Error processing PE data dictionary'); 1013 1216 } 1014 1217 return 1; … … 1016 1219 } else { 1017 1220 $type = 'Virtual Device Driver'; 1221 $ext = '386'; 1018 1222 } 1019 1223 } else { 1020 1224 $type = 'DOS EXE'; 1225 $ext = 'exe'; 1021 1226 } 1022 1227 # … … 1029 1234 if ($1 eq "\xca\xfe\xba\xbe") { 1030 1235 SetByteOrder('MM'); 1031 $exifTool->SetFileType('Mach-O fat binary executable'); 1236 $et->SetFileType('Mach-O fat binary executable', undef, ''); 1237 return 1 if $fast3; 1032 1238 my $count = Get32u(\$buff, 4); # get architecture count 1033 1239 my $more = $count * 20 - ($size - 8); 1034 1240 if ($more > 0) { 1035 1241 unless ($raf->Read($buf2, $more) == $more) { 1036 $e xifTool->Warn('Error reading fat-arch headers');1242 $et->Warn('Error reading fat-arch headers'); 1037 1243 return 1; 1038 1244 } … … 1040 1246 $size += $more; 1041 1247 } 1042 $e xifTool->HandleTag($tagTablePtr, 2, $count);1248 $et->HandleTag($tagTablePtr, 2, $count); 1043 1249 my $i; 1044 1250 for ($i=0; $i<$count; ++$i) { 1045 1251 my $cpuType = Get32s(\$buff, 8 + $i * 20); 1046 my $ cpuSubtype = Get32u(\$buff, 12 + $i * 20);1047 $e xifTool->HandleTag($tagTablePtr, 3, $cpuType);1048 $e xifTool->HandleTag($tagTablePtr, 4, "$cpuType $cpuSubtype");1252 my $subType = Get32s(\$buff, 12 + $i * 20); 1253 $et->HandleTag($tagTablePtr, 3, $cpuType); 1254 $et->HandleTag($tagTablePtr, 4, "$cpuType $subType"); 1049 1255 } 1050 1256 # load first Mach-O header to get the object file type … … 1053 1259 if ($buf2 =~ /^(\xfe\xed\xfa(\xce|\xcf)|(\xce|\xcf)\xfa\xed\xfe)/) { 1054 1260 SetByteOrder($buf2 =~ /^\xfe\xed/ ? 'MM' : 'II'); 1055 my $objType = Get32s(\$buf2, 12); 1056 $exifTool->HandleTag($tagTablePtr, 5, $objType); 1261 my $objType = Get32u(\$buf2, 12); 1262 $et->HandleTag($tagTablePtr, 5, $objType); 1263 # override file type if this is a library or object file 1264 MachOverride($et, $objType, 'fat'); 1057 1265 } elsif ($buf2 =~ /^!<arch>\x0a/) { 1058 1266 # .a libraries use this magic number 1059 $exifTool->HandleTag($tagTablePtr, 5, -1); 1267 $et->HandleTag($tagTablePtr, 5, -1); 1268 # override file type since this is a library 1269 $et->OverrideFileType('Mach-O fat static library', undef, 'A'); 1060 1270 } else { 1061 $e xifTool->Warn('Unrecognized object file type');1271 $et->Warn('Unrecognized object file type'); 1062 1272 } 1063 1273 } else { 1064 $e xifTool->Warn('Error reading file');1274 $et->Warn('Error reading file'); 1065 1275 } 1066 } elsif ($size >= 16) { 1067 $exifTool->SetFileType('Mach-O executable'); 1068 my $info = { 1069 "\xfe\xed\xfa\xce" => ['32 bit', 'Big endian'], 1070 "\xce\xfa\xed\xfe" => ['32 bit', 'Little endian'], 1071 "\xfe\xed\xfa\xcf" => ['64 bit', 'Big endian'], 1072 "\xcf\xfa\xed\xfe" => ['64 bit', 'Little endian'], 1073 }->{substr($buff, 0, 4)}; 1074 my $byteOrder = ($buff =~ /^\xfe/) ? 'MM' : 'II'; 1075 SetByteOrder($byteOrder); 1076 my $cpuType = Get32s(\$buff, 4); 1077 my $cpuSubtype = Get32s(\$buff, 8); 1078 my $objType = Get32s(\$buff, 12); 1079 $exifTool->HandleTag($tagTablePtr, 0, $$info[0]); 1080 $exifTool->HandleTag($tagTablePtr, 1, $$info[1]); 1081 $exifTool->HandleTag($tagTablePtr, 3, $cpuType); 1082 $exifTool->HandleTag($tagTablePtr, 4, "$cpuType $cpuSubtype"); 1083 $exifTool->HandleTag($tagTablePtr, 5, $objType); 1276 } elsif ($size >= 16) { 1277 $et->SetFileType('Mach-O executable', undef, ''); 1278 return 1 if $fast3; 1279 ExtractMachTags($et, \$buff, 1); 1084 1280 } 1085 1281 return 1; … … 1089 1285 } elsif ($buff =~ /^Joy!peff/ and $size > 12) { 1090 1286 # ref http://developer.apple.com/documentation/mac/pdf/MacOS_RT_Architectures.pdf 1091 $exifTool->SetFileType('Classic MacOS executable'); 1287 $et->SetFileType('Classic MacOS executable', undef, ''); 1288 return 1 if $fast3; 1092 1289 SetByteOrder('MM'); 1093 1290 $tagTablePtr = GetTagTable('Image::ExifTool::EXE::PEF'); … … 1099 1296 DirLen => $size, 1100 1297 ); 1101 $e xifTool->ProcessDirectory(\%dirInfo, $tagTablePtr);1298 $et->ProcessDirectory(\%dirInfo, $tagTablePtr); 1102 1299 return 1; 1103 1300 # … … 1105 1302 # 1106 1303 } elsif ($buff =~ /^\x7fELF/ and $size >= 16) { 1107 $exifTool->SetFileType("ELF executable"); 1304 $et->SetFileType('ELF executable', undef, ''); 1305 return 1 if $fast3; 1108 1306 SetByteOrder(Get8u(\$buff,5) == 1 ? 'II' : 'MM'); 1109 1307 $tagTablePtr = GetTagTable('Image::ExifTool::EXE::ELF'); 1110 1308 %dirInfo = ( 1111 DataPt => \$buff,1309 DataPt => \$buff, 1112 1310 DataPos => 0, 1113 1311 DataLen => $size, 1114 DirStart => 0, 1115 DirLen => $size, 1312 DirLen => $size, 1116 1313 ); 1117 $exifTool->ProcessDirectory(\%dirInfo, $tagTablePtr); 1314 $et->ProcessDirectory(\%dirInfo, $tagTablePtr); 1315 # override file type if this is a library or object file 1316 my $override = { 1317 1 => [ 'ELF object file', 'O' ], 1318 3 => [ 'ELF shared library', 'SO' ], 1319 }->{$$et{VALUE}{ObjectFileType} || 0}; 1320 $et->OverrideFileType($$override[0], undef, $$override[1]) if $override; 1321 return 1; 1322 # 1323 # .a libraries 1324 # 1325 } elsif ($buff =~ /^!<arch>\x0a/) { 1326 $et->SetFileType('Static library', undef, 'A'); 1327 return 1 if $fast3; 1328 my $pos = 8; # current file position 1329 my $max = 10; # maximum number of archive files to check 1330 # read into list of ar structures (each 60 bytes long): 1331 while ($max-- > 0) { 1332 # seek to start of the ar structure and read it 1333 $raf->Seek($pos, 0) and $raf->Read($buff, 60) == 60 or last; 1334 substr($buff, 58, 2) eq "`\n" or $et->Warn('Invalid archive header'), last; 1335 unless ($tagTablePtr) { 1336 # extract some information from first file in archive 1337 $tagTablePtr = GetTagTable('Image::ExifTool::EXE::AR'); 1338 %dirInfo = ( 1339 DataPt => \$buff, 1340 DataPos => $pos, 1341 ); 1342 $et->ProcessDirectory(\%dirInfo, $tagTablePtr); 1343 } 1344 my $name = substr($buff, 0, 16); 1345 if ($name =~ m{^#1/(\d+) *$}) { # check for extended archive (BSD variant) 1346 my $len = $1; 1347 $len > 256 and $et->Warn('Invalid extended archive name length'), last; 1348 # (we read the name here just to move the file pointer) 1349 $raf->Read($name, $len) == $len or $et->Warn('Error reading archive name'), last; 1350 } 1351 my $arSize = substr($buff, 48, 10); 1352 $arSize =~ s/^(\d+).*/$1/s or last; # make sure archive size is a number 1353 $raf->Read($buff, 28) == 28 or last; # read (possible) Mach header 1354 ExtractMachTags($et, \$buff) and last; # try to extract tags 1355 $pos += 60 + $arSize; # step to next entry 1356 ++$pos if $pos & 0x01; # padded to an even byte 1357 } 1118 1358 return 1; 1119 1359 # … … 1121 1361 # 1122 1362 } elsif ($buff =~ m{^#!\s*/\S*bin/(\w+)}) { 1123 $type = "$1 script"; 1124 # 1125 # .a libraries 1126 # 1127 } elsif ($buff =~ /^!<arch>\x0a/) { 1128 $type = 'Static library', 1363 my $prog = $1; 1364 $prog = $1 if $prog eq 'env' and $buff =~ /\b(perl|python|ruby|php)\b/; 1365 $type = "$prog script"; 1366 $mime = "text/x-$prog"; 1367 $ext = { 1368 perl => 'pl', 1369 python => 'py', 1370 ruby => 'rb', 1371 php => 'php', 1372 }->{$prog}; 1373 # use '.sh' for extension of all shell scripts 1374 $ext = $prog =~ /sh$/ ? 'sh' : '' unless defined $ext; 1129 1375 } 1130 1376 return 0 unless $type; 1131 $e xifTool->SetFileType($type);1377 $et->SetFileType($type, $mime, $ext); 1132 1378 return 1; 1133 1379 } … … 1153 1399 =head1 AUTHOR 1154 1400 1155 Copyright 2003-20 11, Phil Harvey (phil at owl.phy.queensu.ca)1401 Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com) 1156 1402 1157 1403 This library is free software; you can redistribute it and/or modify it
Note:
See TracChangeset
for help on using the changeset viewer.