├── .gitattributes ├── .gitignore ├── FileSignatures.sln ├── FileSignatures.snk ├── LICENCE ├── README.md ├── examples ├── ConsoleApplication │ ├── InspectFormat.csproj │ ├── InspectFormat.sln │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── README.md └── WebApplication │ ├── Controllers │ └── HomeController.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── README.md │ ├── Startup.cs │ ├── UploadResultModel.cs │ ├── Views │ ├── Home │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ └── _Layout.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml │ ├── WebApplication.csproj │ ├── WebApplication.sln │ ├── appsettings.Development.json │ └── appsettings.json ├── src └── FileSignatures │ ├── FileFormat.cs │ ├── FileFormatInspector.cs │ ├── FileFormatLocator.cs │ ├── FileSignatures.csproj │ ├── Formats │ ├── AdobePdf.cs │ ├── Amr.cs │ ├── Bmp.cs │ ├── CompoundFileBinary.cs │ ├── Dicom.cs │ ├── Excel.cs │ ├── ExcelBinary.cs │ ├── ExcelLegacy.cs │ ├── ExcelWithMacros.cs │ ├── Executable.cs │ ├── Flac.cs │ ├── Flash.cs │ ├── Gif.cs │ ├── Gzip.cs │ ├── Icon.cs │ ├── Image.cs │ ├── Isobmff.cs │ ├── Jfif.cs │ ├── Jpeg.cs │ ├── JpegExif.cs │ ├── M4A.cs │ ├── M4V.cs │ ├── MP4.cs │ ├── MP4V1.cs │ ├── Midi.cs │ ├── Mpeg3.cs │ ├── OfficeOpenXml.cs │ ├── Ogg.cs │ ├── OpenDocument.cs │ ├── OpenDocumentPresentation.cs │ ├── OpenDocumentSpreadsheet.cs │ ├── OpenDocumentText.cs │ ├── OutlookMessage.cs │ ├── Pdf.cs │ ├── Photoshop.cs │ ├── Png.cs │ ├── Powerpoint.cs │ ├── PowerpointLegacy.cs │ ├── PowerpointWithMacros.cs │ ├── Quicktime.cs │ ├── Rar.cs │ ├── RichTextFormat.cs │ ├── SevenZip.cs │ ├── Spiff.cs │ ├── Swf.cs │ ├── Tar.cs │ ├── ThreeGpp.cs │ ├── Tiff.cs │ ├── Vcard.cs │ ├── Visio.cs │ ├── VisioLegacy.cs │ ├── Webp.cs │ ├── Wmf.cs │ ├── Word.cs │ ├── WordLegacy.cs │ ├── WordWithMacros.cs │ ├── Xps.cs │ └── Zip.cs │ ├── IFileFormatInspector.cs │ ├── IFileFormatReader.cs │ └── Properties │ └── AssemblyInfo.cs └── test └── FileSignatures.Tests ├── Benchmarks ├── FileFormatInspectorBenchmarks.cs └── Program.cs ├── FileFormatInspectorTests.cs ├── FileFormatLocatorTests.cs ├── FileFormatTests.cs ├── FileSignatures.Tests.csproj ├── Formats └── OfficeOpenXmlTests.cs ├── FunctionalTests.cs ├── Properties └── AssemblyInfo.cs ├── Samples ├── adobe.pdf ├── dragndrop.msg ├── malicious.pdf ├── nonstandard.docx ├── saved.msg ├── test-v1.mp4 ├── test.3gp ├── test.7z ├── test.amr ├── test.bmp ├── test.dcm ├── test.doc ├── test.docm ├── test.docx ├── test.exe ├── test.exif ├── test.flac ├── test.flv ├── test.gif ├── test.gz ├── test.ico ├── test.jfif ├── test.jpg ├── test.m4a ├── test.m4v ├── test.mid ├── test.mov ├── test.mp3 ├── test.mp4 ├── test.odp ├── test.ods ├── test.odt ├── test.ogg ├── test.pdf ├── test.png ├── test.ppt ├── test.pptm ├── test.pptx ├── test.psd ├── test.rar ├── test.rtf ├── test.spiff ├── test.swf ├── test.tar ├── test.tif ├── test.unknown ├── test.vcf ├── test.vsd ├── test.vsdx ├── test.webp ├── test.wmf ├── test.xls ├── test.xlsb ├── test.xlsm ├── test.xlsx ├── test.xps ├── test.zip └── test2.ppt └── xunit.runner.json /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Visual Studio code 28 | .vscode/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # DNX 46 | project.lock.json 47 | artifacts/ 48 | 49 | *_i.c 50 | *_p.c 51 | *_i.h 52 | *.ilk 53 | *.meta 54 | *.obj 55 | *.pch 56 | *.pdb 57 | *.pgc 58 | *.pgd 59 | *.rsp 60 | *.sbr 61 | *.tlb 62 | *.tli 63 | *.tlh 64 | *.tmp 65 | *.tmp_proj 66 | *.log 67 | *.vspscc 68 | *.vssscc 69 | .builds 70 | *.pidb 71 | *.svclog 72 | *.scc 73 | 74 | # Chutzpah Test files 75 | _Chutzpah* 76 | 77 | # Visual C++ cache files 78 | ipch/ 79 | *.aps 80 | *.ncb 81 | *.opendb 82 | *.opensdf 83 | *.sdf 84 | *.cachefile 85 | *.VC.db 86 | *.VC.VC.opendb 87 | 88 | # Visual Studio profiler 89 | *.psess 90 | *.vsp 91 | *.vspx 92 | *.sap 93 | 94 | # TFS 2012 Local Workspace 95 | $tf/ 96 | 97 | # Guidance Automation Toolkit 98 | *.gpState 99 | 100 | # ReSharper is a .NET coding add-in 101 | _ReSharper*/ 102 | *.[Rr]e[Ss]harper 103 | *.DotSettings.user 104 | 105 | # JustCode is a .NET coding add-in 106 | .JustCode 107 | 108 | # TeamCity is a build add-in 109 | _TeamCity* 110 | 111 | # DotCover is a Code Coverage Tool 112 | *.dotCover 113 | 114 | # NCrunch 115 | _NCrunch_* 116 | .*crunch*.local.xml 117 | nCrunchTemp_* 118 | 119 | # MightyMoose 120 | *.mm.* 121 | AutoTest.Net/ 122 | 123 | # Web workbench (sass) 124 | .sass-cache/ 125 | 126 | # Installshield output folder 127 | [Ee]xpress/ 128 | 129 | # DocProject is a documentation generator add-in 130 | DocProject/buildhelp/ 131 | DocProject/Help/*.HxT 132 | DocProject/Help/*.HxC 133 | DocProject/Help/*.hhc 134 | DocProject/Help/*.hhk 135 | DocProject/Help/*.hhp 136 | DocProject/Help/Html2 137 | DocProject/Help/html 138 | 139 | # Click-Once directory 140 | publish/ 141 | 142 | # Publish Web Output 143 | *.[Pp]ublish.xml 144 | *.azurePubxml 145 | # TODO: Comment the next line if you want to checkin your web deploy settings 146 | # but database connection strings (with potential passwords) will be unencrypted 147 | *.pubxml 148 | *.publishproj 149 | 150 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 151 | # checkin your Azure Web App publish settings, but sensitive information contained 152 | # in these scripts will be unencrypted 153 | PublishScripts/ 154 | 155 | # NuGet Packages 156 | *.nupkg 157 | # The packages folder can be ignored because of Package Restore 158 | **/packages/* 159 | # except build/, which is used as an MSBuild target. 160 | !**/packages/build/ 161 | # Uncomment if necessary however generally it will be regenerated when needed 162 | #!**/packages/repositories.config 163 | # NuGet v3's project.json files produces more ignoreable files 164 | *.nuget.props 165 | *.nuget.targets 166 | 167 | # Microsoft Azure Build Output 168 | csx/ 169 | *.build.csdef 170 | 171 | # Microsoft Azure Emulator 172 | ecf/ 173 | rcf/ 174 | 175 | # Windows Store app package directories and files 176 | AppPackages/ 177 | BundleArtifacts/ 178 | Package.StoreAssociation.xml 179 | _pkginfo.txt 180 | 181 | # Visual Studio cache files 182 | # files ending in .cache can be ignored 183 | *.[Cc]ache 184 | # but keep track of directories ending in .cache 185 | !*.[Cc]ache/ 186 | 187 | # Others 188 | ClientBin/ 189 | ~$* 190 | *~ 191 | *.dbmdl 192 | *.dbproj.schemaview 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # Benchmark Artifacts 257 | BenchmarkDotNet.Artifacts/ 258 | 259 | .DS_Store 260 | -------------------------------------------------------------------------------- /FileSignatures.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29424.173 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A34CAB26-B589-4531-884B-E50BF89CCF2D}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D9653CFC-5C1F-4751-BE1E-B85EAAF73203}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileSignatures", "src\FileSignatures\FileSignatures.csproj", "{52D4F79F-BB2C-46E9-9D27-59FF8DC9BD81}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileSignatures.Tests", "test\FileSignatures.Tests\FileSignatures.Tests.csproj", "{5FE9AF07-5928-482E-9917-285956E7731C}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {52D4F79F-BB2C-46E9-9D27-59FF8DC9BD81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {52D4F79F-BB2C-46E9-9D27-59FF8DC9BD81}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {52D4F79F-BB2C-46E9-9D27-59FF8DC9BD81}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {52D4F79F-BB2C-46E9-9D27-59FF8DC9BD81}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {5FE9AF07-5928-482E-9917-285956E7731C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {5FE9AF07-5928-482E-9917-285956E7731C}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {5FE9AF07-5928-482E-9917-285956E7731C}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {5FE9AF07-5928-482E-9917-285956E7731C}.Release|Any CPU.Build.0 = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | GlobalSection(NestedProjects) = preSolution 33 | {52D4F79F-BB2C-46E9-9D27-59FF8DC9BD81} = {A34CAB26-B589-4531-884B-E50BF89CCF2D} 34 | {5FE9AF07-5928-482E-9917-285956E7731C} = {D9653CFC-5C1F-4751-BE1E-B85EAAF73203} 35 | EndGlobalSection 36 | GlobalSection(ExtensibilityGlobals) = postSolution 37 | SolutionGuid = {03AC7B1D-D40C-4953-8277-2D4EC5AF7E36} 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /FileSignatures.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/FileSignatures.snk -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Neil Harvey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FileSignatures 2 | 3 | [![nuget package](https://badge.fury.io/nu/FileSignatures.svg)](https://www.nuget.org/packages/FileSignatures) 4 | 5 | A small library for detecting the type of a file based on header signature (also known as magic number) rather than file extension. It is designed with extensibility in mind, so that recognised formats can be added easily. 6 | 7 | ## How do I install it? 8 | 9 | FileSignatures is available on NuGet, so can be installed via the Package Manager: 10 | 11 | ``` 12 | Install-Package FileSignatures 13 | ``` 14 | 15 | ## How do I use it? 16 | 17 | Create an instance of the FileFormatInspector class, then pass it a stream to your file: 18 | 19 | ```cs 20 | var inspector = new FileFormatInspector(); 21 | var format = inspector.DetermineFileFormat(stream); 22 | ``` 23 | 24 | This will return a FileFormat instance which contains the signature and media type of the recognised format, 25 | or null if a matching format could not be determined. 26 | 27 | ## How do I register it with a dependency injection container? 28 | 29 | You can either register an instance calling the empty constructor which will register all formats in the FileSignatures assembly: 30 | 31 | ```cs 32 | services.AddSingleton(new FileFormatInspector()); 33 | ``` 34 | 35 | Or use `FileFormatLocator` to scan for the formats you are interested in then pass that to the constructor of `FileFormatInspector` and register that instance: 36 | 37 | ```cs 38 | var recognised = FileFormatLocator.GetFormats().OfType(); 39 | var inspector = new FileFormatInspector(recognised); 40 | services.AddSingleton(inspector); 41 | ``` 42 | 43 | In this example, only formats which derive from `Image` (jpg, tiff, bmp, etc.) will be detected. Anything else will be ignored. 44 | 45 | ## How do I check for a type of file? 46 | 47 | Because the formats are defined as a type hierarchy, you can either check for a specific type if you want 48 | to work with a particular format, or the base type if you are interested in multiple formats. 49 | 50 | ```cs 51 | var format = inspector.DetermineFileFormat(stream); 52 | 53 | if(format is Pdf) { 54 | // Just matches Pdf 55 | } 56 | 57 | if(format is OfficeOpenXml) { 58 | // Matches Word, Excel, Powerpoint 59 | } 60 | 61 | if(format is Image) { 62 | // Matches any image format 63 | } 64 | 65 | ``` 66 | 67 | See the examples for a sample [web application](https://github.com/neilharvey/FileSignatures/tree/master/examples/WebApplication) and a [console application](https://github.com/neilharvey/FileSignatures/tree/master/examples/ConsoleApplication) which demonstrate how to filter uploads by a particular format and retrieve the signature details for a file. 68 | 69 | ## What formats are recognised? 70 | 71 | Currently, the following formats are built-in: 72 | 73 | | Name | Media-Type | Extension 74 | |----------------------------|---------------------------------------------------------------------------|-------- 75 | | 3GPP | video/3gpp | .3gp 76 | | Bitmap | image/bmp | .bmp 77 | | Excel | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | .xlsx 78 | | Excel 97-2003 | application/vnd.ms-excel | .xls 79 | | Exe (Windows) | application/octet-stream | .exe 80 | | GIF | image/gif | .gif 81 | | JPEG | image/jpeg | .jpg 82 | | MP4 | video/mp4 | .mp4 83 | | Open Document Presentation | application/vnd.oasis.opendocument.presentationn | .odp 84 | | Open Document Spreadhseet | application/vnd.oasis.opendocument.spreadsheet | .ods 85 | | Open Document Text | application/vnd.oasis.opendocument.text | .odt 86 | | Outlook Message | application/vnd.ms-outlook | .msg 87 | | PDF | application/pdf | .pdf 88 | | PNG | image/png | .png 89 | | PowerPoint | application/vnd.openxmlformats-officedocument.presentationml.presentation | .pptx 90 | | Powerpoint 97-2003 | application/vnd.ms-powerpoint | .ppt 91 | | QuickTime | video/quicktime | .mov 92 | | Rich Text Format | application/rtf | .rtf 93 | | TIFF | image/tiff | .tif 94 | | Visio | application/vnd.visio | .vsdx 95 | | Visio 97-2003 | application/vnd.visio | .vsd 96 | | Webp | image/webp | .webp 97 | | Word | application/vnd.openxmlformats-officedocument.wordprocessingml.document | .docx 98 | | Word 97-2003 | application/msword | .doc 99 | | Xps | application/vnd.ms-xpsdocument | .xps 100 | | Zip | application/zip | .zip 101 | 102 | ## How do I add additional formats? 103 | 104 | Create a new class (or many classes) which inherit from `FileFormat` to implement a custom format. Next, pass a collection of recognised formats to the constructor of `FileFormatInspector`, being sure to include your custom format. 105 | 106 | The `FileFormatLocator` class can be used to load all custom formats located within an assembly: 107 | 108 | ```cs 109 | var assembly = typeof(CustomFileFormat).GetTypeInfo().Assembly; 110 | 111 | // Just the formats defined in the assembly containing CustomFileFormat 112 | var customFormats = FileFormatLocator.GetFormats(assembly); 113 | 114 | // Formats defined in the assembly and all the defaults 115 | var allFormats = FileFormatLocator.GetFormats(assembly, true); 116 | ``` 117 | 118 | Using this method, you can continue to create custom formats and they will automatically be included into the recognised formats without any additional configuration. 119 | 120 | ## What is the licence? 121 | 122 | This project is licensed under the [MIT license](LICENSE). 123 | -------------------------------------------------------------------------------- /examples/ConsoleApplication/InspectFormat.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/ConsoleApplication/InspectFormat.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2046 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InspectFormat", "InspectFormat.csproj", "{F15D206A-AB58-49A0-BAE8-85B8DE7362B8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {F15D206A-AB58-49A0-BAE8-85B8DE7362B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {F15D206A-AB58-49A0-BAE8-85B8DE7362B8}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {F15D206A-AB58-49A0-BAE8-85B8DE7362B8}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {F15D206A-AB58-49A0-BAE8-85B8DE7362B8}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {B34BECAE-570A-4103-96FC-FAC4A18D7C0A} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /examples/ConsoleApplication/Program.cs: -------------------------------------------------------------------------------- 1 | using FileSignatures; 2 | using FileSignatures.Formats; 3 | using System; 4 | using System.IO; 5 | using System.Linq; 6 | 7 | namespace InspectFormat 8 | { 9 | public class Program 10 | { 11 | public static void Main(string[] args) 12 | { 13 | Console.WriteLine(); 14 | 15 | if (args.Length != 1) 16 | { 17 | Console.WriteLine("Usage: dotnet run "); 18 | return; 19 | } 20 | 21 | var fileInfo = new FileInfo(args[0]); 22 | if (!fileInfo.Exists) 23 | { 24 | Console.WriteLine(args[0] + " does not exist."); 25 | return; 26 | } 27 | 28 | var inspector = new FileFormatInspector(); 29 | using (var stream = fileInfo.OpenRead()) 30 | { 31 | var format = inspector.DetermineFileFormat(stream); 32 | 33 | if (format == null) 34 | { 35 | Console.WriteLine("File format was not recognised."); 36 | } 37 | else 38 | { 39 | Console.WriteLine("Media Type : " + format.MediaType); 40 | Console.WriteLine("Signature : " + BitConverter.ToString(format.Signature.ToArray())); 41 | Console.WriteLine("Extension : " + format.Extension); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/ConsoleApplication/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTrademark("")] 9 | 10 | // Setting ComVisible to false makes the types in this assembly not visible 11 | // to COM components. If you need to access a type in this assembly from 12 | // COM, set the ComVisible attribute to true on that type. 13 | [assembly: ComVisible(false)] 14 | 15 | // The following GUID is for the ID of the typelib if this project is exposed to COM 16 | [assembly: Guid("30d5e715-8e7c-4996-8cca-9215038ad903")] 17 | -------------------------------------------------------------------------------- /examples/ConsoleApplication/README.md: -------------------------------------------------------------------------------- 1 | Console Application Example 2 | =========================== 3 | 4 | This example demonstrates how to examine the format of a file on the local machine via a console. 5 | 6 | Usage 7 | ----- 8 | 9 | From a command prompt within the ConsoleApplication directory, run the command: 10 | 11 | ``` 12 | dotnet run /path/to/file 13 | ``` 14 | 15 | This will examine the file and return the media type and description if recognised. For example, if the file was identified as a JPEG then the following would be returned: 16 | 17 | ``` 18 | Media Type : image/jpeg 19 | Signature : FF-D8-FF-E0 20 | Extension : jpg 21 | ``` -------------------------------------------------------------------------------- /examples/WebApplication/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using FileSignatures; 2 | using FileSignatures.Formats; 3 | using Microsoft.AspNetCore.Http; 4 | using Microsoft.AspNetCore.Mvc; 5 | using System.IO; 6 | 7 | namespace WebApplication.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | private readonly IFileFormatInspector fileFormatInspector; 12 | 13 | public HomeController(IFileFormatInspector fileFormatInspector) 14 | { 15 | this.fileFormatInspector = fileFormatInspector; 16 | } 17 | 18 | [HttpGet] 19 | public IActionResult Index(UploadResultModel model) 20 | { 21 | return View(model); 22 | } 23 | 24 | [HttpPost] 25 | public IActionResult Index(IFormFile file) 26 | { 27 | FileFormat format; 28 | 29 | using(var stream = file.OpenReadStream()) 30 | { 31 | format = fileFormatInspector.DetermineFileFormat(stream); 32 | } 33 | 34 | var model = new UploadResultModel() 35 | { 36 | Accepted = format is Image, 37 | MediaType = format?.MediaType, 38 | FileName = Path.GetFileName(file.FileName) 39 | }; 40 | 41 | return RedirectToAction(nameof(Index), model); 42 | } 43 | 44 | public IActionResult Error() 45 | { 46 | return View(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/WebApplication/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace WebApplication 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => 22 | { 23 | webBuilder.UseStartup(); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/WebApplication/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:50210", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "WebApplication": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/WebApplication/README.md: -------------------------------------------------------------------------------- 1 | Web Application Example 2 | =========================== 3 | 4 | This example demonstrates how to examine the format of a file which has been uploaded to an ASP.NET Core web application. 5 | 6 | Usage 7 | ----- 8 | 9 | Run the web application and upload a file to the index page. Image files will be accepted, and non-image files will be rejected irrespective of the extension or content-type headers provided by the browser. 10 | 11 | Explanation 12 | ----------- 13 | 14 | A concrete ```FileFormatInspector``` which recognises image formats is registered in the Startup class: 15 | 16 | ```cs 17 | var recognised = FileFormatLocator.GetFormats().OfType(); 18 | var inspector = new FileFormatInspector(recognised); 19 | services.AddSingleton(inspector); 20 | ``` 21 | 22 | This can then be injected into the constructor of the HomeController: 23 | 24 | ```cs 25 | public HomeController(IFileFormatInspector fileFormatInspector) 26 | { 27 | this.fileFormatInspector = fileFormatInspector; 28 | } 29 | ``` 30 | Then we can use this after a file has been posted back to verify that the uploaded file is an image: 31 | 32 | ```cs 33 | [HttpPost] 34 | public IActionResult Index(IFormFile file) 35 | { 36 | FileFormat format; 37 | 38 | using(var stream = file.OpenReadStream()) 39 | { 40 | format = fileFormatInspector.DetermineFileFormat(stream); 41 | } 42 | 43 | var model = new UploadResultModel() 44 | { 45 | Accepted = format is Image, 46 | MediaType = format?.MediaType, 47 | FileName = Path.GetFileName(file.FileName) 48 | }; 49 | 50 | return RedirectToAction(nameof(Index), model); 51 | } 52 | ``` 53 | 54 | This gives us a more reliable way of checking the content of an uploaded file than examining ```IFormFile.FileName``` or ```IFormFile.ContentType``` which are both under the control of the client. -------------------------------------------------------------------------------- /examples/WebApplication/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using FileSignatures; 6 | using FileSignatures.Formats; 7 | using Microsoft.AspNetCore.Builder; 8 | using Microsoft.AspNetCore.Hosting; 9 | using Microsoft.AspNetCore.Http; 10 | using Microsoft.Extensions.DependencyInjection; 11 | using Microsoft.Extensions.Hosting; 12 | 13 | namespace WebApplication 14 | { 15 | public class Startup 16 | { 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | services.AddMvc(); 20 | 21 | // For this example we will only recognise image-based formats. 22 | var recognised = FileFormatLocator.GetFormats().OfType(); 23 | var inspector = new FileFormatInspector(recognised); 24 | services.AddSingleton(inspector); 25 | } 26 | 27 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 28 | { 29 | if (env.IsDevelopment()) 30 | { 31 | app.UseDeveloperExceptionPage(); 32 | } 33 | 34 | app.UseRouting(); 35 | app.UseEndpoints(x => 36 | { 37 | x.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}"); 38 | }); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/WebApplication/UploadResultModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace WebApplication 7 | { 8 | public class UploadResultModel 9 | { 10 | public bool? Accepted { get; set; } 11 | 12 | public string FileName { get; set; } 13 | 14 | public string MediaType { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/WebApplication/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model UploadResultModel 2 | @{ 3 | ViewData["Title"] = "Home Page"; 4 | } 5 | 6 |

File Upload Example

7 | 8 |

9 | Select a file to upload to the web application. Image files will be accepted, and non-image files will be rejected. 10 |

11 | 12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | 21 |
22 | 23 |
24 | 25 | @if (Model.Accepted.HasValue) 26 | { 27 | if (Model.Accepted.Value) 28 | { 29 |
30 | The file @Model.FileName is an image with format @Model.MediaType. 31 |
32 | } 33 | else 34 | { 35 |
36 | The file @Model.FileName is not an image file. 37 |
38 | } 39 | } -------------------------------------------------------------------------------- /examples/WebApplication/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Error"; 3 | } 4 | 5 |

Error.

6 |

An error occurred while processing your request.

7 | 8 |

Development Mode

9 |

10 | Swapping to Development environment will display more detailed information about the error that occurred. 11 |

12 |

13 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 14 |

15 | -------------------------------------------------------------------------------- /examples/WebApplication/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | File Upload Example 8 | 9 | 10 |
11 | @RenderBody() 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/WebApplication/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using WebApplication 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /examples/WebApplication/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /examples/WebApplication/WebApplication.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/WebApplication/WebApplication.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29503.13 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApplication", "WebApplication.csproj", "{CED2B627-5F23-4736-924A-728A43667430}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {CED2B627-5F23-4736-924A-728A43667430}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {CED2B627-5F23-4736-924A-728A43667430}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {CED2B627-5F23-4736-924A-728A43667430}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {CED2B627-5F23-4736-924A-728A43667430}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {0F4645A2-9AFF-445C-A57B-B6A0ABEF7D3E} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /examples/WebApplication/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/WebApplication/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /src/FileSignatures/FileFormat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace FileSignatures 7 | { 8 | /// 9 | /// Specifies the format of a file. 10 | /// 11 | public abstract class FileFormat : IEquatable 12 | { 13 | /// 14 | /// Initializes a new instance of the FileFormat class which has the specified signature and media type. 15 | /// 16 | /// The header signature of the format. 17 | /// The media type of the format. 18 | /// The appropriate file extension for the format. 19 | protected FileFormat(byte[] signature, string mediaType, string extension) 20 | : this(signature, signature == null ? 0 : signature.Length, mediaType, extension, 0) 21 | { 22 | } 23 | 24 | /// 25 | /// Initializes a new instance of the FileFormat class which has the specified signature and media type. 26 | /// 27 | /// The header signature of the format. 28 | /// The media type of the format. 29 | /// The appropriate file extension for the format. 30 | /// The offset at which the signature is located. 31 | protected FileFormat(byte[] signature, string mediaType, string extension, int offset) 32 | : this(signature, signature == null ? offset : signature.Length + offset, mediaType, extension, offset) 33 | { 34 | } 35 | 36 | /// 37 | /// Initializes a new instance of the FileFormat class which has the specified signature and media type. 38 | /// 39 | /// The header signature of the format. 40 | /// The number of bytes required to determine the format. 41 | /// The media type of the format. 42 | /// The appropriate file extension for the format. 43 | protected FileFormat(byte[] signature, int headerLength, string mediaType, string extension) 44 | : this(signature, headerLength, mediaType, extension, 0) 45 | { 46 | } 47 | 48 | /// 49 | /// Initializes a new instance of the FileFormat class which has the specified signature and media type. 50 | /// 51 | /// The header signature of the format. 52 | /// The number of bytes required to determine the format. 53 | /// The media type of the format. 54 | /// The appropriate file extension for the format. 55 | /// The offset at which the signature is located. 56 | protected FileFormat(byte[] signature, int headerLength, string mediaType, string extension, int offset) 57 | { 58 | if (signature == null) 59 | { 60 | throw new ArgumentNullException(nameof(signature)); 61 | } 62 | 63 | if (string.IsNullOrEmpty(mediaType)) 64 | { 65 | throw new ArgumentNullException(nameof(mediaType)); 66 | } 67 | 68 | Signature = new ReadOnlyCollection(signature); 69 | HeaderLength = headerLength; 70 | Offset = offset; 71 | Extension = extension; 72 | MediaType = mediaType; 73 | } 74 | 75 | /// 76 | /// Gets a byte signature which can be used to identify the file format. 77 | /// 78 | public ReadOnlyCollection Signature { get; } 79 | 80 | /// 81 | /// Gets the number of bytes required to determine the format. 82 | /// A value of indicates that the entire file is required to determine the format. 83 | /// 84 | public int HeaderLength { get; } 85 | 86 | /// 87 | /// Gets the appropriate file extension for the format. 88 | /// 89 | public string Extension { get; } 90 | 91 | /// 92 | /// Gets the media type identifier for the format. 93 | /// 94 | public string MediaType { get; } 95 | 96 | /// 97 | /// Gets the offset in the file at which the signature is located. 98 | /// 99 | public int Offset { get; } 100 | 101 | /// 102 | /// Returns a value indicating whether the format matches a file header. 103 | /// 104 | /// The stream to check. 105 | public virtual bool IsMatch(Stream stream) 106 | { 107 | if (stream == null || (stream.Length < HeaderLength && HeaderLength < int.MaxValue) || Offset > stream.Length) 108 | { 109 | return false; 110 | } 111 | 112 | stream.Position = Offset; 113 | 114 | for (int i = 0; i < Signature.Count; i++) 115 | { 116 | var b = stream.ReadByte(); 117 | if (b != Signature[i]) 118 | { 119 | return false; 120 | } 121 | } 122 | 123 | return true; 124 | } 125 | 126 | /// 127 | /// Determines whether the object is equal to this FileFormat. 128 | /// 129 | /// The object to compare. 130 | public override bool Equals(object obj) 131 | { 132 | return Equals(obj as FileFormat); 133 | } 134 | 135 | /// 136 | /// Determines whether the format is equal to this FileFormat. 137 | /// 138 | /// The format to compare. 139 | public bool Equals(FileFormat? fileFormat) 140 | { 141 | if (fileFormat == null) 142 | { 143 | return false; 144 | } 145 | 146 | if (ReferenceEquals(this, fileFormat)) 147 | { 148 | return true; 149 | } 150 | 151 | if (GetType() != fileFormat.GetType()) 152 | { 153 | return false; 154 | } 155 | 156 | return fileFormat.Signature.SequenceEqual(Signature); 157 | } 158 | 159 | /// 160 | /// Serves as the default hash function. 161 | /// 162 | public override int GetHashCode() 163 | { 164 | unchecked 165 | { 166 | if (Signature == null) 167 | { 168 | return 0; 169 | } 170 | 171 | var hash = 17; 172 | foreach (var element in Signature) 173 | { 174 | hash = hash * 31 + element.GetHashCode(); 175 | } 176 | 177 | return hash; 178 | } 179 | } 180 | 181 | /// 182 | /// Returns a string that represents this format. 183 | /// 184 | public override string ToString() 185 | { 186 | return MediaType; 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/FileSignatures/FileFormatInspector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace FileSignatures 7 | { 8 | /// 9 | /// Provides a mechanism to determine the format of a file. 10 | /// 11 | public class FileFormatInspector : IFileFormatInspector 12 | { 13 | private readonly IEnumerable _formats; 14 | 15 | /// 16 | /// Initialises a new FileFormatInspector instance which can determine the default file formats. 17 | /// 18 | public FileFormatInspector() : this(FileFormatLocator.GetFormats()) 19 | { 20 | } 21 | 22 | /// 23 | /// Initialises a new FileFormatInspector instance which can determine the specified file formats. 24 | /// 25 | /// The formats which are recognised. 26 | public FileFormatInspector(IEnumerable formats) 27 | { 28 | _formats = formats ?? throw new ArgumentNullException(nameof(formats)); 29 | } 30 | 31 | /// 32 | /// Determines the format of a file. 33 | /// 34 | /// A stream containing the file content. 35 | /// An instance of a matching file format, or null if the format could not be determined. 36 | public FileFormat? DetermineFileFormat(Stream stream) 37 | { 38 | if (stream == null) 39 | { 40 | throw new ArgumentNullException(nameof(stream)); 41 | } 42 | 43 | if (!stream.CanSeek) 44 | { 45 | throw new NotSupportedException("The passed stream object is not seekable."); 46 | } 47 | 48 | if (stream.Length == 0) 49 | { 50 | return null; 51 | } 52 | 53 | var matches = FindMatchingFormats(stream); 54 | 55 | if (matches.Count > 1) 56 | { 57 | RemoveBaseFormats(matches); 58 | } 59 | 60 | if (matches.Count > 1) 61 | { 62 | return matches.OrderByDescending(m => m.HeaderLength).First(); 63 | } 64 | 65 | return matches.Count == 1 ? matches[0] : null; 66 | } 67 | 68 | private List FindMatchingFormats(Stream stream) 69 | { 70 | var candidates = _formats 71 | .OrderBy(t => t.HeaderLength) 72 | .ToList(); 73 | 74 | for (int i = 0; i < candidates.Count; i++) 75 | { 76 | if (!candidates[i].IsMatch(stream)) 77 | { 78 | candidates.RemoveAt(i); 79 | i--; 80 | } 81 | } 82 | 83 | if(candidates.Count > 1) 84 | { 85 | var readers = candidates.OfType().ToList(); 86 | 87 | if(readers.Any()) 88 | { 89 | using var file = readers[0].Read(stream); 90 | foreach(var reader in readers) 91 | { 92 | if (!reader.IsMatch(file)) 93 | { 94 | candidates.Remove((FileFormat)reader); 95 | } 96 | } 97 | } 98 | } 99 | 100 | stream.Position = 0; 101 | return candidates; 102 | } 103 | 104 | private static void RemoveBaseFormats(List candidates) 105 | { 106 | for (var i = 0; i < candidates.Count; i++) 107 | { 108 | for (var j = 0; j < candidates.Count; j++) 109 | { 110 | if (i != j && candidates[j].GetType().IsAssignableFrom(candidates[i].GetType())) 111 | { 112 | candidates.RemoveAt(j); 113 | i--; j--; 114 | } 115 | } 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/FileSignatures/FileFormatLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace FileSignatures 7 | { 8 | public static class FileFormatLocator 9 | { 10 | /// 11 | /// Returns all the default file formats. 12 | /// 13 | public static IEnumerable GetFormats() 14 | { 15 | return GetFormats(typeof(FileFormatLocator).GetTypeInfo().Assembly); 16 | } 17 | 18 | /// 19 | /// Returns all the concrete types found in the specified assembly. 20 | /// 21 | /// The assembly which contains the file format definitions. 22 | public static IEnumerable GetFormats(Assembly assembly) 23 | { 24 | if(assembly == null) 25 | { 26 | throw new ArgumentNullException(nameof(assembly)); 27 | } 28 | 29 | return assembly.GetTypes() 30 | .Where(t => typeof(FileFormat).IsAssignableFrom(t)) 31 | .Where(t => !t.GetTypeInfo().IsAbstract) 32 | .Where(t => t.GetConstructors().Any(c => c.GetParameters().Length == 0)) 33 | .Select(t => Activator.CreateInstance(t)) 34 | .OfType(); 35 | } 36 | 37 | /// 38 | /// Returns all the concrete types found in the specified assembly. 39 | /// 40 | /// The assembly which contains the file format definitions. 41 | /// Whether to include the default format definitions with the results from the external assembly. 42 | public static IEnumerable GetFormats(Assembly assembly, bool includeDefaults) 43 | { 44 | var formatsInAssembly = GetFormats(assembly); 45 | 46 | if (!includeDefaults) 47 | { 48 | return formatsInAssembly; 49 | } 50 | else 51 | { 52 | var formatsThisAssembly = GetFormats(); 53 | return formatsInAssembly.Union(formatsThisAssembly); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/FileSignatures/FileSignatures.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | A small library for detecting the type of a file based on header signature (also known as magic number) rather than file extension. 5 | Neil Harvey 6 | netstandard2.0 7 | FileSignatures 8 | FileSignatures 9 | File Format;Mime Type;Media Type;Header;Signature;Detection 10 | https://github.com/neilharvey/FileSignatures/releases 11 | https://github.com/neilharvey/FileSignatures/ 12 | 13 | false 14 | false 15 | false 16 | 5.2.0 17 | true 18 | MIT 19 | 5.2.0 20 | Latest 21 | enable 22 | 5.2.0 23 | True 24 | ..\..\FileSignatures.snk 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/AdobePdf.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace FileSignatures.Formats; 4 | 5 | public class AdobePdf : Pdf 6 | { 7 | private const byte VersionNumberPlaceholder = 0x00; 8 | 9 | public AdobePdf() : base([ 10 | 0x25, 0x21, 0x50, 0x53, 0x2D, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x2D, VersionNumberPlaceholder, 0x2E, 11 | VersionNumberPlaceholder, 0x20, 0x50, 0x44, 12 | 0x46, 0x2D, VersionNumberPlaceholder, 0x2E, VersionNumberPlaceholder 13 | ]) 14 | { 15 | } 16 | 17 | public override bool IsMatch(Stream stream) 18 | { 19 | if (stream == null || (stream.Length < HeaderLength && HeaderLength < int.MaxValue) || Offset > stream.Length) 20 | { 21 | return false; 22 | } 23 | 24 | stream.Position = Offset; 25 | 26 | for (var i = 0; i < Signature.Count; i++) 27 | { 28 | var b = stream.ReadByte(); 29 | if (!IsSignatureByte(b, i)) 30 | { 31 | return false; 32 | } 33 | } 34 | 35 | return true; 36 | } 37 | 38 | private bool IsSignatureByte(int value, int signatureIndex) 39 | { 40 | return IsVersionNumber(value, Signature[signatureIndex]) 41 | || value == Signature[signatureIndex]; 42 | } 43 | 44 | private static bool IsVersionNumber(int value, byte signatureByte) 45 | { 46 | var isNumber = value is >= 0x30 and <= 0x39; 47 | return signatureByte == VersionNumberPlaceholder && isNumber; 48 | } 49 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Amr.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of an Adaptive Multi-Rate ACELP (Algebraic Code Excited Linear Prediction) Codec file 5 | /// Commonly audio format with GSM cell phones. (See RFC 4867.) 6 | /// 7 | public class Amr : FileFormat 8 | { 9 | public Amr() : base(new byte[] { 0x23, 0x21, 0x41, 0x4D, 0x52 }, "audio/amr", "amr") { } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Bmp.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Bitmap image file. 5 | /// 6 | public class Bmp : Image 7 | { 8 | public Bmp() : base(new byte[] { 0x42, 0x4D }, "image/bmp", "bmp") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/CompoundFileBinary.cs: -------------------------------------------------------------------------------- 1 | using OpenMcdf; 2 | using System; 3 | using System.IO; 4 | 5 | namespace FileSignatures.Formats 6 | { 7 | /// 8 | /// Specifies the format of a Compound Binary File. 9 | /// 10 | /// 11 | /// See [MS-CFB] https://msdn.microsoft.com/en-us/library/dd942138.aspx, 12 | /// in particular 2.2 for a description of the CFB header specification. 13 | /// 14 | public abstract class CompoundFileBinary : FileFormat, IFileFormatReader 15 | { 16 | /// 17 | /// Initializes a new instance of the CompoundFileBinary class. 18 | /// 19 | /// The entry in the structured storage which is used to identify the format. 20 | /// The media type of the format. 21 | /// The appropriate extension for the format. 22 | public CompoundFileBinary(string storage, string mediaType, string extension) : base( 23 | new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 }, 24 | int.MaxValue, 25 | mediaType, 26 | extension) 27 | { 28 | if (string.IsNullOrEmpty(storage)) 29 | { 30 | throw new ArgumentNullException(nameof(storage)); 31 | } 32 | 33 | Storage = storage; 34 | } 35 | 36 | /// 37 | /// Gets the entry in the structured storage which is used to identify the format. 38 | /// 39 | public string Storage { get; } 40 | 41 | public bool IsMatch(IDisposable? file) 42 | { 43 | if(file is CompoundFile cf) 44 | { 45 | return cf.RootStorage.TryGetStream(Storage, out CFStream _); 46 | } 47 | else 48 | { 49 | return false; 50 | } 51 | } 52 | 53 | public IDisposable? Read(Stream stream) 54 | { 55 | try 56 | { 57 | return new CompoundFile(stream, CFSUpdateMode.ReadOnly, CFSConfiguration.LeaveOpen); 58 | } 59 | catch(EndOfStreamException) 60 | { 61 | return null; 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Dicom.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Dicom file. 5 | /// 6 | public class Dicom : FileFormat 7 | { 8 | public Dicom() : base(new byte[] { 0x44, 0x49, 0x43, 0x4D }, "application/dicom", "dcm", 128) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Excel.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of an Excel workbook. 5 | /// 6 | public class Excel : OfficeOpenXml 7 | { 8 | public Excel() : base("xl/workbook.xml", macroEnabled: false, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/ExcelBinary.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | /// 4 | /// An Excel workbook stored in binary format. 5 | /// 6 | /// 7 | /// See https://www.iana.org/assignments/media-types/application/vnd.ms-excel.sheet.binary.macroEnabled.12 8 | /// 9 | public class ExcelBinary : OfficeOpenXml 10 | { 11 | public ExcelBinary() : base("xl/workbook.bin", macroEnabled: false, "vnd.ms-excel.sheet.binary.macroEnabled.12", "xlsb") 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/ExcelLegacy.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of an Excel 97-2003 workbook. 5 | /// 6 | public class ExcelLegacy : CompoundFileBinary 7 | { 8 | public ExcelLegacy() : base("Workbook", "application/vnd.ms-excel", "xls") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/ExcelWithMacros.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of an Excel workbook that supports macros. 5 | /// 6 | public class ExcelWithMacros : OfficeOpenXml 7 | { 8 | public ExcelWithMacros() : base("xl/workbook.xml", macroEnabled: true, "application/vnd.ms-excel.sheet.macroEnabled.12", "xlsm") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Executable.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Windows executable file 5 | /// 6 | public class Executable : FileFormat 7 | { 8 | public Executable() : base(new byte[] { 0x4D, 0x5A }, "application/vnd.microsoft.portable-executable", "exe") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Flac.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | /// 4 | /// Specifies the format of a FLAC (Free Lossless Audio Codec) file. 5 | /// 6 | public class Flac : FileFormat 7 | { 8 | public Flac() : base([0x66, 0x4C, 0x61, 0x43], 4, "audio/flac", "flac") 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Flash.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | /// 4 | /// Specifies the format of a Flash Video file. 5 | /// 6 | public class Flash : FileFormat 7 | { 8 | public Flash() : base([0x46, 0x4C, 0x56], 3, "video/x-flv", "flv") 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Gif.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of Graphics Interchange Format (GIF) image. 5 | /// 6 | public class Gif : Image 7 | { 8 | public Gif() : base(new byte[] { 0x47, 0x49, 0x46, 0x38 }, "image/gif", "gif") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Gzip.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | /// 4 | /// Specifies the format of a gzip archive. 5 | /// 6 | /// 7 | /// See https://www.iana.org/assignments/media-types/application/gzip 8 | /// 9 | public class Gzip : FileFormat 10 | { 11 | public Gzip() : base([0x1F, 0x8B], 3, "application/gzip", "gz") 12 | { 13 | } 14 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Icon.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | /// 4 | /// Specifies the format of an icon file. 5 | /// 6 | /// 7 | public class Icon : Image 8 | { 9 | public Icon() : base([0x00, 0x00, 0x01, 0x00], "image/vnd.microsoft.icon", "ico") 10 | { 11 | } 12 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Image.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of an image. 5 | /// 6 | /// 7 | /// This is just a stub class to assist with selecting image formats. 8 | /// 9 | public abstract class Image : FileFormat 10 | { 11 | protected Image(byte[] signature, string mediaType, string extension) : base(signature, mediaType, extension) 12 | { 13 | } 14 | 15 | protected Image(byte[] signature, string mediaType, string extension, int offset) : base(signature, mediaType, extension, offset) 16 | { 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Isobmff.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace FileSignatures.Formats 4 | { 5 | /// 6 | /// Specifies the format of a ISO/IEC base media file format 7 | /// 8 | /// 9 | public abstract class Isobmff : FileFormat 10 | { 11 | private static readonly byte[] signature = { 0x66, 0x74, 0x79, 0x70 }; 12 | 13 | protected Isobmff(byte[] signature, string mediaType, string extension) 14 | : base(Isobmff.signature.Concat(signature).ToArray(), mediaType, extension, 4) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Jfif.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a JPEG File Interchange Fomat (JFIF) file. 5 | /// 6 | public class JpegJfif : Jpeg 7 | { 8 | public JpegJfif() : base(new byte[] { 0xFF, 0xE0 }) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Jpeg.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Joint Photographics Experts Group (JPEG) image. 5 | /// 6 | public class Jpeg : Image 7 | { 8 | private static readonly byte[] soi = new byte[] { 0xFF, 0xD8 }; 9 | private const string mediaType = "image/jpeg"; 10 | private const string extension = "jpg"; 11 | 12 | /// 13 | /// Initialises a new Jpeg format. 14 | /// 15 | public Jpeg() : base(soi, mediaType, extension) 16 | { 17 | } 18 | 19 | /// 20 | /// Initialises a new Jpeg format with the specified application marker. 21 | /// 22 | /// The 2-byte application marker used by the JPEG format. 23 | protected Jpeg(byte[] marker) : base(new byte[] { soi[0], soi[1], marker[0], marker[1] }, mediaType, extension) 24 | { 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/JpegExif.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a JPEG image containing EXIF data. 5 | /// 6 | public class JpegExif : Jpeg 7 | { 8 | public JpegExif() : base(new byte[] { 0xFF, 0xE1 }) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/M4A.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Apple Lossless Audio Codec file 5 | /// 6 | public class M4A : Isobmff 7 | { 8 | public M4A() : base(new byte[] { 0x4D, 0x34, 0x41, 0x20 }, "audio/mp4", "m4a") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/M4V.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of an MPEG-4 video file 5 | /// 6 | public class M4V : Isobmff 7 | { 8 | public M4V() : base(new byte[] { 0x4D, 0x34, 0x56, 0x20 }, "video/mp4", "m4v") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/MP4.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a MPEG-4 video 5 | /// 6 | public class MP4 : Isobmff 7 | { 8 | public MP4() : base(new byte[] { 0x6D, 0x70, 0x34, 0x32 }, "video/mp4", "mp4") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/MP4V1.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a MPEG-4 v1 file 5 | /// 6 | public class MP4V1 : Isobmff 7 | { 8 | public MP4V1() : base(new byte[] { 0x69, 0x73, 0x6F, 0x6D }, "video/mp4", "mp4") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Midi.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | /// 4 | /// Musical Instrument Digital Interface (MIDI) format. 5 | /// 6 | /// 7 | /// There does not appear to be an IANA registration for this format but audio/midi appears to be commonly used. 8 | /// 9 | public class Midi: FileFormat 10 | { 11 | public Midi() : base([0x4D, 0x54, 0x68, 0x64], "audio/midi", "mid") 12 | { 13 | } 14 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Mpeg3.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a MPEG-1 Audio Layer 3 (MP3) audio file 5 | /// 6 | public class Mpeg3 : FileFormat 7 | { 8 | public Mpeg3() : base(new byte[] { 0x49, 0x44, 0x33 }, "audio/mpeg", "mp3") { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/OfficeOpenXml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Compression; 4 | using System.Linq; 5 | 6 | namespace FileSignatures.Formats 7 | { 8 | /// 9 | /// Specifies the format of an Office Open XML file. 10 | /// 11 | public abstract class OfficeOpenXml : Zip, IFileFormatReader 12 | { 13 | /// 14 | /// Initializes a new instance of the OfficeOpenXmlFormat class which matches an archive containing a unique entry. 15 | /// 16 | /// The entry in the archive which is used to identify the format. 17 | /// Should this match office files with macros, or ones without macros 18 | /// The media type of the format. 19 | /// The appropriate extension for the format. 20 | protected OfficeOpenXml(string identifiableEntry, bool macroEnabled, string mediaType, string extension) : base(int.MaxValue, mediaType, extension) 21 | { 22 | if (string.IsNullOrEmpty(identifiableEntry)) 23 | { 24 | throw new ArgumentNullException(nameof(identifiableEntry)); 25 | } 26 | 27 | IdentifiableEntry = identifiableEntry; 28 | MacroEnabled = macroEnabled; 29 | } 30 | 31 | /// 32 | /// Gets the entry in the file which can be used to identify the format. 33 | /// 34 | /// 35 | public string IdentifiableEntry { get; } 36 | 37 | /// 38 | /// If this file exists in the zip file anywhere, it indicates that the office document supports macros 39 | /// 40 | public const string MacroIdentifiableEntry = "vbaProject.bin"; 41 | 42 | /// 43 | /// Should this match office files with macros, or ones without macros 44 | /// 45 | public bool MacroEnabled { get; } 46 | 47 | public bool IsMatch(IDisposable? file) 48 | { 49 | if (file is ZipArchive archive) 50 | { 51 | // Match archives which contain a non-standard version of the identifiable entry, e.g. document2.xml instead of document.xml. 52 | var index = Math.Max(0, IdentifiableEntry.LastIndexOf('.')); 53 | var fileName = IdentifiableEntry.Substring(0, IdentifiableEntry.Length - index); 54 | var extension = IdentifiableEntry.Substring(index); 55 | var matchesIdentifiableEntry = archive.Entries.Any(e => e.FullName.StartsWith(fileName, StringComparison.OrdinalIgnoreCase) 56 | && e.FullName.EndsWith(extension, StringComparison.OrdinalIgnoreCase)); 57 | 58 | var hasMacros = archive.Entries.Any(e => e.FullName.EndsWith(MacroIdentifiableEntry, StringComparison.OrdinalIgnoreCase)); 59 | 60 | return matchesIdentifiableEntry && MacroEnabled == hasMacros; 61 | } 62 | else 63 | { 64 | return false; 65 | } 66 | } 67 | 68 | public IDisposable? Read(Stream stream) 69 | { 70 | try 71 | { 72 | return new ZipArchive(stream, ZipArchiveMode.Read, true); 73 | } 74 | catch (InvalidDataException) 75 | { 76 | return null; 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Ogg.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of an Ogg Vorbis Codec compressed Multimedia file 5 | /// 6 | public class Ogg : FileFormat 7 | { 8 | public Ogg() : base(new byte[] { 0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "audio/ogg", "ogg") { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/OpenDocument.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.IO; 5 | using System.Text; 6 | 7 | namespace FileSignatures.Formats; 8 | 9 | /// 10 | /// Specifies the format of an OpenDocument file. 11 | /// 12 | public abstract class OpenDocument : Zip 13 | { 14 | private const int SubsignatureOffset = 30; 15 | 16 | protected OpenDocument(byte[] subsignature, string mediaType, string extension) : base(SubsignatureOffset + subsignature.Length, mediaType, extension) 17 | { 18 | Subsignature = new ReadOnlyCollection(subsignature); ; 19 | } 20 | 21 | /// 22 | /// Gets the subsignature of the OpenDocument file. 23 | /// This will be the media type in byte format e.g. 'mimetypeapplication/vnd.oasis.opendocument.presentation' 24 | /// 25 | public ReadOnlyCollection Subsignature { get; } 26 | 27 | public override bool IsMatch(Stream stream) 28 | { 29 | if (!base.IsMatch(stream)) 30 | return false; 31 | 32 | stream.Position = SubsignatureOffset; 33 | 34 | for (int i = 0; i < Subsignature.Count; i++) 35 | { 36 | var b = stream.ReadByte(); 37 | if (b != Subsignature[i]) 38 | { 39 | return false; 40 | } 41 | } 42 | 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/OpenDocumentPresentation.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a OpenDocument Presentation file. 5 | /// 6 | public class OpenDocumentPresentation : OpenDocument 7 | { 8 | public OpenDocumentPresentation() : base([ 9 | 0x6D, 0x69, 0x6D, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 10 | 0x2F, 0x76, 0x6E, 0x64, 0x2E, 0x6F, 0x61, 0x73, 0x69, 0x73, 0x2E, 0x6F, 0x70, 0x65, 0x6E, 0x64, 0x6F, 0x63, 0x75, 11 | 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6E, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E 12 | ], "application/vnd.oasis.opendocument.presentation", "odp") 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/OpenDocumentSpreadsheet.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a OffsetFileFormat file. 5 | /// 6 | public class OpenDocumentSpreadsheet : OpenDocument 7 | { 8 | public OpenDocumentSpreadsheet() : base([ 9 | 0x6D, 0x69, 0x6D, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 10 | 0x6E, 0x2F, 0x76, 0x6E, 0x64, 0x2E, 0x6F, 0x61, 0x73, 0x69, 0x73, 0x2E, 0x6F, 0x70, 0x65, 0x6E, 0x64, 0x6F, 11 | 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x73, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x65, 0x65, 0x74 12 | ], "application/vnd.oasis.opendocument.spreadsheet", "ods") 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/OpenDocumentText.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a OpenDocumentText file. 5 | /// 6 | public class OpenDocumentText : OpenDocument 7 | { 8 | public OpenDocumentText() : base([ 9 | 0x6D, 0x69, 0x6D, 0x65, 0x74, 0x79, 0x70, 0x65, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 10 | 0x69, 0x6F, 0x6E, 0x2F, 0x76, 0x6E, 0x64, 0x2E, 0x6F, 0x61, 0x73, 0x69, 0x73, 0x2E, 0x6F, 0x70, 11 | 0x65, 0x6E, 0x64, 0x6F, 0x63, 0x75, 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x74, 0x65, 0x78, 0x74 12 | ], "application/vnd.oasis.opendocument.text", "odt") 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/OutlookMessage.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | public class OutlookMessage : CompoundFileBinary 4 | { 5 | public OutlookMessage() : base("__properties_version1.0", "application/vnd.ms-outlook", "msg") 6 | { 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Pdf.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace FileSignatures.Formats 4 | { 5 | /// 6 | /// Specifies the format of a Portable Document Format (PDF) file. 7 | /// 8 | public class Pdf : FileFormat 9 | { 10 | public Pdf() : this([0x25, 0x50, 0x44, 0x46]) 11 | { 12 | } 13 | 14 | protected Pdf(byte[] signature) : base(signature, "application/pdf", "pdf", 0) 15 | { 16 | } 17 | 18 | } 19 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Photoshop.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | /// 4 | /// Photoshop Document file format. 5 | /// 6 | /// 7 | /// See https://www.iana.org/assignments/media-types/image/vnd.adobe.photoshop 8 | /// 9 | public class Photoshop : FileFormat 10 | { 11 | public Photoshop() : base([0x38, 0x42, 0x50, 0x53], 4, "image/vnd.adobe.photoshop", "psd") 12 | { 13 | } 14 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Png.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Portable Network Graphics (PNG) image. 5 | /// 6 | public class Png : Image 7 | { 8 | public Png() : base(new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, "image/png", "png") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Powerpoint.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Powerpoint presentation. 5 | /// 6 | public class PowerPoint : OfficeOpenXml 7 | { 8 | public PowerPoint() : base("ppt/presentation.xml", macroEnabled: false, "application/vnd.openxmlformats-officedocument.presentationml.presentation", "pptx") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/PowerpointLegacy.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a legacy Powerpoint 97-2003 presentation. 5 | /// 6 | public class PowerPointLegacy : CompoundFileBinary 7 | { 8 | public PowerPointLegacy() : base("PowerPoint Document", "application/vnd.ms-powerpoint", "ppt") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/PowerpointWithMacros.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Powerpoint presentation that supports macros. 5 | /// 6 | public class PowerPointWithMacros : OfficeOpenXml 7 | { 8 | public PowerPointWithMacros() : base("ppt/presentation.xml", macroEnabled: true, "application/vnd.ms-powerpoint.presentation.macroEnabled.12", "pptm") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Quicktime.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a QuickTime movie file 5 | /// 6 | public class Quicktime : Isobmff 7 | { 8 | public Quicktime() : base(new byte[] { 0x71, 0x74, 0x20, 0x20 }, "video/quicktime", "mov") { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Rar.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | public class Rar: FileFormat 4 | { 5 | public Rar() : base([0x52, 0x61 ,0x72 ,0x21, 0x1A, 0x07, 0x00], 7, "application/vnd.rar","rar") 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/RichTextFormat.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Rich Text Format (RTF) file. 5 | /// 6 | public class RichTextFormat : FileFormat 7 | { 8 | public RichTextFormat() : base(new byte[] { 0x7B, 0x5C, 0x72, 0x74, 0x66, 0x31 }, "application/rtf", "rtf") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/SevenZip.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | /// 4 | /// Specifies the format of a 7-zip archive. 5 | /// 6 | /// 7 | /// There is no official IANA registration but application/x-7z-compressed is commonly used. 8 | /// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types 9 | /// 10 | public class SevenZip : FileFormat 11 | { 12 | public SevenZip() : base([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C], 6, "application/x-7z-compressed", "7z") 13 | { 14 | } 15 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Spiff.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specified the format of a Still Picture Interchange File Format (SPIFF) file. 5 | /// 6 | public class Spiff : Jpeg 7 | { 8 | public Spiff() : base(new byte[] { 0xFF, 0xE8 }) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Swf.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | 4 | namespace FileSignatures.Formats; 5 | 6 | /// 7 | /// Shockwave Flash Movie format. 8 | /// 9 | /// 10 | /// See https://www.iana.org/assignments/media-types/application/vnd.adobe.flash.movie 11 | /// 12 | public class Swf : FileFormat 13 | { 14 | private static readonly byte[] ValidLeadingBytes = [0x46, 0x43, 0x5A]; 15 | 16 | public Swf() : base([0x57, 0x53], 3, "application/vnd.adobe.flash.movie", "swf", 1) 17 | { 18 | } 19 | 20 | public override bool IsMatch(Stream stream) 21 | { 22 | stream.Position = 0; 23 | var leadingByte = (byte)stream.ReadByte(); 24 | return ValidLeadingBytes.Contains(leadingByte) && base.IsMatch(stream); 25 | } 26 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Tar.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | /// 4 | /// Specifies the format of a TAR archive file. 5 | /// 6 | /// 7 | /// There is no official IANA registration for the TAR format but application/x-tar is commonly used. 8 | /// See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types 9 | /// 10 | public class Tar : FileFormat 11 | { 12 | public Tar() : base([0x75, 0x73, 0x74, 0x61, 0x72], "application/x-tar", "tar", 257) 13 | { 14 | } 15 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/ThreeGpp.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a 3rd Generation Partnership Project 3GPP multimedia files (3GG, 3GP, 3G2) 5 | /// 6 | public class ThreeGpp : Isobmff 7 | { 8 | public ThreeGpp() : base(new byte[] { 0x33, 0x67, 0x70 }, "video/3gpp", "3gp") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Tiff.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Tagged Image File Format (TIFF) image. 5 | /// 6 | public class Tiff : Image 7 | { 8 | public Tiff() : base(new byte[] { 0x2A, 0x00 }, "image/tiff", "tif", 2) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Vcard.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Contact vCard file 5 | /// 6 | public class Vcard : FileFormat 7 | { 8 | // 0x0D, 0x0A (\r\n) combinations are omitted because the text writer can use any line ending style 9 | public Vcard() : base(new byte[] { 0x42, 0x45, 0x47, 0x49, 0x4E, 0x3A, 0x56, 0x43, 0x41, 0x52, 0x44 }, "text/vcard", "vcf") 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Visio.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | public class Visio : OfficeOpenXml 4 | { 5 | public Visio() : base("visio/document.xml", macroEnabled: false, "application/vnd.visio", "vsdx") 6 | { 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/VisioLegacy.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | public class VisioLegacy : CompoundFileBinary 4 | { 5 | public VisioLegacy() : base("VisioDocument", "application/vnd.visio", "vsd") 6 | { 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Webp.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Google WebP image file format. 5 | /// 6 | /// 7 | /// See https://www.iana.org/assignments/media-types/image/webp 8 | /// 9 | public class Webp : Image 10 | { 11 | public Webp() : base([0x57, 0x45, 0x42, 0x50], "image/webp", "webp", 8) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Wmf.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats; 2 | 3 | /// 4 | /// Windows Metafile format. 5 | /// 6 | /// 7 | /// See https://www.iana.org/assignments/media-types/image/wmf 8 | /// 9 | public class Wmf : FileFormat 10 | { 11 | public Wmf() : base([0xD7, 0xCD, 0xC6, 0x9A], "image/wmf", "wmf") 12 | { 13 | } 14 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Word.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Word document. 5 | /// 6 | public class Word : OfficeOpenXml 7 | { 8 | public Word() : base("word/document.xml", macroEnabled: false, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "docx") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/WordLegacy.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Word 97-2003 document. 5 | /// 6 | public class WordLegacy : CompoundFileBinary 7 | { 8 | public WordLegacy() : base("WordDocument", "application/msword", "doc") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/WordWithMacros.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a Word document with macros. 5 | /// 6 | public class WordWithMacros : OfficeOpenXml 7 | { 8 | public WordWithMacros() : base("word/document.xml", macroEnabled: true, "application/vnd.ms-word.document.macroEnabled.12", "docm") 9 | { 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Xps.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of an XML Paper Specification (XPS) document. 5 | /// 6 | public class Xps : OfficeOpenXml 7 | { 8 | public Xps() : base("FixedDocSeq.fdseq", macroEnabled: false, "application/vnd.ms-xpsdocument", "xps") 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/FileSignatures/Formats/Zip.cs: -------------------------------------------------------------------------------- 1 | namespace FileSignatures.Formats 2 | { 3 | /// 4 | /// Specifies the format of a zip archive. 5 | /// 6 | public class Zip : FileFormat 7 | { 8 | public Zip() : this(4, "application/zip", "zip") 9 | { 10 | } 11 | 12 | protected Zip(int headerLength, string mediaType, string extension) : base(new byte[] { 0x50, 0x4B, 0x03, 0x04 }, headerLength, mediaType, extension) 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/FileSignatures/IFileFormatInspector.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace FileSignatures 4 | { 5 | /// 6 | /// Provides a mechanism to determine the format of a file. 7 | /// 8 | public interface IFileFormatInspector 9 | { 10 | /// 11 | /// Determines the format of a file. 12 | /// 13 | /// A stream containing the file content. 14 | /// An instance of a matching file format, or null if the format could not be determined. 15 | FileFormat? DetermineFileFormat(Stream stream); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/FileSignatures/IFileFormatReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace FileSignatures 5 | { 6 | /// 7 | /// A format which requires a stream to be converted into an intermediate object to determine it's exact format. 8 | /// 9 | /// 10 | /// OpenOfficeXml files are based on zip so the stream must be converted into a zip archive to determine the exact format. 11 | /// 12 | public interface IFileFormatReader 13 | { 14 | /// 15 | /// Reads a stream and converts it to another format. 16 | /// 17 | /// The stream to convert. 18 | IDisposable? Read(Stream stream); 19 | 20 | /// 21 | /// Returns a value indicating whether the format is a match for the converted stream. 22 | /// 23 | /// The converted stream to check. 24 | bool IsMatch(IDisposable? file); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/FileSignatures/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("FileSignatures")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("52d4f79f-bb2c-46e9-9d27-59ff8dc9bd81")] 19 | 20 | [assembly: System.CLSCompliant(true)] -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Benchmarks/FileFormatInspectorBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace FileSignatures.Tests.Benchmarks 7 | { 8 | [MemoryDiagnoser] 9 | public class FileFormatInspectorBenchmarks 10 | { 11 | private readonly FileFormatInspector inspector; 12 | private static readonly string samplesPath; 13 | 14 | static FileFormatInspectorBenchmarks() 15 | { 16 | var buildDirectoryPath = Path.GetDirectoryName(typeof(FunctionalTests).Assembly.Location); 17 | samplesPath = Path.Combine(buildDirectoryPath, "Samples"); 18 | } 19 | 20 | public FileFormatInspectorBenchmarks() 21 | { 22 | inspector = new FileFormatInspector(); 23 | } 24 | 25 | [ParamsSource(nameof(SampleFiles))] 26 | public string FileName { get; set; } 27 | 28 | public static IEnumerable SampleFiles() 29 | { 30 | var samplesDirectory = new DirectoryInfo(samplesPath); 31 | 32 | return samplesDirectory 33 | .GetFiles() 34 | //.Where(x => x.Extension == ".xls") 35 | .Select(x => x.Name) 36 | .ToList(); 37 | } 38 | 39 | [Benchmark] 40 | public FileFormat DetermineFileFormat() 41 | { 42 | // We must open the stream as part of the benchmark because otherwise 43 | // Windows anti-malware will get rather upset with us. 44 | using var stream = File.OpenRead(Path.Combine(samplesPath, FileName)); 45 | return inspector.DetermineFileFormat(stream); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | namespace FileSignatures.Tests.Benchmarks 4 | { 5 | public static class Program 6 | { 7 | public static void Main() 8 | { 9 | BenchmarkRunner.Run(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/FileFormatInspectorTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Xunit; 4 | 5 | namespace FileSignatures.Tests 6 | { 7 | public class FileFormatInspectorTests 8 | { 9 | [Fact] 10 | public void StreamCannotBeNull() 11 | { 12 | var inspector = new FileFormatInspector(); 13 | 14 | Assert.Throws(() => inspector.DetermineFileFormat(null)); 15 | } 16 | 17 | [Fact] 18 | public void EmptyStreamReturnsNull() 19 | { 20 | var inspector = new FileFormatInspector(); 21 | FileFormat result; 22 | 23 | using (var stream = new MemoryStream()) 24 | { 25 | result = inspector.DetermineFileFormat(stream); 26 | } 27 | 28 | Assert.Null(result); 29 | } 30 | 31 | [Fact] 32 | public void StreamMustBeSeekable() 33 | { 34 | var nonSeekableStream = new NonSeekableStream(); 35 | var inspector = new FileFormatInspector(Array.Empty()); 36 | 37 | Assert.Throws(() => inspector.DetermineFileFormat(nonSeekableStream)); 38 | } 39 | 40 | private class NonSeekableStream : Stream 41 | { 42 | public override bool CanSeek => false; 43 | 44 | #region Not relevant for tests 45 | public override bool CanRead => throw new NotImplementedException(); 46 | 47 | public override bool CanWrite => throw new NotImplementedException(); 48 | 49 | public override long Length => throw new NotImplementedException(); 50 | 51 | public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } 52 | 53 | public override void Flush() 54 | { 55 | throw new NotImplementedException(); 56 | } 57 | 58 | public override int Read(byte[] buffer, int offset, int count) 59 | { 60 | throw new NotImplementedException(); 61 | } 62 | 63 | public override long Seek(long offset, SeekOrigin origin) 64 | { 65 | throw new NotImplementedException(); 66 | } 67 | 68 | public override void SetLength(long value) 69 | { 70 | throw new NotImplementedException(); 71 | } 72 | 73 | public override void Write(byte[] buffer, int offset, int count) 74 | { 75 | throw new NotImplementedException(); 76 | } 77 | 78 | #endregion 79 | } 80 | 81 | [Fact] 82 | public void UnrecognisedReturnsNull() 83 | { 84 | var inspector = new FileFormatInspector(Array.Empty()); 85 | FileFormat result; 86 | 87 | using (var stream = new MemoryStream(new byte[] { 0x0A })) 88 | { 89 | result = inspector.DetermineFileFormat(stream); 90 | } 91 | 92 | Assert.Null(result); 93 | } 94 | 95 | [Fact] 96 | public void SingleMatchIsReturned() 97 | { 98 | var expected = new TestFileFormat(new byte[] { 0x42, 0x4D }); 99 | var inspector = new FileFormatInspector(new FileFormat[] { expected }); 100 | FileFormat result; 101 | 102 | using (var stream = new MemoryStream(new byte[] { 0x42, 0x4D, 0x3A, 0x00 })) 103 | { 104 | result = inspector.DetermineFileFormat(stream); 105 | } 106 | 107 | Assert.Equal(expected, result); 108 | } 109 | 110 | [Fact] 111 | public void StreamIsReadUntilRequiredBufferIsReceived() 112 | { 113 | var expected = new TestFileFormat(new byte[] { 0x00, 0x01 }); 114 | var incorrect = new TestFileFormat(new byte[] { 0x00, 0x02 }); 115 | var inspector = new FileFormatInspector(new FileFormat[] { expected, incorrect }); 116 | FileFormat result; 117 | 118 | using (var fragmentedStream = new FragmentedStream(new byte[] { 0x00, 0x01, 0x03 })) 119 | { 120 | result = inspector.DetermineFileFormat(fragmentedStream); 121 | } 122 | 123 | Assert.Equal(expected, result); 124 | } 125 | 126 | [Fact] 127 | public void StreamIsResetToOriginalPosition() 128 | { 129 | var shortSignature = new TestFileFormat(new byte[] { 0x00, 0x01 }); 130 | var longSignaure = new TestFileFormat(new byte[] { 0x00, 0x01, 0x02 }); 131 | var inspector = new FileFormatInspector(new FileFormat[] { shortSignature, longSignaure }); 132 | var position = 0L; 133 | 134 | using (var stream = new MemoryStream(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04 })) 135 | { 136 | inspector.DetermineFileFormat(stream); 137 | position = stream.Position; 138 | } 139 | 140 | Assert.Equal(0, position); 141 | } 142 | 143 | [Fact] 144 | public void MultipleMatchesReturnsMostDerivedFormat() 145 | { 146 | var baseFormat = new BaseFormat(); 147 | var inheritedFormat = new InheritedFormat(); 148 | var inspector = new FileFormatInspector(new FileFormat[] { inheritedFormat, baseFormat }); 149 | FileFormat result = null; 150 | 151 | using (var stream = new MemoryStream(new byte[] { 0x00 })) 152 | { 153 | result = inspector.DetermineFileFormat(stream); 154 | } 155 | 156 | Assert.Equal(inheritedFormat, result); 157 | } 158 | 159 | [Fact] 160 | public void MutipleMatchesReturnsFormatWithLongestHeader() 161 | { 162 | var shortHeader = new TestFileFormat(new byte[] { 0x02, 0x00 }); 163 | var longHeader = new AnotherTestFileFormat(new byte[] { 0x02, 0x00, 0xFF }); 164 | 165 | var inspector = new FileFormatInspector(new FileFormat[] { shortHeader, longHeader }); 166 | FileFormat result = null; 167 | 168 | using (var stream = new MemoryStream(new byte[] { 0x02, 0x00, 0xFF, 0xFA })) 169 | { 170 | result = inspector.DetermineFileFormat(stream); 171 | } 172 | 173 | Assert.NotNull(result); 174 | Assert.Equal(longHeader, result); 175 | } 176 | 177 | private class FragmentedStream : MemoryStream 178 | { 179 | public FragmentedStream(byte[] buffer) : base(buffer) 180 | { 181 | } 182 | 183 | public override int Read(byte[] buffer, int offset, int count) 184 | { 185 | return base.Read(buffer, offset, 1); 186 | } 187 | } 188 | 189 | private class TestFileFormat : FileFormat 190 | { 191 | public TestFileFormat(byte[] signature) : base(signature, "example/test", "test") 192 | { 193 | } 194 | } 195 | 196 | private class BaseFormat : FileFormat 197 | { 198 | public BaseFormat() : this("example/base") 199 | { 200 | } 201 | 202 | protected BaseFormat(string mediaType) : base(new byte[] { 0x00 }, mediaType, "") 203 | { 204 | } 205 | 206 | public override bool IsMatch(Stream stream) 207 | { 208 | return true; 209 | } 210 | } 211 | 212 | private class InheritedFormat : BaseFormat 213 | { 214 | public InheritedFormat() : base("example/inherited") 215 | { 216 | } 217 | } 218 | 219 | private class AnotherTestFileFormat : FileFormat 220 | { 221 | public AnotherTestFileFormat(byte[] signature) : base(signature, "example/another", "test") 222 | { 223 | } 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/FileFormatLocatorTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using Xunit; 5 | 6 | namespace FileSignatures.Tests 7 | { 8 | public class FileFormatLocatorTests 9 | { 10 | [Fact] 11 | public void LocatesConcreteFormatsInAssembly() 12 | { 13 | var expected = typeof(FileFormat) 14 | .GetTypeInfo() 15 | .Assembly 16 | .GetTypes() 17 | .Where(t => typeof(FileFormat).IsAssignableFrom(t)) 18 | .Where(t => !t.GetTypeInfo().IsAbstract) 19 | .Where(t => t.GetConstructors().Any(c => c.GetParameters().Count() == 0)) 20 | .Select(t => Activator.CreateInstance(t)) 21 | .OfType(); 22 | 23 | var result = FileFormatLocator.GetFormats(); 24 | 25 | Assert.Equal(expected, result); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/FileFormatTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Xunit; 4 | 5 | namespace FileSignatures.Tests 6 | { 7 | public class FileFormatTests 8 | { 9 | [Fact] 10 | public void SignatureCannotBeNull() 11 | { 12 | Assert.Throws(() => new ConcreteFileFormat(null, "example/bad", "bad")); 13 | } 14 | 15 | [Theory] 16 | [InlineData(null)] 17 | [InlineData("")] 18 | public void MediaTypeCannotBeNullOrEmpty(string badMediaType) 19 | { 20 | Assert.Throws(() => new ConcreteFileFormat(new byte[] { 0x01 }, badMediaType, "bad")); 21 | } 22 | 23 | [Fact] 24 | public void EqualityIsBasedOnSignature() 25 | { 26 | var first = new ConcreteFileFormat(new byte[] { 0x01 }, "example/one", "1"); 27 | var second = new ConcreteFileFormat(new byte[] { 0x01 }, "example/two", "2"); 28 | 29 | Assert.Equal(first, second); 30 | } 31 | 32 | [Fact] 33 | public void GetHashCodeIsBasedOnSignature() 34 | { 35 | var first = new ConcreteFileFormat(new byte[] { 0x01 }, "example/one", "1"); 36 | var second = new ConcreteFileFormat(new byte[] { 0x01 }, "example/two", "2"); 37 | 38 | Assert.Equal(first.GetHashCode(), second.GetHashCode()); 39 | } 40 | 41 | [Fact] 42 | public void MatchesHeaderContainingSignature() 43 | { 44 | var format = new ConcreteFileFormat(new byte[] { 0x6F, 0x3C }, "example/sim", ""); 45 | var header = new byte[] { 0x6F, 0x3c, 0xFF, 0xFA }; 46 | 47 | using var ms = new MemoryStream(header); 48 | var result = format.IsMatch(ms); 49 | 50 | Assert.True(result); 51 | } 52 | 53 | [Fact] 54 | public void MatchesSignatureAtOffsetPosition() 55 | { 56 | var format = new OffsetFileFormat(new byte[] { 0x03, 0x04 }, "example/test", "", 2); 57 | var header = new byte[] { 0x01, 0x02, 0x03, 0x04 }; 58 | 59 | using var ms = new MemoryStream(header); 60 | var result = format.IsMatch(ms); 61 | 62 | Assert.True(result); 63 | } 64 | 65 | private class OffsetFileFormat : FileFormat 66 | { 67 | public OffsetFileFormat(byte[] signature, string mediatType, string extension, int offset) 68 | : base(signature, mediatType, extension, offset) 69 | { 70 | } 71 | } 72 | 73 | [Theory] 74 | [InlineData(new byte[] { 0x6F })] 75 | [InlineData(new byte[] { 0x3C, 0x6F })] 76 | public void DoesNotMatchDifferentHeader(byte[] header) 77 | { 78 | var format = new ConcreteFileFormat(new byte[] { 0x6F, 0x3C }, "example/sim", ""); 79 | 80 | using var ms = new MemoryStream(header); 81 | var result = format.IsMatch(ms); 82 | 83 | Assert.False(result); 84 | } 85 | 86 | private class ConcreteFileFormat : FileFormat 87 | { 88 | public ConcreteFileFormat(byte[] signature, string mediaType, string extension) : base(signature, mediaType, extension) 89 | { 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/FileSignatures.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | FileSignatures.Tests 6 | FileSignatures.Tests 7 | true 8 | false 9 | false 10 | false 11 | Latest 12 | FileSignatures.Tests.Benchmarks.Program 13 | 14 | 15 | 16 | 17 | PreserveNewest 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | all 27 | runtime; build; native; contentfiles; analyzers; buildtransitive 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Formats/OfficeOpenXmlTests.cs: -------------------------------------------------------------------------------- 1 | using FileSignatures.Formats; 2 | using System.IO; 3 | using System.IO.Compression; 4 | using Xunit; 5 | 6 | namespace FileSignatures.Tests.Formats 7 | { 8 | public class OfficeOpenXmlTests 9 | { 10 | [Fact] 11 | public void InvalidZipArchiveDoesNotThrow() 12 | { 13 | var inspector = new FileFormatInspector(); 14 | 15 | using var stream = new MemoryStream(new byte[] { 0x50, 0x4B, 0x03, 0x04 }); 16 | var format = inspector.DetermineFileFormat(stream); 17 | 18 | Assert.NotNull(format); 19 | Assert.IsType(format); 20 | } 21 | 22 | [Fact] 23 | public void IdentifierWithoutExtensionDoesNotThrow() 24 | { 25 | var format = new TestOfficeOpenXml("test", macroEnabled: false, "example/test", "test"); 26 | 27 | using var stream = new MemoryStream(); 28 | using(var createArchive = new ZipArchive(stream, ZipArchiveMode.Create, true)) 29 | { 30 | createArchive.CreateEntry("test"); 31 | } 32 | 33 | using var archive = new ZipArchive(stream, ZipArchiveMode.Read); 34 | 35 | var result = format.IsMatch(archive); 36 | 37 | Assert.True(result); 38 | } 39 | 40 | private class TestOfficeOpenXml : OfficeOpenXml 41 | { 42 | public TestOfficeOpenXml(string identifiableEntry, bool macroEnabled, string mediaType, string extension) : base(identifiableEntry, macroEnabled, mediaType, extension) 43 | { 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/FunctionalTests.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Reflection; 3 | using Xunit; 4 | 5 | namespace FileSignatures.Tests 6 | { 7 | public class FunctionalTests 8 | { 9 | [Theory] 10 | [InlineData("test.bmp", "image/bmp")] 11 | [InlineData("test.doc", "application/msword")] 12 | [InlineData("test.docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document")] 13 | [InlineData("test.docm", "application/vnd.ms-word.document.macroEnabled.12")] 14 | [InlineData("test.exe", "application/vnd.microsoft.portable-executable")] 15 | [InlineData("test.gif", "image/gif")] 16 | [InlineData("test.jfif", "image/jpeg")] 17 | [InlineData("test.exif", "image/jpeg")] 18 | [InlineData("saved.msg", "application/vnd.ms-outlook")] 19 | [InlineData("dragndrop.msg", "application/vnd.ms-outlook")] 20 | [InlineData("nonstandard.docx","application/vnd.openxmlformats-officedocument.wordprocessingml.document")] 21 | [InlineData("test.pdf", "application/pdf")] 22 | [InlineData("adobe.pdf", "application/pdf")] 23 | [InlineData("test.rtf", "application/rtf")] 24 | [InlineData("test.png", "image/png")] 25 | [InlineData("test.ppt", "application/vnd.ms-powerpoint")] 26 | [InlineData("test2.ppt", "application/vnd.ms-powerpoint")] 27 | [InlineData("test.pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation")] 28 | [InlineData("test.pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12")] 29 | [InlineData("test.spiff", "image/jpeg")] 30 | [InlineData("test.tif", "image/tiff")] 31 | [InlineData("test.xls", "application/vnd.ms-excel")] 32 | [InlineData("test.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")] 33 | [InlineData("test.xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12")] 34 | [InlineData("test.xps", "application/vnd.ms-xpsdocument")] 35 | [InlineData("test.zip", "application/zip")] 36 | [InlineData("test.rar", "application/vnd.rar")] 37 | [InlineData("test.tar", "application/x-tar")] 38 | [InlineData("test.dcm", "application/dicom")] 39 | [InlineData("test.odt", "application/vnd.oasis.opendocument.text")] 40 | [InlineData("test.ods", "application/vnd.oasis.opendocument.spreadsheet")] 41 | [InlineData("test.odp", "application/vnd.oasis.opendocument.presentation")] 42 | [InlineData("test.vsd", "application/vnd.visio")] 43 | [InlineData("test.vsdx", "application/vnd.visio")] 44 | [InlineData("test.webp", "image/webp")] 45 | [InlineData("test.mp4", "video/mp4")] 46 | [InlineData("test-v1.mp4", "video/mp4")] 47 | [InlineData("test.m4v", "video/mp4")] 48 | [InlineData("test.m4a", "audio/mp4")] 49 | [InlineData("test.flv", "video/x-flv")] 50 | [InlineData("test.mid", "audio/midi")] 51 | [InlineData("test.mov", "video/quicktime")] 52 | [InlineData("test.3gp", "video/3gpp")] 53 | [InlineData("test.vcf", "text/vcard")] 54 | [InlineData("test.mp3", "audio/mpeg")] 55 | [InlineData("test.flac", "audio/flac")] 56 | [InlineData("test.ogg", "audio/ogg")] 57 | [InlineData("test.amr", "audio/amr")] 58 | [InlineData("test.ico", "image/vnd.microsoft.icon")] 59 | [InlineData("malicious.pdf", "application/vnd.microsoft.portable-executable")] 60 | [InlineData("test.gz", "application/gzip")] 61 | [InlineData("test.7z", "application/x-7z-compressed")] 62 | [InlineData("test.swf", "application/vnd.adobe.flash.movie")] 63 | [InlineData("test.wmf", "image/wmf")] 64 | [InlineData("test.psd", "image/vnd.adobe.photoshop")] 65 | [InlineData("test.xlsb", "vnd.ms-excel.sheet.binary.macroEnabled.12")] 66 | public void SamplesAreRecognised(string sample, string expected) 67 | { 68 | var result = InspectSample(sample); 69 | 70 | Assert.NotNull(result); 71 | Assert.Equal(expected, result?.MediaType); 72 | } 73 | 74 | private static FileFormat InspectSample(string fileName) 75 | { 76 | var inspector = new FileFormatInspector(); 77 | var buildDirectoryPath = Path.GetDirectoryName(typeof(FunctionalTests).GetTypeInfo().Assembly.Location)!; 78 | var sample = new FileInfo(Path.Combine(buildDirectoryPath, "Samples", fileName)); 79 | 80 | using var stream = sample.OpenRead(); 81 | var result = inspector.DetermineFileFormat(stream); 82 | 83 | return result; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("FileSignatures.Tests")] 10 | [assembly: AssemblyTrademark("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("5fe9af07-5928-482e-9917-285956e7731c")] 19 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/dragndrop.msg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/dragndrop.msg -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/malicious.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/malicious.pdf -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/nonstandard.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/nonstandard.docx -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/saved.msg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/saved.msg -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test-v1.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test-v1.mp4 -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.3gp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.3gp -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.7z -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.amr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.amr -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.bmp -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.dcm: -------------------------------------------------------------------------------- 1 | DICMULhOBUI1.2.840.10008.1.2UI1.3.6.1.4.1.30071.8SHfo-dicom 4.0.0AEAQUILA -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.doc -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.docm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.docm -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.docx -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.exe -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.exif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.exif -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.flac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.flac -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.flv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.flv -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.gif -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.gz -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.ico -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.jfif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.jfif -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.jpg -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.m4a -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.m4v: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.m4v -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.mid -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.mov -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.mp3 -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.mp4 -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.odp -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.ods -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.odt -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.ogg -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.pdf -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.png -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.ppt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.ppt -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.pptm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.pptm -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.pptx -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.psd -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.rar -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch0\stshfloch37\stshfhich37\stshfbi0\deflang2057\deflangfe2057\themelang2057\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;} 2 | {\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} 3 | {\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0302020204030204}Calibri Light;} 4 | {\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} 5 | {\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;} 6 | {\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f39\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} 7 | {\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} 8 | {\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f379\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}{\f380\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;} 9 | {\f382\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f383\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f386\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}{\f387\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);} 10 | {\f409\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f410\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f412\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f413\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;} 11 | {\f414\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\f415\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\f416\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f417\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);} 12 | {\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} 13 | {\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} 14 | {\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} 15 | {\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} 16 | {\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} 17 | {\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhimajor\f31528\fbidi \fswiss\fcharset238\fprq2 Calibri Light CE;}{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;} 18 | {\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;}{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}{\fhimajor\f31533\fbidi \fswiss\fcharset177\fprq2 Calibri Light (Hebrew);} 19 | {\fhimajor\f31534\fbidi \fswiss\fcharset178\fprq2 Calibri Light (Arabic);}{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);} 20 | {\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} 21 | {\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} 22 | {\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} 23 | {\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} 24 | {\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} 25 | {\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} 26 | {\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} 27 | {\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} 28 | {\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;} 29 | {\fhiminor\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\fhiminor\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;} 30 | {\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} 31 | {\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} 32 | {\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}} 33 | {\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0; 34 | \red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\*\defchp \f37 }{\*\defpap \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 } 35 | \noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \f37\fs22\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 36 | \snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\* 37 | \ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv 38 | \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \f37\fs20\lang2057\langfe2057\cgrid\langnp2057\langfenp2057 \snext11 \ssemihidden \sunhideused Normal Table;}} 39 | {\*\rsidtbl \rsid2120983\rsid5536708\rsid12397393\rsid13137492\rsid14158604}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator Neil Harvey} 40 | {\creatim\yr2016\mo12\dy28\hr8\min56}{\revtim\yr2016\mo12\dy28\hr8\min58}{\printim\yr2016\mo12\dy28\hr8\min55}{\version3}{\edmins1}{\nofpages1}{\nofwords0}{\nofchars0}{\nofcharsws0}{\vern57441}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/wor 41 | d/2003/wordml}}\paperw11906\paperh16838\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect 42 | \widowctrl\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\noxlattoyen 43 | \expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1440\dgvorigin1440\dghshow1\dgvshow1 44 | \jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct 45 | \asianbrkrule\rsidroot12397393\newtblstyruls\nogrowautofit\utinl \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1 46 | \pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5 47 | \pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang 48 | {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 49 | \ltrch\fcs0 \f37\fs22\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid14158604 50 | \par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a 51 | 9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad 52 | 5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6 53 | b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0 54 | 0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6 55 | a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f 56 | c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512 57 | 0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462 58 | a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865 59 | 6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b 60 | 4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b 61 | 4757e8d3f729e245eb2b260a0238fd010000ffff0300504b030414000600080000002100aa5225dfc60600008b1a0000160000007468656d652f7468656d652f 62 | 7468656d65312e786d6cec595d8bdb46147d2ff43f08bd3bfe92fcb1c41b6cd9ceb6d94d42eca4e4716c8fadc98e344633de8d0981923c160aa569e943037deb 63 | 43691b48a02fe9afd936a54d217fa17746b63c638fbb9b2585a5640d8b343af7ce997bafce1d4997afdc8fa87384134e58dc708b970aae83e3211b9178d2706f 64 | f7bbb99aeb7081e211a22cc60d778eb97b65f7c30f2ea31d11e2083b601ff31dd4704321a63bf93c1fc230e297d814c7706dcc920809384d26f951828ec16f44 65 | f3a542a1928f10895d274611b8bd311e932176fad2a5bbbb74dea1701a0b2e078634e949d7d8b050d8d1615122f89c0734718e106db830cf881df7f17de13a14 66 | 7101171a6e41fdb9f9ddcb79b4b330a2628bad66d7557f0bbb85c1e8b0a4e64c26836c52cff3bd4a33f3af00546ce23ad54ea553c9fc29001a0e61a52917dda7 67 | dfaab7dafe02ab81d2438bef76b55d2e1a78cd7f798373d3973f03af40a97f6f03dfed06104503af4029dedfc07b5eb51478065e81527c65035f2d34db5ed5c0 68 | 2b5048497cb8812ef89572b05c6d061933ba6785d77daf5b2d2d9caf50500d5975c929c62c16db6a2d42f758d2058004522448ec88f9148fd110aa3840940c12 69 | e2ec93490885374531e3305c2815ba8532fc973f4f1da988a01d8c346bc90b98f08d21c9c7e1c3844c45c3fd18bcba1ae4cdcb1fdfbc7cee9c3c7a71f2e89793 70 | c78f4f1efd9c3a32acf6503cd1ad5e7fffc5df4f3f75fe7afeddeb275fd9f15cc7fffed367bffdfaa51d082b5d85e0d5d7cffe78f1ecd5379ffff9c3130bbc99 71 | a0810eef930873e73a3e766eb10816a6426032c783e4ed2cfa2122ba45339e701423398bc57f478406fafa1c5164c1b5b019c13b09488c0d787576cf20dc0b93 72 | 9920168fd7c2c8001e30465b2cb146e19a9c4b0b737f164fec9327331d770ba123dbdc018a8dfc766653d05662731984d8a07993a258a0098eb170e4357688b1 73 | 6575770931e27a408609e36c2c9cbbc46921620d499f0c8c6a5a19ed9108f232b711847c1bb139b8e3b418b5adba8d8f4c24dc15885ac8f73135c27815cd048a 74 | 6c2efb28a27ac0f791086d247bf364a8e33a5c40a6279832a733c29cdb6c6e24b05e2de9d7405eec693fa0f3c84426821cda7cee23c674649b1d06218aa6366c 75 | 8fc4a18efd881f428922e7261336f80133ef10790e7940f1d674df21d848f7e96a701b9455a7b42a107965965872791533a37e7b733a4658490d08bfa1e71189 76 | 4f15f73559f7ff5b5907217df5ed53cbaa2eaaa0371362bda3f6d6647c1b6e5dbc03968cc8c5d7ee369ac53731dc2e9b0decbd74bf976ef77f2fdddbeee7772f 77 | d82b8d06f9965bc574abae36eed1d67dfb9850da13738af7b9daba73e84ca32e0c4a3bf5cc8ab3e7b8690887f24e86090cdc2441cac64998f88488b017a229ec 78 | ef8bae7432e10bd713ee4c19876dbf1ab6fa96783a8b0ed8287d5c2d16e5a3692a1e1c89d578c1cfc6e15143a4e84a75f50896b9576c27ea51794940dabe0d09 79 | 6d329344d942a2ba1c9441520fe610340b09b5b277c2a26e615193ee97a9da6001d4b2acc0d6c9810d57c3f53d30012378a242148f649ed2542fb3ab92f92e33 80 | bd2d984605c03e625901ab4cd725d7adcb93ab4b4bed0c99364868e566925091513d8c87688417d52947cf42e36d735d5fa5d4a02743a1e683d25ad1a8d6fe8d 81 | c579730d76ebda40635d2968ec1c37dc4ad9879219a269c31dc3633f1c4653a81d2eb7bc884ee0ddd95024e90d7f1e6599265cb4110fd3802bd149d520220227 82 | 0e2551c395cbcfd24063a5218a5bb104827061c9d541562e1a3948ba99643c1ee3a1d0d3ae8dc848a7a7a0f0a95658af2af3f383a5259b41ba7be1e8d819d059 83 | 720b4189f9d5a20ce0887078fb534ca33922f03a3313b255fdad35a685eceaef13550da5e3884e43b4e828ba98a77025e5191d7596c5403b5bac1902aa8564d1 84 | 080713d960f5a01add34eb1a2987ad5df7742319394d34573dd35015d935ed2a66ccb06c036bb13c5f93d7582d430c9aa677f854bad725b7bed4bab57d42d625 85 | 20e059fc2c5df70c0d41a3b69acca026196fcab0d4ecc5a8d93b960b3c85da599a84a6fa95a5dbb5b8653dc23a1d0c9eabf383dd7ad5c2d078b9af549156df3d 86 | f44f136c700fc4a30d2f81675470954af8f09020d810f5d49e24950db845ee8bc5ad0147ce2c210df741c16f7a41c90f72859adfc97965af90abf9cd72aee9fb 87 | e562c72f16daadd243682c228c8a7efacda50bafa2e87cf1e5458d6f7c7d89966fdb2e0d599467eaeb4a5e11575f5f8aa5ed5f5f1c02a2f3a052ead6cbf55625 88 | 572f37bb39afddaae5ea41a5956b57826abbdb0efc5abdfbd0758e14d86b9603afd2a9e52ac520c8799582a45fabe7aa5ea9d4f4aacd5ac76b3e5c6c6360e5a9 89 | 7c2c6201e155bc76ff010000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f7468656d652f5f72656c732f 90 | 7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f2451eced0dae2c082e8761be 91 | 9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198720e274a939cd08a54f980 92 | ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528a2c6cce0239baa4c04ca5b 93 | babac4df000000ffff0300504b01022d0014000600080000002100e9de0fbfff0000001c0200001300000000000000000000000000000000005b436f6e74656e 94 | 745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b00000000000000000000000000300100005f72656c732f 95 | 2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000190200007468656d652f7468656d652f74 96 | 68656d654d616e616765722e786d6c504b01022d0014000600080000002100aa5225dfc60600008b1a00001600000000000000000000000000d6020000746865 97 | 6d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b0100002700000000000000000000000000d00900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000cb0a00000000} 98 | {\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d 99 | 617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169 100 | 6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363 101 | 656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e} 102 | {\*\latentstyles\lsdstimax371\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1; 103 | \lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4; 104 | \lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7; 105 | \lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1; 106 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 5; 107 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 9; 108 | \lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3; 109 | \lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6; 110 | \lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Indent; 111 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 header;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footer; 112 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index heading;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of figures; 113 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope return;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation reference; 114 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 line number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 page number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote text; 115 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of authorities;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 macro;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 toa heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List; 116 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 3; 117 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 3; 118 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 3; 119 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Closing; 120 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Signature;\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent; 121 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 4; 122 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Message Header;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation; 123 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Note Heading; 124 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 3; 125 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Block Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 FollowedHyperlink;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong; 126 | \lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Document Map;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Plain Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 E-mail Signature; 127 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Top of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Bottom of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal (Web);\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Acronym; 128 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition; 129 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter; 130 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1; 131 | \lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid; 132 | \lsdsemihidden1 \lsdlocked0 Placeholder Text;\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid; 133 | \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2; 134 | \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List;\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1; 135 | \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1; 136 | \lsdsemihidden1 \lsdlocked0 Revision;\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1; 137 | \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1; 138 | \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2; 139 | \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2; 140 | \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2; 141 | \lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3; 142 | \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3; 143 | \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3; 144 | \lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4; 145 | \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4; 146 | \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4; 147 | \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdpriority62 \lsdlocked0 Light Grid Accent 5; 148 | \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5; 149 | \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5; 150 | \lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6; 151 | \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6; 152 | \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6; 153 | \lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis; 154 | \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography; 155 | \lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4; 156 | \lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4; 157 | \lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1; 158 | \lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1; 159 | \lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2; 160 | \lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2; 161 | \lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3; 162 | \lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4; 163 | \lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4; 164 | \lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5; 165 | \lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5; 166 | \lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6; 167 | \lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6; 168 | \lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark; 169 | \lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1; 170 | \lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1; 171 | \lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2; 172 | \lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3; 173 | \lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3; 174 | \lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4; 175 | \lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4; 176 | \lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5; 177 | \lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5; 178 | \lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6; 179 | \lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;}}{\*\datastore 010500000200000018000000 180 | 4d73786d6c322e534158584d4c5265616465722e362e3000000000000000000000060000 181 | d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 182 | ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 183 | ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 184 | ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 185 | fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 186 | ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 187 | ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 188 | ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 189 | ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e500000000000000000000000010fe 190 | 5b91e860d201feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000 191 | 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000 192 | 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000 193 | 0000000000000000000000000000000000000000000000000105000000000000}} -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.spiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.spiff -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.swf -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.tar: -------------------------------------------------------------------------------- 1 | dummy.txt0000644000175000017500000000007610507736720012006 0ustar haypohaypodummy ASCII text stored in a TAR archive for Hachoir testcase 2 | subdir/0000755000175000001440000000000010507736757011426 5ustar haypouserssubdir/another.txt0000644000175000017500000000010610507736750013600 0ustar haypohaypoanother dummy ASCII text stored in a TAR archive for Hachoir testcase 3 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.tif -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.unknown: -------------------------------------------------------------------------------- 1 | A sample unreognisable file format. -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.vcf: -------------------------------------------------------------------------------- 1 | BEGIN:VCARD 2 | VERSION:3.0 3 | PRODID:-//Apple Inc.//macOS 11.5.2//EN 4 | N:Doe;John;;; 5 | FN:John Doe 6 | ORG:Sharpened Productions; 7 | EMAIL;type=INTERNET;type=HOME;type=pref:johndoe@email.com 8 | EMAIL;type=INTERNET;type=WORK:johndoe@workemail.com 9 | TEL;type=CELL;type=VOICE;type=pref:123-456-7890 10 | ADR;type=HOME;type=pref:;;12345 First Avenue;Hometown;NY;12345;United States 11 | ADR;type=WORK:;;67890 Second Avenue;Businesstown;NY;67890;United States 12 | NOTE:The man I met at the company networking event. He mentioned that he had some potential leads. 13 | item1.URL;type=pref:https://fileinfo.com/ 14 | item1.X-ABLabel:_$!!$_ 15 | BDAY:2000-01-01 16 | END:VCARD 17 | -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.vsd -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.vsdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.vsdx -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.webp -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.wmf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.wmf -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.xls -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.xlsb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.xlsb -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.xlsm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.xlsm -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.xlsx -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.xps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.xps -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test.zip -------------------------------------------------------------------------------- /test/FileSignatures.Tests/Samples/test2.ppt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neilharvey/FileSignatures/ba0ea5a1ea2e7cf7bfe19d3d2d754fbf0186b8db/test/FileSignatures.Tests/Samples/test2.ppt -------------------------------------------------------------------------------- /test/FileSignatures.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "methodDisplay" : "method" 3 | } 4 | --------------------------------------------------------------------------------