mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 03:52:24 -05:00 
			
		
		
		
	[chore]: Bump github.com/go-playground/validator/v10 (#1812)
Bumps [github.com/go-playground/validator/v10](https://github.com/go-playground/validator) from 10.13.0 to 10.14.0. - [Release notes](https://github.com/go-playground/validator/releases) - [Commits](https://github.com/go-playground/validator/compare/v10.13.0...v10.14.0) --- updated-dependencies: - dependency-name: github.com/go-playground/validator/v10 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
		
					parent
					
						
							
								9c24dee01f
							
						
					
				
			
			
				commit
				
					
						ea1bbacf4b
					
				
			
		
					 38 changed files with 3788 additions and 28 deletions
				
			
		
							
								
								
									
										5
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								go.mod
									
										
									
									
									
								
							|  | @ -26,7 +26,7 @@ require ( | ||||||
| 	github.com/gin-gonic/gin v1.9.0 | 	github.com/gin-gonic/gin v1.9.0 | ||||||
| 	github.com/go-fed/httpsig v1.1.0 | 	github.com/go-fed/httpsig v1.1.0 | ||||||
| 	github.com/go-playground/form/v4 v4.2.0 | 	github.com/go-playground/form/v4 v4.2.0 | ||||||
| 	github.com/go-playground/validator/v10 v10.13.0 | 	github.com/go-playground/validator/v10 v10.14.0 | ||||||
| 	github.com/google/uuid v1.3.0 | 	github.com/google/uuid v1.3.0 | ||||||
| 	github.com/gorilla/feeds v1.1.1 | 	github.com/gorilla/feeds v1.1.1 | ||||||
| 	github.com/gorilla/websocket v1.5.0 | 	github.com/gorilla/websocket v1.5.0 | ||||||
|  | @ -99,6 +99,7 @@ require ( | ||||||
| 	github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e // indirect | 	github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e // indirect | ||||||
| 	github.com/dustin/go-humanize v1.0.1 // indirect | 	github.com/dustin/go-humanize v1.0.1 // indirect | ||||||
| 	github.com/fsnotify/fsnotify v1.6.0 // indirect | 	github.com/fsnotify/fsnotify v1.6.0 // indirect | ||||||
|  | 	github.com/gabriel-vasile/mimetype v1.4.2 // indirect | ||||||
| 	github.com/gin-contrib/sse v0.1.0 // indirect | 	github.com/gin-contrib/sse v0.1.0 // indirect | ||||||
| 	github.com/go-errors/errors v1.4.1 // indirect | 	github.com/go-errors/errors v1.4.1 // indirect | ||||||
| 	github.com/go-jose/go-jose/v3 v3.0.0 // indirect | 	github.com/go-jose/go-jose/v3 v3.0.0 // indirect | ||||||
|  | @ -129,7 +130,7 @@ require ( | ||||||
| 	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect | 	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect | ||||||
| 	github.com/klauspost/compress v1.16.3 // indirect | 	github.com/klauspost/compress v1.16.3 // indirect | ||||||
| 	github.com/klauspost/cpuid/v2 v2.2.4 // indirect | 	github.com/klauspost/cpuid/v2 v2.2.4 // indirect | ||||||
| 	github.com/leodido/go-urn v1.2.3 // indirect | 	github.com/leodido/go-urn v1.2.4 // indirect | ||||||
| 	github.com/magiconair/properties v1.8.7 // indirect | 	github.com/magiconair/properties v1.8.7 // indirect | ||||||
| 	github.com/mattn/go-isatty v0.0.18 // indirect | 	github.com/mattn/go-isatty v0.0.18 // indirect | ||||||
| 	github.com/minio/md5-simd v1.1.2 // indirect | 	github.com/minio/md5-simd v1.1.2 // indirect | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								go.sum
									
										
									
									
									
								
							|  | @ -188,6 +188,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 | ||||||
| github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= | ||||||
| github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= | ||||||
| github.com/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg= | github.com/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg= | ||||||
|  | github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= | ||||||
|  | github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= | ||||||
| github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= | github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= | ||||||
| github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= | github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= | ||||||
| github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | ||||||
|  | @ -230,8 +232,8 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl | ||||||
| github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= | ||||||
| github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= | ||||||
| github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= | github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= | ||||||
| github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ= | github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= | ||||||
| github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4= | github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= | ||||||
| github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0= | github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0= | ||||||
| github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= | ||||||
| github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= | github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= | ||||||
|  | @ -427,8 +429,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||||||
| github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||||||
| github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||||||
| github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= | ||||||
| github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA= | github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= | ||||||
| github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= | github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= | ||||||
| github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | ||||||
| github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | ||||||
| github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								vendor/github.com/gabriel-vasile/mimetype/.gitattributes
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/gabriel-vasile/mimetype/.gitattributes
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | testdata/* linguist-vendored | ||||||
							
								
								
									
										76
									
								
								vendor/github.com/gabriel-vasile/mimetype/CODE_OF_CONDUCT.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								vendor/github.com/gabriel-vasile/mimetype/CODE_OF_CONDUCT.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | ||||||
|  | # Contributor Covenant Code of Conduct | ||||||
|  | 
 | ||||||
|  | ## Our Pledge | ||||||
|  | 
 | ||||||
|  | In the interest of fostering an open and welcoming environment, we as | ||||||
|  | contributors and maintainers pledge to making participation in our project and | ||||||
|  | our community a harassment-free experience for everyone, regardless of age, body | ||||||
|  | size, disability, ethnicity, sex characteristics, gender identity and expression, | ||||||
|  | level of experience, education, socio-economic status, nationality, personal | ||||||
|  | appearance, race, religion, or sexual identity and orientation. | ||||||
|  | 
 | ||||||
|  | ## Our Standards | ||||||
|  | 
 | ||||||
|  | Examples of behavior that contributes to creating a positive environment | ||||||
|  | include: | ||||||
|  | 
 | ||||||
|  | * Using welcoming and inclusive language | ||||||
|  | * Being respectful of differing viewpoints and experiences | ||||||
|  | * Gracefully accepting constructive criticism | ||||||
|  | * Focusing on what is best for the community | ||||||
|  | * Showing empathy towards other community members | ||||||
|  | 
 | ||||||
|  | Examples of unacceptable behavior by participants include: | ||||||
|  | 
 | ||||||
|  | * The use of sexualized language or imagery and unwelcome sexual attention or | ||||||
|  |  advances | ||||||
|  | * Trolling, insulting/derogatory comments, and personal or political attacks | ||||||
|  | * Public or private harassment | ||||||
|  | * Publishing others' private information, such as a physical or electronic | ||||||
|  |  address, without explicit permission | ||||||
|  | * Other conduct which could reasonably be considered inappropriate in a | ||||||
|  |  professional setting | ||||||
|  | 
 | ||||||
|  | ## Our Responsibilities | ||||||
|  | 
 | ||||||
|  | Project maintainers are responsible for clarifying the standards of acceptable | ||||||
|  | behavior and are expected to take appropriate and fair corrective action in | ||||||
|  | response to any instances of unacceptable behavior. | ||||||
|  | 
 | ||||||
|  | Project maintainers have the right and responsibility to remove, edit, or | ||||||
|  | reject comments, commits, code, wiki edits, issues, and other contributions | ||||||
|  | that are not aligned to this Code of Conduct, or to ban temporarily or | ||||||
|  | permanently any contributor for other behaviors that they deem inappropriate, | ||||||
|  | threatening, offensive, or harmful. | ||||||
|  | 
 | ||||||
|  | ## Scope | ||||||
|  | 
 | ||||||
|  | This Code of Conduct applies both within project spaces and in public spaces | ||||||
|  | when an individual is representing the project or its community. Examples of | ||||||
|  | representing a project or community include using an official project e-mail | ||||||
|  | address, posting via an official social media account, or acting as an appointed | ||||||
|  | representative at an online or offline event. Representation of a project may be | ||||||
|  | further defined and clarified by project maintainers. | ||||||
|  | 
 | ||||||
|  | ## Enforcement | ||||||
|  | 
 | ||||||
|  | Instances of abusive, harassing, or otherwise unacceptable behavior may be | ||||||
|  | reported by contacting the project team at vasile.gabriel@email.com. All | ||||||
|  | complaints will be reviewed and investigated and will result in a response that | ||||||
|  | is deemed necessary and appropriate to the circumstances. The project team is | ||||||
|  | obligated to maintain confidentiality with regard to the reporter of an incident. | ||||||
|  | Further details of specific enforcement policies may be posted separately. | ||||||
|  | 
 | ||||||
|  | Project maintainers who do not follow or enforce the Code of Conduct in good | ||||||
|  | faith may face temporary or permanent repercussions as determined by other | ||||||
|  | members of the project's leadership. | ||||||
|  | 
 | ||||||
|  | ## Attribution | ||||||
|  | 
 | ||||||
|  | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, | ||||||
|  | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html | ||||||
|  | 
 | ||||||
|  | [homepage]: https://www.contributor-covenant.org | ||||||
|  | 
 | ||||||
|  | For answers to common questions about this code of conduct, see | ||||||
|  | https://www.contributor-covenant.org/faq | ||||||
							
								
								
									
										12
									
								
								vendor/github.com/gabriel-vasile/mimetype/CONTRIBUTING.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/gabriel-vasile/mimetype/CONTRIBUTING.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | ## Contribute | ||||||
|  | Contributions to **mimetype** are welcome. If you find an issue and you consider | ||||||
|  | contributing, you can use the [Github issues tracker](https://github.com/gabriel-vasile/mimetype/issues) | ||||||
|  | in order to report it, or better yet, open a pull request. | ||||||
|  | 
 | ||||||
|  | Code contributions must respect these rules: | ||||||
|  |  - code must be test covered | ||||||
|  |  - code must be formatted using gofmt tool | ||||||
|  |  - exported names must be documented | ||||||
|  | 
 | ||||||
|  | **Important**: By submitting a pull request, you agree to allow the project | ||||||
|  | owner to license your work under the same license as that used by the project. | ||||||
							
								
								
									
										21
									
								
								vendor/github.com/gabriel-vasile/mimetype/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/gabriel-vasile/mimetype/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | MIT License | ||||||
|  | 
 | ||||||
|  | Copyright (c) 2018-2020 Gabriel Vasile | ||||||
|  | 
 | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  | 
 | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  | 
 | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
							
								
								
									
										108
									
								
								vendor/github.com/gabriel-vasile/mimetype/README.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								vendor/github.com/gabriel-vasile/mimetype/README.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,108 @@ | ||||||
|  | <h1 align="center"> | ||||||
|  |   mimetype | ||||||
|  | </h1> | ||||||
|  | 
 | ||||||
|  | <h4 align="center"> | ||||||
|  |   A package for detecting MIME types and extensions based on magic numbers | ||||||
|  | </h4> | ||||||
|  | <h6 align="center"> | ||||||
|  |   Goroutine safe, extensible, no C bindings | ||||||
|  | </h6> | ||||||
|  | 
 | ||||||
|  | <p align="center"> | ||||||
|  |   <a href="https://travis-ci.org/gabriel-vasile/mimetype"> | ||||||
|  |     <img alt="Build Status" src="https://travis-ci.org/gabriel-vasile/mimetype.svg?branch=master"> | ||||||
|  |   </a> | ||||||
|  |   <a href="https://pkg.go.dev/github.com/gabriel-vasile/mimetype"> | ||||||
|  |     <img alt="Go Reference" src="https://pkg.go.dev/badge/github.com/gabriel-vasile/mimetype.svg"> | ||||||
|  |   </a> | ||||||
|  |   <a href="https://goreportcard.com/report/github.com/gabriel-vasile/mimetype"> | ||||||
|  |     <img alt="Go report card" src="https://goreportcard.com/badge/github.com/gabriel-vasile/mimetype"> | ||||||
|  |   </a> | ||||||
|  |   <a href="https://codecov.io/gh/gabriel-vasile/mimetype"> | ||||||
|  |     <img alt="Code coverage" src="https://codecov.io/gh/gabriel-vasile/mimetype/branch/master/graph/badge.svg?token=qcfJF1kkl2"/> | ||||||
|  |   </a> | ||||||
|  |   <a href="LICENSE"> | ||||||
|  |     <img alt="License" src="https://img.shields.io/badge/License-MIT-green.svg"> | ||||||
|  |   </a> | ||||||
|  | </p> | ||||||
|  | 
 | ||||||
|  | ## Features | ||||||
|  | - fast and precise MIME type and file extension detection | ||||||
|  | - long list of [supported MIME types](supported_mimes.md) | ||||||
|  | - possibility to [extend](https://pkg.go.dev/github.com/gabriel-vasile/mimetype#example-package-Extend) with other file formats | ||||||
|  | - common file formats are prioritized | ||||||
|  | - [text vs. binary files differentiation](https://pkg.go.dev/github.com/gabriel-vasile/mimetype#example-package-TextVsBinary) | ||||||
|  | - safe for concurrent usage | ||||||
|  | 
 | ||||||
|  | ## Install | ||||||
|  | ```bash | ||||||
|  | go get github.com/gabriel-vasile/mimetype | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Usage | ||||||
|  | ```go | ||||||
|  | mtype := mimetype.Detect([]byte) | ||||||
|  | // OR | ||||||
|  | mtype, err := mimetype.DetectReader(io.Reader) | ||||||
|  | // OR | ||||||
|  | mtype, err := mimetype.DetectFile("/path/to/file") | ||||||
|  | fmt.Println(mtype.String(), mtype.Extension()) | ||||||
|  | ``` | ||||||
|  | See the [runnable Go Playground examples](https://pkg.go.dev/github.com/gabriel-vasile/mimetype#pkg-overview). | ||||||
|  | 
 | ||||||
|  | ## Usage' | ||||||
|  | Only use libraries like **mimetype** as a last resort. Content type detection | ||||||
|  | using magic numbers is slow, inaccurate, and non-standard. Most of the times | ||||||
|  | protocols have methods for specifying such metadata; e.g., `Content-Type` header | ||||||
|  | in HTTP and SMTP. | ||||||
|  | 
 | ||||||
|  | ## FAQ | ||||||
|  | Q: My file is in the list of [supported MIME types](supported_mimes.md) but | ||||||
|  | it is not correctly detected. What should I do? | ||||||
|  | 
 | ||||||
|  | A: Some file formats (often Microsoft Office documents) keep their signatures | ||||||
|  | towards the end of the file. Try increasing the number of bytes used for detection | ||||||
|  | with: | ||||||
|  | ```go | ||||||
|  | mimetype.SetLimit(1024*1024) // Set limit to 1MB. | ||||||
|  | // or | ||||||
|  | mimetype.SetLimit(0) // No limit, whole file content used. | ||||||
|  | mimetype.DetectFile("file.doc") | ||||||
|  | ``` | ||||||
|  | If increasing the limit does not help, please | ||||||
|  | [open an issue](https://github.com/gabriel-vasile/mimetype/issues/new?assignees=&labels=&template=mismatched-mime-type-detected.md&title=). | ||||||
|  | 
 | ||||||
|  | ## Structure | ||||||
|  | **mimetype** uses a hierarchical structure to keep the MIME type detection logic. | ||||||
|  | This reduces the number of calls needed for detecting the file type. The reason | ||||||
|  | behind this choice is that there are file formats used as containers for other | ||||||
|  | file formats. For example, Microsoft Office files are just zip archives, | ||||||
|  | containing specific metadata files. Once a file has been identified as a | ||||||
|  | zip, there is no need to check if it is a text file, but it is worth checking if | ||||||
|  | it is an Microsoft Office file. | ||||||
|  | 
 | ||||||
|  | To prevent loading entire files into memory, when detecting from a | ||||||
|  | [reader](https://pkg.go.dev/github.com/gabriel-vasile/mimetype#DetectReader) | ||||||
|  | or from a [file](https://pkg.go.dev/github.com/gabriel-vasile/mimetype#DetectFile) | ||||||
|  | **mimetype** limits itself to reading only the header of the input. | ||||||
|  | <div align="center"> | ||||||
|  |   <img alt="structure" src="https://github.com/gabriel-vasile/mimetype/blob/420a05228c6a6efbb6e6f080168a25663414ff36/mimetype.gif?raw=true" width="88%"> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | ## Performance | ||||||
|  | Thanks to the hierarchical structure, searching for common formats first, | ||||||
|  | and limiting itself to file headers, **mimetype** matches the performance of | ||||||
|  | stdlib `http.DetectContentType` while outperforming the alternative package. | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  |                             mimetype  http.DetectContentType      filetype | ||||||
|  | BenchmarkMatchTar-24       250 ns/op         400 ns/op           3778 ns/op | ||||||
|  | BenchmarkMatchZip-24       524 ns/op         351 ns/op           4884 ns/op | ||||||
|  | BenchmarkMatchJpeg-24      103 ns/op         228 ns/op            839 ns/op | ||||||
|  | BenchmarkMatchGif-24       139 ns/op         202 ns/op            751 ns/op | ||||||
|  | BenchmarkMatchPng-24       165 ns/op         221 ns/op           1176 ns/op | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Contributing | ||||||
|  | See [CONTRIBUTING.md](CONTRIBUTING.md). | ||||||
							
								
								
									
										309
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/charset/charset.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										309
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/charset/charset.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,309 @@ | ||||||
|  | package charset | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/xml" | ||||||
|  | 	"strings" | ||||||
|  | 	"unicode/utf8" | ||||||
|  | 
 | ||||||
|  | 	"golang.org/x/net/html" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	F = 0 /* character never appears in text */ | ||||||
|  | 	T = 1 /* character appears in plain ASCII text */ | ||||||
|  | 	I = 2 /* character appears in ISO-8859 text */ | ||||||
|  | 	X = 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */ | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	boms = []struct { | ||||||
|  | 		bom []byte | ||||||
|  | 		enc string | ||||||
|  | 	}{ | ||||||
|  | 		{[]byte{0xEF, 0xBB, 0xBF}, "utf-8"}, | ||||||
|  | 		{[]byte{0x00, 0x00, 0xFE, 0xFF}, "utf-32be"}, | ||||||
|  | 		{[]byte{0xFF, 0xFE, 0x00, 0x00}, "utf-32le"}, | ||||||
|  | 		{[]byte{0xFE, 0xFF}, "utf-16be"}, | ||||||
|  | 		{[]byte{0xFF, 0xFE}, "utf-16le"}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// https://github.com/file/file/blob/fa93fb9f7d21935f1c7644c47d2975d31f12b812/src/encoding.c#L241 | ||||||
|  | 	textChars = [256]byte{ | ||||||
|  | 		/*                  BEL BS HT LF VT FF CR    */ | ||||||
|  | 		F, F, F, F, F, F, F, T, T, T, T, T, T, T, F, F, /* 0x0X */ | ||||||
|  | 		/*                              ESC          */ | ||||||
|  | 		F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */ | ||||||
|  | 		T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */ | ||||||
|  | 		T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */ | ||||||
|  | 		T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */ | ||||||
|  | 		T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */ | ||||||
|  | 		T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */ | ||||||
|  | 		T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */ | ||||||
|  | 		/*            NEL                            */ | ||||||
|  | 		X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */ | ||||||
|  | 		X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */ | ||||||
|  | 		I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */ | ||||||
|  | 		I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */ | ||||||
|  | 		I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */ | ||||||
|  | 		I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */ | ||||||
|  | 		I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */ | ||||||
|  | 		I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xfX */ | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // FromBOM returns the charset declared in the BOM of content. | ||||||
|  | func FromBOM(content []byte) string { | ||||||
|  | 	for _, b := range boms { | ||||||
|  | 		if bytes.HasPrefix(content, b.bom) { | ||||||
|  | 			return b.enc | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FromPlain returns the charset of a plain text. It relies on BOM presence | ||||||
|  | // and it falls back on checking each byte in content. | ||||||
|  | func FromPlain(content []byte) string { | ||||||
|  | 	if len(content) == 0 { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	if cset := FromBOM(content); cset != "" { | ||||||
|  | 		return cset | ||||||
|  | 	} | ||||||
|  | 	origContent := content | ||||||
|  | 	// Try to detect UTF-8. | ||||||
|  | 	// First eliminate any partial rune at the end. | ||||||
|  | 	for i := len(content) - 1; i >= 0 && i > len(content)-4; i-- { | ||||||
|  | 		b := content[i] | ||||||
|  | 		if b < 0x80 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		if utf8.RuneStart(b) { | ||||||
|  | 			content = content[:i] | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	hasHighBit := false | ||||||
|  | 	for _, c := range content { | ||||||
|  | 		if c >= 0x80 { | ||||||
|  | 			hasHighBit = true | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if hasHighBit && utf8.Valid(content) { | ||||||
|  | 		return "utf-8" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// ASCII is a subset of UTF8. Follow W3C recommendation and replace with UTF8. | ||||||
|  | 	if ascii(origContent) { | ||||||
|  | 		return "utf-8" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return latin(origContent) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func latin(content []byte) string { | ||||||
|  | 	hasControlBytes := false | ||||||
|  | 	for _, b := range content { | ||||||
|  | 		t := textChars[b] | ||||||
|  | 		if t != T && t != I { | ||||||
|  | 			return "" | ||||||
|  | 		} | ||||||
|  | 		if b >= 0x80 && b <= 0x9F { | ||||||
|  | 			hasControlBytes = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// Code range 0x80 to 0x9F is reserved for control characters in ISO-8859-1 | ||||||
|  | 	// (so-called C1 Controls). Windows 1252, however, has printable punctuation | ||||||
|  | 	// characters in this range. | ||||||
|  | 	if hasControlBytes { | ||||||
|  | 		return "windows-1252" | ||||||
|  | 	} | ||||||
|  | 	return "iso-8859-1" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ascii(content []byte) bool { | ||||||
|  | 	for _, b := range content { | ||||||
|  | 		if textChars[b] != T { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FromXML returns the charset of an XML document. It relies on the XML | ||||||
|  | // header <?xml version="1.0" encoding="UTF-8"?> and falls back on the plain | ||||||
|  | // text content. | ||||||
|  | func FromXML(content []byte) string { | ||||||
|  | 	if cset := fromXML(content); cset != "" { | ||||||
|  | 		return cset | ||||||
|  | 	} | ||||||
|  | 	return FromPlain(content) | ||||||
|  | } | ||||||
|  | func fromXML(content []byte) string { | ||||||
|  | 	content = trimLWS(content) | ||||||
|  | 	dec := xml.NewDecoder(bytes.NewReader(content)) | ||||||
|  | 	rawT, err := dec.RawToken() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	t, ok := rawT.(xml.ProcInst) | ||||||
|  | 	if !ok { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return strings.ToLower(xmlEncoding(string(t.Inst))) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FromHTML returns the charset of an HTML document. It first looks if a BOM is | ||||||
|  | // present and if so uses it to determine the charset. If no BOM is present, | ||||||
|  | // it relies on the meta tag <meta charset="UTF-8"> and falls back on the | ||||||
|  | // plain text content. | ||||||
|  | func FromHTML(content []byte) string { | ||||||
|  | 	if cset := FromBOM(content); cset != "" { | ||||||
|  | 		return cset | ||||||
|  | 	} | ||||||
|  | 	if cset := fromHTML(content); cset != "" { | ||||||
|  | 		return cset | ||||||
|  | 	} | ||||||
|  | 	return FromPlain(content) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func fromHTML(content []byte) string { | ||||||
|  | 	z := html.NewTokenizer(bytes.NewReader(content)) | ||||||
|  | 	for { | ||||||
|  | 		switch z.Next() { | ||||||
|  | 		case html.ErrorToken: | ||||||
|  | 			return "" | ||||||
|  | 
 | ||||||
|  | 		case html.StartTagToken, html.SelfClosingTagToken: | ||||||
|  | 			tagName, hasAttr := z.TagName() | ||||||
|  | 			if !bytes.Equal(tagName, []byte("meta")) { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			attrList := make(map[string]bool) | ||||||
|  | 			gotPragma := false | ||||||
|  | 
 | ||||||
|  | 			const ( | ||||||
|  | 				dontKnow = iota | ||||||
|  | 				doNeedPragma | ||||||
|  | 				doNotNeedPragma | ||||||
|  | 			) | ||||||
|  | 			needPragma := dontKnow | ||||||
|  | 
 | ||||||
|  | 			name := "" | ||||||
|  | 			for hasAttr { | ||||||
|  | 				var key, val []byte | ||||||
|  | 				key, val, hasAttr = z.TagAttr() | ||||||
|  | 				ks := string(key) | ||||||
|  | 				if attrList[ks] { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 				attrList[ks] = true | ||||||
|  | 				for i, c := range val { | ||||||
|  | 					if 'A' <= c && c <= 'Z' { | ||||||
|  | 						val[i] = c + 0x20 | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				switch ks { | ||||||
|  | 				case "http-equiv": | ||||||
|  | 					if bytes.Equal(val, []byte("content-type")) { | ||||||
|  | 						gotPragma = true | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 				case "content": | ||||||
|  | 					name = fromMetaElement(string(val)) | ||||||
|  | 					if name != "" { | ||||||
|  | 						needPragma = doNeedPragma | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 				case "charset": | ||||||
|  | 					name = string(val) | ||||||
|  | 					needPragma = doNotNeedPragma | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if needPragma == dontKnow || needPragma == doNeedPragma && !gotPragma { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if strings.HasPrefix(name, "utf-16") { | ||||||
|  | 				name = "utf-8" | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return name | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func fromMetaElement(s string) string { | ||||||
|  | 	for s != "" { | ||||||
|  | 		csLoc := strings.Index(s, "charset") | ||||||
|  | 		if csLoc == -1 { | ||||||
|  | 			return "" | ||||||
|  | 		} | ||||||
|  | 		s = s[csLoc+len("charset"):] | ||||||
|  | 		s = strings.TrimLeft(s, " \t\n\f\r") | ||||||
|  | 		if !strings.HasPrefix(s, "=") { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		s = s[1:] | ||||||
|  | 		s = strings.TrimLeft(s, " \t\n\f\r") | ||||||
|  | 		if s == "" { | ||||||
|  | 			return "" | ||||||
|  | 		} | ||||||
|  | 		if q := s[0]; q == '"' || q == '\'' { | ||||||
|  | 			s = s[1:] | ||||||
|  | 			closeQuote := strings.IndexRune(s, rune(q)) | ||||||
|  | 			if closeQuote == -1 { | ||||||
|  | 				return "" | ||||||
|  | 			} | ||||||
|  | 			return s[:closeQuote] | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		end := strings.IndexAny(s, "; \t\n\f\r") | ||||||
|  | 		if end == -1 { | ||||||
|  | 			end = len(s) | ||||||
|  | 		} | ||||||
|  | 		return s[:end] | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func xmlEncoding(s string) string { | ||||||
|  | 	param := "encoding=" | ||||||
|  | 	idx := strings.Index(s, param) | ||||||
|  | 	if idx == -1 { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	v := s[idx+len(param):] | ||||||
|  | 	if v == "" { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	if v[0] != '\'' && v[0] != '"' { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	idx = strings.IndexRune(v[1:], rune(v[0])) | ||||||
|  | 	if idx == -1 { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	return v[1 : idx+1] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // trimLWS trims whitespace from beginning of the input. | ||||||
|  | // TODO: find a way to call trimLWS once per detection instead of once in each | ||||||
|  | // detector which needs the trimmed input. | ||||||
|  | func trimLWS(in []byte) []byte { | ||||||
|  | 	firstNonWS := 0 | ||||||
|  | 	for ; firstNonWS < len(in) && isWS(in[firstNonWS]); firstNonWS++ { | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return in[firstNonWS:] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func isWS(b byte) bool { | ||||||
|  | 	return b == '\t' || b == '\n' || b == '\x0c' || b == '\r' || b == ' ' | ||||||
|  | } | ||||||
							
								
								
									
										544
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/json/json.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										544
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/json/json.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,544 @@ | ||||||
|  | // Copyright (c) 2009 The Go Authors. All rights reserved. | ||||||
|  | // | ||||||
|  | // Redistribution and use in source and binary forms, with or without | ||||||
|  | // modification, are permitted provided that the following conditions are | ||||||
|  | // met: | ||||||
|  | // | ||||||
|  | //    * Redistributions of source code must retain the above copyright | ||||||
|  | // notice, this list of conditions and the following disclaimer. | ||||||
|  | //    * Redistributions in binary form must reproduce the above | ||||||
|  | // copyright notice, this list of conditions and the following disclaimer | ||||||
|  | // in the documentation and/or other materials provided with the | ||||||
|  | // distribution. | ||||||
|  | //    * Neither the name of Google Inc. nor the names of its | ||||||
|  | // contributors may be used to endorse or promote products derived from | ||||||
|  | // this software without specific prior written permission. | ||||||
|  | // | ||||||
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | 
 | ||||||
|  | // Package json provides a JSON value parser state machine. | ||||||
|  | // This package is almost entirely copied from the Go stdlib. | ||||||
|  | // Changes made to it permit users of the package to tell | ||||||
|  | // if some slice of bytes is a valid beginning of a json string. | ||||||
|  | package json | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type ( | ||||||
|  | 	scanStatus int | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	parseObjectKey   = iota // parsing object key (before colon) | ||||||
|  | 	parseObjectValue        // parsing object value (after colon) | ||||||
|  | 	parseArrayValue         // parsing array value | ||||||
|  | 
 | ||||||
|  | 	scanContinue     scanStatus = iota // uninteresting byte | ||||||
|  | 	scanBeginLiteral                   // end implied by next result != scanContinue | ||||||
|  | 	scanBeginObject                    // begin object | ||||||
|  | 	scanObjectKey                      // just finished object key (string) | ||||||
|  | 	scanObjectValue                    // just finished non-last object value | ||||||
|  | 	scanEndObject                      // end object (implies scanObjectValue if possible) | ||||||
|  | 	scanBeginArray                     // begin array | ||||||
|  | 	scanArrayValue                     // just finished array value | ||||||
|  | 	scanEndArray                       // end array (implies scanArrayValue if possible) | ||||||
|  | 	scanSkipSpace                      // space byte; can skip; known to be last "continue" result | ||||||
|  | 	scanEnd                            // top-level value ended *before* this byte; known to be first "stop" result | ||||||
|  | 	scanError                          // hit an error, scanner.err. | ||||||
|  | 
 | ||||||
|  | 	// This limits the max nesting depth to prevent stack overflow. | ||||||
|  | 	// This is permitted by https://tools.ietf.org/html/rfc7159#section-9 | ||||||
|  | 	maxNestingDepth = 10000 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type ( | ||||||
|  | 	scanner struct { | ||||||
|  | 		step       func(*scanner, byte) scanStatus | ||||||
|  | 		parseState []int | ||||||
|  | 		endTop     bool | ||||||
|  | 		err        error | ||||||
|  | 		index      int | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Scan returns the number of bytes scanned and if there was any error | ||||||
|  | // in trying to reach the end of data. | ||||||
|  | func Scan(data []byte) (int, error) { | ||||||
|  | 	s := &scanner{} | ||||||
|  | 	_ = checkValid(data, s) | ||||||
|  | 	return s.index, s.err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // checkValid verifies that data is valid JSON-encoded data. | ||||||
|  | // scan is passed in for use by checkValid to avoid an allocation. | ||||||
|  | func checkValid(data []byte, scan *scanner) error { | ||||||
|  | 	scan.reset() | ||||||
|  | 	for _, c := range data { | ||||||
|  | 		scan.index++ | ||||||
|  | 		if scan.step(scan, c) == scanError { | ||||||
|  | 			return scan.err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if scan.eof() == scanError { | ||||||
|  | 		return scan.err | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func isSpace(c byte) bool { | ||||||
|  | 	return c == ' ' || c == '\t' || c == '\r' || c == '\n' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *scanner) reset() { | ||||||
|  | 	s.step = stateBeginValue | ||||||
|  | 	s.parseState = s.parseState[0:0] | ||||||
|  | 	s.err = nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // eof tells the scanner that the end of input has been reached. | ||||||
|  | // It returns a scan status just as s.step does. | ||||||
|  | func (s *scanner) eof() scanStatus { | ||||||
|  | 	if s.err != nil { | ||||||
|  | 		return scanError | ||||||
|  | 	} | ||||||
|  | 	if s.endTop { | ||||||
|  | 		return scanEnd | ||||||
|  | 	} | ||||||
|  | 	s.step(s, ' ') | ||||||
|  | 	if s.endTop { | ||||||
|  | 		return scanEnd | ||||||
|  | 	} | ||||||
|  | 	if s.err == nil { | ||||||
|  | 		s.err = fmt.Errorf("unexpected end of JSON input") | ||||||
|  | 	} | ||||||
|  | 	return scanError | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // pushParseState pushes a new parse state p onto the parse stack. | ||||||
|  | // an error state is returned if maxNestingDepth was exceeded, otherwise successState is returned. | ||||||
|  | func (s *scanner) pushParseState(c byte, newParseState int, successState scanStatus) scanStatus { | ||||||
|  | 	s.parseState = append(s.parseState, newParseState) | ||||||
|  | 	if len(s.parseState) <= maxNestingDepth { | ||||||
|  | 		return successState | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "exceeded max depth") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // popParseState pops a parse state (already obtained) off the stack | ||||||
|  | // and updates s.step accordingly. | ||||||
|  | func (s *scanner) popParseState() { | ||||||
|  | 	n := len(s.parseState) - 1 | ||||||
|  | 	s.parseState = s.parseState[0:n] | ||||||
|  | 	if n == 0 { | ||||||
|  | 		s.step = stateEndTop | ||||||
|  | 		s.endTop = true | ||||||
|  | 	} else { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateBeginValueOrEmpty is the state after reading `[`. | ||||||
|  | func stateBeginValueOrEmpty(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	if c == ']' { | ||||||
|  | 		return stateEndValue(s, c) | ||||||
|  | 	} | ||||||
|  | 	return stateBeginValue(s, c) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateBeginValue is the state at the beginning of the input. | ||||||
|  | func stateBeginValue(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	switch c { | ||||||
|  | 	case '{': | ||||||
|  | 		s.step = stateBeginStringOrEmpty | ||||||
|  | 		return s.pushParseState(c, parseObjectKey, scanBeginObject) | ||||||
|  | 	case '[': | ||||||
|  | 		s.step = stateBeginValueOrEmpty | ||||||
|  | 		return s.pushParseState(c, parseArrayValue, scanBeginArray) | ||||||
|  | 	case '"': | ||||||
|  | 		s.step = stateInString | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	case '-': | ||||||
|  | 		s.step = stateNeg | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	case '0': // beginning of 0.123 | ||||||
|  | 		s.step = state0 | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	case 't': // beginning of true | ||||||
|  | 		s.step = stateT | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	case 'f': // beginning of false | ||||||
|  | 		s.step = stateF | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	case 'n': // beginning of null | ||||||
|  | 		s.step = stateN | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	} | ||||||
|  | 	if '1' <= c && c <= '9' { // beginning of 1234.5 | ||||||
|  | 		s.step = state1 | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "looking for beginning of value") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateBeginStringOrEmpty is the state after reading `{`. | ||||||
|  | func stateBeginStringOrEmpty(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	if c == '}' { | ||||||
|  | 		n := len(s.parseState) | ||||||
|  | 		s.parseState[n-1] = parseObjectValue | ||||||
|  | 		return stateEndValue(s, c) | ||||||
|  | 	} | ||||||
|  | 	return stateBeginString(s, c) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateBeginString is the state after reading `{"key": value,`. | ||||||
|  | func stateBeginString(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	if c == '"' { | ||||||
|  | 		s.step = stateInString | ||||||
|  | 		return scanBeginLiteral | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "looking for beginning of object key string") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateEndValue is the state after completing a value, | ||||||
|  | // such as after reading `{}` or `true` or `["x"`. | ||||||
|  | func stateEndValue(s *scanner, c byte) scanStatus { | ||||||
|  | 	n := len(s.parseState) | ||||||
|  | 	if n == 0 { | ||||||
|  | 		// Completed top-level before the current byte. | ||||||
|  | 		s.step = stateEndTop | ||||||
|  | 		s.endTop = true | ||||||
|  | 		return stateEndTop(s, c) | ||||||
|  | 	} | ||||||
|  | 	if c <= ' ' && isSpace(c) { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 		return scanSkipSpace | ||||||
|  | 	} | ||||||
|  | 	ps := s.parseState[n-1] | ||||||
|  | 	switch ps { | ||||||
|  | 	case parseObjectKey: | ||||||
|  | 		if c == ':' { | ||||||
|  | 			s.parseState[n-1] = parseObjectValue | ||||||
|  | 			s.step = stateBeginValue | ||||||
|  | 			return scanObjectKey | ||||||
|  | 		} | ||||||
|  | 		return s.error(c, "after object key") | ||||||
|  | 	case parseObjectValue: | ||||||
|  | 		if c == ',' { | ||||||
|  | 			s.parseState[n-1] = parseObjectKey | ||||||
|  | 			s.step = stateBeginString | ||||||
|  | 			return scanObjectValue | ||||||
|  | 		} | ||||||
|  | 		if c == '}' { | ||||||
|  | 			s.popParseState() | ||||||
|  | 			return scanEndObject | ||||||
|  | 		} | ||||||
|  | 		return s.error(c, "after object key:value pair") | ||||||
|  | 	case parseArrayValue: | ||||||
|  | 		if c == ',' { | ||||||
|  | 			s.step = stateBeginValue | ||||||
|  | 			return scanArrayValue | ||||||
|  | 		} | ||||||
|  | 		if c == ']' { | ||||||
|  | 			s.popParseState() | ||||||
|  | 			return scanEndArray | ||||||
|  | 		} | ||||||
|  | 		return s.error(c, "after array element") | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateEndTop is the state after finishing the top-level value, | ||||||
|  | // such as after reading `{}` or `[1,2,3]`. | ||||||
|  | // Only space characters should be seen now. | ||||||
|  | func stateEndTop(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c != ' ' && c != '\t' && c != '\r' && c != '\n' { | ||||||
|  | 		// Complain about non-space byte on next call. | ||||||
|  | 		s.error(c, "after top-level value") | ||||||
|  | 	} | ||||||
|  | 	return scanEnd | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateInString is the state after reading `"`. | ||||||
|  | func stateInString(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == '"' { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if c == '\\' { | ||||||
|  | 		s.step = stateInStringEsc | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if c < 0x20 { | ||||||
|  | 		return s.error(c, "in string literal") | ||||||
|  | 	} | ||||||
|  | 	return scanContinue | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateInStringEsc is the state after reading `"\` during a quoted string. | ||||||
|  | func stateInStringEsc(s *scanner, c byte) scanStatus { | ||||||
|  | 	switch c { | ||||||
|  | 	case 'b', 'f', 'n', 'r', 't', '\\', '/', '"': | ||||||
|  | 		s.step = stateInString | ||||||
|  | 		return scanContinue | ||||||
|  | 	case 'u': | ||||||
|  | 		s.step = stateInStringEscU | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in string escape code") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateInStringEscU is the state after reading `"\u` during a quoted string. | ||||||
|  | func stateInStringEscU(s *scanner, c byte) scanStatus { | ||||||
|  | 	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | ||||||
|  | 		s.step = stateInStringEscU1 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	// numbers | ||||||
|  | 	return s.error(c, "in \\u hexadecimal character escape") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateInStringEscU1 is the state after reading `"\u1` during a quoted string. | ||||||
|  | func stateInStringEscU1(s *scanner, c byte) scanStatus { | ||||||
|  | 	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | ||||||
|  | 		s.step = stateInStringEscU12 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	// numbers | ||||||
|  | 	return s.error(c, "in \\u hexadecimal character escape") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateInStringEscU12 is the state after reading `"\u12` during a quoted string. | ||||||
|  | func stateInStringEscU12(s *scanner, c byte) scanStatus { | ||||||
|  | 	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | ||||||
|  | 		s.step = stateInStringEscU123 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	// numbers | ||||||
|  | 	return s.error(c, "in \\u hexadecimal character escape") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateInStringEscU123 is the state after reading `"\u123` during a quoted string. | ||||||
|  | func stateInStringEscU123(s *scanner, c byte) scanStatus { | ||||||
|  | 	if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { | ||||||
|  | 		s.step = stateInString | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	// numbers | ||||||
|  | 	return s.error(c, "in \\u hexadecimal character escape") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateNeg is the state after reading `-` during a number. | ||||||
|  | func stateNeg(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == '0' { | ||||||
|  | 		s.step = state0 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if '1' <= c && c <= '9' { | ||||||
|  | 		s.step = state1 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in numeric literal") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // state1 is the state after reading a non-zero integer during a number, | ||||||
|  | // such as after reading `1` or `100` but not `0`. | ||||||
|  | func state1(s *scanner, c byte) scanStatus { | ||||||
|  | 	if '0' <= c && c <= '9' { | ||||||
|  | 		s.step = state1 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return state0(s, c) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // state0 is the state after reading `0` during a number. | ||||||
|  | func state0(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == '.' { | ||||||
|  | 		s.step = stateDot | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if c == 'e' || c == 'E' { | ||||||
|  | 		s.step = stateE | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return stateEndValue(s, c) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateDot is the state after reading the integer and decimal point in a number, | ||||||
|  | // such as after reading `1.`. | ||||||
|  | func stateDot(s *scanner, c byte) scanStatus { | ||||||
|  | 	if '0' <= c && c <= '9' { | ||||||
|  | 		s.step = stateDot0 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "after decimal point in numeric literal") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateDot0 is the state after reading the integer, decimal point, and subsequent | ||||||
|  | // digits of a number, such as after reading `3.14`. | ||||||
|  | func stateDot0(s *scanner, c byte) scanStatus { | ||||||
|  | 	if '0' <= c && c <= '9' { | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	if c == 'e' || c == 'E' { | ||||||
|  | 		s.step = stateE | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return stateEndValue(s, c) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateE is the state after reading the mantissa and e in a number, | ||||||
|  | // such as after reading `314e` or `0.314e`. | ||||||
|  | func stateE(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == '+' || c == '-' { | ||||||
|  | 		s.step = stateESign | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return stateESign(s, c) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateESign is the state after reading the mantissa, e, and sign in a number, | ||||||
|  | // such as after reading `314e-` or `0.314e+`. | ||||||
|  | func stateESign(s *scanner, c byte) scanStatus { | ||||||
|  | 	if '0' <= c && c <= '9' { | ||||||
|  | 		s.step = stateE0 | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in exponent of numeric literal") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateE0 is the state after reading the mantissa, e, optional sign, | ||||||
|  | // and at least one digit of the exponent in a number, | ||||||
|  | // such as after reading `314e-2` or `0.314e+1` or `3.14e0`. | ||||||
|  | func stateE0(s *scanner, c byte) scanStatus { | ||||||
|  | 	if '0' <= c && c <= '9' { | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return stateEndValue(s, c) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateT is the state after reading `t`. | ||||||
|  | func stateT(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == 'r' { | ||||||
|  | 		s.step = stateTr | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal true (expecting 'r')") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateTr is the state after reading `tr`. | ||||||
|  | func stateTr(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == 'u' { | ||||||
|  | 		s.step = stateTru | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal true (expecting 'u')") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateTru is the state after reading `tru`. | ||||||
|  | func stateTru(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == 'e' { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal true (expecting 'e')") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateF is the state after reading `f`. | ||||||
|  | func stateF(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == 'a' { | ||||||
|  | 		s.step = stateFa | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal false (expecting 'a')") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateFa is the state after reading `fa`. | ||||||
|  | func stateFa(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == 'l' { | ||||||
|  | 		s.step = stateFal | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal false (expecting 'l')") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateFal is the state after reading `fal`. | ||||||
|  | func stateFal(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == 's' { | ||||||
|  | 		s.step = stateFals | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal false (expecting 's')") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateFals is the state after reading `fals`. | ||||||
|  | func stateFals(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == 'e' { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal false (expecting 'e')") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateN is the state after reading `n`. | ||||||
|  | func stateN(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == 'u' { | ||||||
|  | 		s.step = stateNu | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal null (expecting 'u')") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateNu is the state after reading `nu`. | ||||||
|  | func stateNu(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == 'l' { | ||||||
|  | 		s.step = stateNul | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal null (expecting 'l')") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateNul is the state after reading `nul`. | ||||||
|  | func stateNul(s *scanner, c byte) scanStatus { | ||||||
|  | 	if c == 'l' { | ||||||
|  | 		s.step = stateEndValue | ||||||
|  | 		return scanContinue | ||||||
|  | 	} | ||||||
|  | 	return s.error(c, "in literal null (expecting 'l')") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // stateError is the state after reaching a syntax error, | ||||||
|  | // such as after reading `[1}` or `5.1.2`. | ||||||
|  | func stateError(s *scanner, c byte) scanStatus { | ||||||
|  | 	return scanError | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // error records an error and switches to the error state. | ||||||
|  | func (s *scanner) error(c byte, context string) scanStatus { | ||||||
|  | 	s.step = stateError | ||||||
|  | 	s.err = fmt.Errorf("invalid character <<%c>> %s", c, context) | ||||||
|  | 	return scanError | ||||||
|  | } | ||||||
							
								
								
									
										124
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/archive.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/archive.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,124 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// SevenZ matches a 7z archive. | ||||||
|  | 	SevenZ = prefix([]byte{0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C}) | ||||||
|  | 	// Gzip matches gzip files based on http://www.zlib.org/rfc-gzip.html#header-trailer. | ||||||
|  | 	Gzip = prefix([]byte{0x1f, 0x8b}) | ||||||
|  | 	// Fits matches an Flexible Image Transport System file. | ||||||
|  | 	Fits = prefix([]byte{ | ||||||
|  | 		0x53, 0x49, 0x4D, 0x50, 0x4C, 0x45, 0x20, 0x20, 0x3D, 0x20, | ||||||
|  | 		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||||||
|  | 		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, | ||||||
|  | 	}) | ||||||
|  | 	// Xar matches an eXtensible ARchive format file. | ||||||
|  | 	Xar = prefix([]byte{0x78, 0x61, 0x72, 0x21}) | ||||||
|  | 	// Bz2 matches a bzip2 file. | ||||||
|  | 	Bz2 = prefix([]byte{0x42, 0x5A, 0x68}) | ||||||
|  | 	// Ar matches an ar (Unix) archive file. | ||||||
|  | 	Ar = prefix([]byte{0x21, 0x3C, 0x61, 0x72, 0x63, 0x68, 0x3E}) | ||||||
|  | 	// Deb matches a Debian package file. | ||||||
|  | 	Deb = offset([]byte{ | ||||||
|  | 		0x64, 0x65, 0x62, 0x69, 0x61, 0x6E, 0x2D, | ||||||
|  | 		0x62, 0x69, 0x6E, 0x61, 0x72, 0x79, | ||||||
|  | 	}, 8) | ||||||
|  | 	// Warc matches a Web ARChive file. | ||||||
|  | 	Warc = prefix([]byte("WARC/1.0"), []byte("WARC/1.1")) | ||||||
|  | 	// Cab matches a Microsoft Cabinet archive file. | ||||||
|  | 	Cab = prefix([]byte("MSCF\x00\x00\x00\x00")) | ||||||
|  | 	// Xz matches an xz compressed stream based on https://tukaani.org/xz/xz-file-format.txt. | ||||||
|  | 	Xz = prefix([]byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00}) | ||||||
|  | 	// Lzip matches an Lzip compressed file. | ||||||
|  | 	Lzip = prefix([]byte{0x4c, 0x5a, 0x49, 0x50}) | ||||||
|  | 	// RPM matches an RPM or Delta RPM package file. | ||||||
|  | 	RPM = prefix([]byte{0xed, 0xab, 0xee, 0xdb}, []byte("drpm")) | ||||||
|  | 	// Cpio matches a cpio archive file. | ||||||
|  | 	Cpio = prefix([]byte("070707"), []byte("070701"), []byte("070702")) | ||||||
|  | 	// RAR matches a RAR archive file. | ||||||
|  | 	RAR = prefix([]byte("Rar!\x1A\x07\x00"), []byte("Rar!\x1A\x07\x01\x00")) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // InstallShieldCab matches an InstallShield Cabinet archive file. | ||||||
|  | func InstallShieldCab(raw []byte, _ uint32) bool { | ||||||
|  | 	return len(raw) > 7 && | ||||||
|  | 		bytes.Equal(raw[0:4], []byte("ISc(")) && | ||||||
|  | 		raw[6] == 0 && | ||||||
|  | 		(raw[7] == 1 || raw[7] == 2 || raw[7] == 4) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Zstd matches a Zstandard archive file. | ||||||
|  | func Zstd(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) >= 4 && | ||||||
|  | 		(0x22 <= raw[0] && raw[0] <= 0x28 || raw[0] == 0x1E) && // Different Zstandard versions. | ||||||
|  | 		bytes.HasPrefix(raw[1:], []byte{0xB5, 0x2F, 0xFD}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // CRX matches a Chrome extension file: a zip archive prepended by a package header. | ||||||
|  | func CRX(raw []byte, limit uint32) bool { | ||||||
|  | 	const minHeaderLen = 16 | ||||||
|  | 	if len(raw) < minHeaderLen || !bytes.HasPrefix(raw, []byte("Cr24")) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	pubkeyLen := binary.LittleEndian.Uint32(raw[8:12]) | ||||||
|  | 	sigLen := binary.LittleEndian.Uint32(raw[12:16]) | ||||||
|  | 	zipOffset := minHeaderLen + pubkeyLen + sigLen | ||||||
|  | 	if uint32(len(raw)) < zipOffset { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return Zip(raw[zipOffset:], limit) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Tar matches a (t)ape (ar)chive file. | ||||||
|  | func Tar(raw []byte, _ uint32) bool { | ||||||
|  | 	// The "magic" header field for files in in UStar (POSIX IEEE P1003.1) archives | ||||||
|  | 	// has the prefix "ustar". The values of the remaining bytes in this field vary | ||||||
|  | 	// by archiver implementation. | ||||||
|  | 	if len(raw) >= 512 && bytes.HasPrefix(raw[257:], []byte{0x75, 0x73, 0x74, 0x61, 0x72}) { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(raw) < 256 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// The older v7 format has no "magic" field, and therefore must be identified | ||||||
|  | 	// with heuristics based on legal ranges of values for other header fields: | ||||||
|  | 	// https://www.nationalarchives.gov.uk/PRONOM/Format/proFormatSearch.aspx?status=detailReport&id=385&strPageToDisplay=signatures | ||||||
|  | 	rules := []struct { | ||||||
|  | 		min, max uint8 | ||||||
|  | 		i        int | ||||||
|  | 	}{ | ||||||
|  | 		{0x21, 0xEF, 0}, | ||||||
|  | 		{0x30, 0x37, 105}, | ||||||
|  | 		{0x20, 0x37, 106}, | ||||||
|  | 		{0x00, 0x00, 107}, | ||||||
|  | 		{0x30, 0x37, 113}, | ||||||
|  | 		{0x20, 0x37, 114}, | ||||||
|  | 		{0x00, 0x00, 115}, | ||||||
|  | 		{0x30, 0x37, 121}, | ||||||
|  | 		{0x20, 0x37, 122}, | ||||||
|  | 		{0x00, 0x00, 123}, | ||||||
|  | 		{0x30, 0x37, 134}, | ||||||
|  | 		{0x30, 0x37, 146}, | ||||||
|  | 		{0x30, 0x37, 153}, | ||||||
|  | 		{0x00, 0x37, 154}, | ||||||
|  | 	} | ||||||
|  | 	for _, r := range rules { | ||||||
|  | 		if raw[r.i] < r.min || raw[r.i] > r.max { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, i := range []uint8{135, 147, 155} { | ||||||
|  | 		if raw[i] != 0x00 && raw[i] != 0x20 { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true | ||||||
|  | } | ||||||
							
								
								
									
										76
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/audio.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/audio.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// Flac matches a Free Lossless Audio Codec file. | ||||||
|  | 	Flac = prefix([]byte("\x66\x4C\x61\x43\x00\x00\x00\x22")) | ||||||
|  | 	// Midi matches a Musical Instrument Digital Interface file. | ||||||
|  | 	Midi = prefix([]byte("\x4D\x54\x68\x64")) | ||||||
|  | 	// Ape matches a Monkey's Audio file. | ||||||
|  | 	Ape = prefix([]byte("\x4D\x41\x43\x20\x96\x0F\x00\x00\x34\x00\x00\x00\x18\x00\x00\x00\x90\xE3")) | ||||||
|  | 	// MusePack matches a Musepack file. | ||||||
|  | 	MusePack = prefix([]byte("MPCK")) | ||||||
|  | 	// Au matches a Sun Microsystems au file. | ||||||
|  | 	Au = prefix([]byte("\x2E\x73\x6E\x64")) | ||||||
|  | 	// Amr matches an Adaptive Multi-Rate file. | ||||||
|  | 	Amr = prefix([]byte("\x23\x21\x41\x4D\x52")) | ||||||
|  | 	// Voc matches a Creative Voice file. | ||||||
|  | 	Voc = prefix([]byte("Creative Voice File")) | ||||||
|  | 	// M3u matches a Playlist file. | ||||||
|  | 	M3u = prefix([]byte("#EXTM3U")) | ||||||
|  | 	// AAC matches an Advanced Audio Coding file. | ||||||
|  | 	AAC = prefix([]byte{0xFF, 0xF1}, []byte{0xFF, 0xF9}) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Mp3 matches an mp3 file. | ||||||
|  | func Mp3(raw []byte, limit uint32) bool { | ||||||
|  | 	if len(raw) < 3 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if bytes.HasPrefix(raw, []byte("ID3")) { | ||||||
|  | 		// MP3s with an ID3v2 tag will start with "ID3" | ||||||
|  | 		// ID3v1 tags, however appear at the end of the file. | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Match MP3 files without tags | ||||||
|  | 	switch binary.BigEndian.Uint16(raw[:2]) & 0xFFFE { | ||||||
|  | 	case 0xFFFA: | ||||||
|  | 		// MPEG ADTS, layer III, v1 | ||||||
|  | 		return true | ||||||
|  | 	case 0xFFF2: | ||||||
|  | 		// MPEG ADTS, layer III, v2 | ||||||
|  | 		return true | ||||||
|  | 	case 0xFFE2: | ||||||
|  | 		// MPEG ADTS, layer III, v2.5 | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Wav matches a Waveform Audio File Format file. | ||||||
|  | func Wav(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 12 && | ||||||
|  | 		bytes.Equal(raw[:4], []byte("RIFF")) && | ||||||
|  | 		bytes.Equal(raw[8:12], []byte{0x57, 0x41, 0x56, 0x45}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Aiff matches Audio Interchange File Format file. | ||||||
|  | func Aiff(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 12 && | ||||||
|  | 		bytes.Equal(raw[:4], []byte{0x46, 0x4F, 0x52, 0x4D}) && | ||||||
|  | 		bytes.Equal(raw[8:12], []byte{0x41, 0x49, 0x46, 0x46}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Qcp matches a Qualcomm Pure Voice file. | ||||||
|  | func Qcp(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 12 && | ||||||
|  | 		bytes.Equal(raw[:4], []byte("RIFF")) && | ||||||
|  | 		bytes.Equal(raw[8:12], []byte("QLCM")) | ||||||
|  | } | ||||||
							
								
								
									
										196
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/binary.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/binary.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,196 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"debug/macho" | ||||||
|  | 	"encoding/binary" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// Lnk matches Microsoft lnk binary format. | ||||||
|  | 	Lnk = prefix([]byte{0x4C, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00}) | ||||||
|  | 	// Wasm matches a web assembly File Format file. | ||||||
|  | 	Wasm = prefix([]byte{0x00, 0x61, 0x73, 0x6D}) | ||||||
|  | 	// Exe matches a Windows/DOS executable file. | ||||||
|  | 	Exe = prefix([]byte{0x4D, 0x5A}) | ||||||
|  | 	// Elf matches an Executable and Linkable Format file. | ||||||
|  | 	Elf = prefix([]byte{0x7F, 0x45, 0x4C, 0x46}) | ||||||
|  | 	// Nes matches a Nintendo Entertainment system ROM file. | ||||||
|  | 	Nes = prefix([]byte{0x4E, 0x45, 0x53, 0x1A}) | ||||||
|  | 	// SWF matches an Adobe Flash swf file. | ||||||
|  | 	SWF = prefix([]byte("CWS"), []byte("FWS"), []byte("ZWS")) | ||||||
|  | 	// Torrent has bencoded text in the beginning. | ||||||
|  | 	Torrent = prefix([]byte("d8:announce")) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Java bytecode and Mach-O binaries share the same magic number. | ||||||
|  | // More info here https://github.com/threatstack/libmagic/blob/master/magic/Magdir/cafebabe | ||||||
|  | func classOrMachOFat(in []byte) bool { | ||||||
|  | 	// There should be at least 8 bytes for both of them because the only way to | ||||||
|  | 	// quickly distinguish them is by comparing byte at position 7 | ||||||
|  | 	if len(in) < 8 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return bytes.HasPrefix(in, []byte{0xCA, 0xFE, 0xBA, 0xBE}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Class matches a java class file. | ||||||
|  | func Class(raw []byte, limit uint32) bool { | ||||||
|  | 	return classOrMachOFat(raw) && raw[7] > 30 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // MachO matches Mach-O binaries format. | ||||||
|  | func MachO(raw []byte, limit uint32) bool { | ||||||
|  | 	if classOrMachOFat(raw) && raw[7] < 20 { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if len(raw) < 4 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	be := binary.BigEndian.Uint32(raw) | ||||||
|  | 	le := binary.LittleEndian.Uint32(raw) | ||||||
|  | 
 | ||||||
|  | 	return be == macho.Magic32 || | ||||||
|  | 		le == macho.Magic32 || | ||||||
|  | 		be == macho.Magic64 || | ||||||
|  | 		le == macho.Magic64 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Dbf matches a dBase file. | ||||||
|  | // https://www.dbase.com/Knowledgebase/INT/db7_file_fmt.htm | ||||||
|  | func Dbf(raw []byte, limit uint32) bool { | ||||||
|  | 	if len(raw) < 68 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 3rd and 4th bytes contain the last update month and day of month. | ||||||
|  | 	if !(0 < raw[2] && raw[2] < 13 && 0 < raw[3] && raw[3] < 32) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 12, 13, 30, 31 are reserved bytes and always filled with 0x00. | ||||||
|  | 	if raw[12] != 0x00 || raw[13] != 0x00 || raw[30] != 0x00 || raw[31] != 0x00 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// Production MDX flag; | ||||||
|  | 	// 0x01 if a production .MDX file exists for this table; | ||||||
|  | 	// 0x00 if no .MDX file exists. | ||||||
|  | 	if raw[28] > 0x01 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// dbf type is dictated by the first byte. | ||||||
|  | 	dbfTypes := []byte{ | ||||||
|  | 		0x02, 0x03, 0x04, 0x05, 0x30, 0x31, 0x32, 0x42, 0x62, 0x7B, 0x82, | ||||||
|  | 		0x83, 0x87, 0x8A, 0x8B, 0x8E, 0xB3, 0xCB, 0xE5, 0xF5, 0xF4, 0xFB, | ||||||
|  | 	} | ||||||
|  | 	for _, b := range dbfTypes { | ||||||
|  | 		if raw[0] == b { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ElfObj matches an object file. | ||||||
|  | func ElfObj(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 17 && ((raw[16] == 0x01 && raw[17] == 0x00) || | ||||||
|  | 		(raw[16] == 0x00 && raw[17] == 0x01)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ElfExe matches an executable file. | ||||||
|  | func ElfExe(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 17 && ((raw[16] == 0x02 && raw[17] == 0x00) || | ||||||
|  | 		(raw[16] == 0x00 && raw[17] == 0x02)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ElfLib matches a shared library file. | ||||||
|  | func ElfLib(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 17 && ((raw[16] == 0x03 && raw[17] == 0x00) || | ||||||
|  | 		(raw[16] == 0x00 && raw[17] == 0x03)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ElfDump matches a core dump file. | ||||||
|  | func ElfDump(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 17 && ((raw[16] == 0x04 && raw[17] == 0x00) || | ||||||
|  | 		(raw[16] == 0x00 && raw[17] == 0x04)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Dcm matches a DICOM medical format file. | ||||||
|  | func Dcm(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 131 && | ||||||
|  | 		bytes.Equal(raw[128:132], []byte{0x44, 0x49, 0x43, 0x4D}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Marc matches a MARC21 (MAchine-Readable Cataloging) file. | ||||||
|  | func Marc(raw []byte, limit uint32) bool { | ||||||
|  | 	// File is at least 24 bytes ("leader" field size). | ||||||
|  | 	if len(raw) < 24 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Fixed bytes at offset 20. | ||||||
|  | 	if !bytes.Equal(raw[20:24], []byte("4500")) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// First 5 bytes are ASCII digits. | ||||||
|  | 	for i := 0; i < 5; i++ { | ||||||
|  | 		if raw[i] < '0' || raw[i] > '9' { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Field terminator is present in first 2048 bytes. | ||||||
|  | 	return bytes.Contains(raw[:min(2048, len(raw))], []byte{0x1E}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Glb matches a glTF model format file. | ||||||
|  | // GLB is the binary file format representation of 3D models save in | ||||||
|  | // the GL transmission Format (glTF). | ||||||
|  | // see more: https://docs.fileformat.com/3d/glb/ | ||||||
|  | //           https://www.iana.org/assignments/media-types/model/gltf-binary | ||||||
|  | // GLB file format is based on little endian and its header structure | ||||||
|  | // show  below: | ||||||
|  | // | ||||||
|  | // <-- 12-byte header                             --> | ||||||
|  | // | magic            | version          | length   | | ||||||
|  | // | (uint32)         | (uint32)         | (uint32) | | ||||||
|  | // | \x67\x6C\x54\x46 | \x01\x00\x00\x00 | ...      | | ||||||
|  | // | g   l   T   F    | 1                | ...      | | ||||||
|  | var Glb = prefix([]byte("\x67\x6C\x54\x46\x02\x00\x00\x00"), | ||||||
|  | 	[]byte("\x67\x6C\x54\x46\x01\x00\x00\x00")) | ||||||
|  | 
 | ||||||
|  | // TzIf matches a Time Zone Information Format (TZif) file. | ||||||
|  | // See more: https://tools.ietf.org/id/draft-murchison-tzdist-tzif-00.html#rfc.section.3 | ||||||
|  | // Its header structure is shown below: | ||||||
|  | // +---------------+---+ | ||||||
|  | // |  magic    (4) | <-+-- version (1) | ||||||
|  | // +---------------+---+---------------------------------------+ | ||||||
|  | // |           [unused - reserved for future use] (15)         | | ||||||
|  | // +---------------+---------------+---------------+-----------+ | ||||||
|  | // |  isutccnt (4) |  isstdcnt (4) |  leapcnt  (4) | | ||||||
|  | // +---------------+---------------+---------------+ | ||||||
|  | // |  timecnt  (4) |  typecnt  (4) |  charcnt  (4) | | ||||||
|  | func TzIf(raw []byte, limit uint32) bool { | ||||||
|  | 	// File is at least 44 bytes (header size). | ||||||
|  | 	if len(raw) < 44 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !bytes.HasPrefix(raw, []byte("TZif")) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Field "typecnt" MUST not be zero. | ||||||
|  | 	if binary.BigEndian.Uint32(raw[36:40]) == 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Version has to be NUL (0x00), '2' (0x32) or '3' (0x33). | ||||||
|  | 	return raw[4] == 0x00 || raw[4] == 0x32 || raw[4] == 0x33 | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/database.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/database.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// Sqlite matches an SQLite database file. | ||||||
|  | 	Sqlite = prefix([]byte{ | ||||||
|  | 		0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, | ||||||
|  | 		0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x33, 0x00, | ||||||
|  | 	}) | ||||||
|  | 	// MsAccessAce matches Microsoft Access dababase file. | ||||||
|  | 	MsAccessAce = offset([]byte("Standard ACE DB"), 4) | ||||||
|  | 	// MsAccessMdb matches legacy Microsoft Access database file (JET, 2003 and earlier). | ||||||
|  | 	MsAccessMdb = offset([]byte("Standard Jet DB"), 4) | ||||||
|  | ) | ||||||
							
								
								
									
										62
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/document.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/document.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import "bytes" | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// Pdf matches a Portable Document Format file. | ||||||
|  | 	// https://github.com/file/file/blob/11010cc805546a3e35597e67e1129a481aed40e8/magic/Magdir/pdf | ||||||
|  | 	Pdf = prefix( | ||||||
|  | 		// usual pdf signature | ||||||
|  | 		[]byte("%PDF-"), | ||||||
|  | 		// new-line prefixed signature | ||||||
|  | 		[]byte("\012%PDF-"), | ||||||
|  | 		// UTF-8 BOM prefixed signature | ||||||
|  | 		[]byte("\xef\xbb\xbf%PDF-"), | ||||||
|  | 	) | ||||||
|  | 	// Fdf matches a Forms Data Format file. | ||||||
|  | 	Fdf = prefix([]byte("%FDF")) | ||||||
|  | 	// Mobi matches a Mobi file. | ||||||
|  | 	Mobi = offset([]byte("BOOKMOBI"), 60) | ||||||
|  | 	// Lit matches a Microsoft Lit file. | ||||||
|  | 	Lit = prefix([]byte("ITOLITLS")) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // DjVu matches a DjVu file. | ||||||
|  | func DjVu(raw []byte, limit uint32) bool { | ||||||
|  | 	if len(raw) < 12 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	if !bytes.HasPrefix(raw, []byte{0x41, 0x54, 0x26, 0x54, 0x46, 0x4F, 0x52, 0x4D}) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return bytes.HasPrefix(raw[12:], []byte("DJVM")) || | ||||||
|  | 		bytes.HasPrefix(raw[12:], []byte("DJVU")) || | ||||||
|  | 		bytes.HasPrefix(raw[12:], []byte("DJVI")) || | ||||||
|  | 		bytes.HasPrefix(raw[12:], []byte("THUM")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // P7s matches an .p7s signature File (PEM, Base64). | ||||||
|  | func P7s(raw []byte, limit uint32) bool { | ||||||
|  | 	// Check for PEM Encoding. | ||||||
|  | 	if bytes.HasPrefix(raw, []byte("-----BEGIN PKCS7")) { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	// Check if DER Encoding is long enough. | ||||||
|  | 	if len(raw) < 20 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// Magic Bytes for the signedData ASN.1 encoding. | ||||||
|  | 	startHeader := [][]byte{{0x30, 0x80}, {0x30, 0x81}, {0x30, 0x82}, {0x30, 0x83}, {0x30, 0x84}} | ||||||
|  | 	signedDataMatch := []byte{0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07} | ||||||
|  | 	// Check if Header is correct. There are multiple valid headers. | ||||||
|  | 	for i, match := range startHeader { | ||||||
|  | 		// If first bytes match, then check for ASN.1 Object Type. | ||||||
|  | 		if bytes.HasPrefix(raw, match) { | ||||||
|  | 			if bytes.HasPrefix(raw[i+2:], signedDataMatch) { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/font.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/font.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// Woff matches a Web Open Font Format file. | ||||||
|  | 	Woff = prefix([]byte("wOFF")) | ||||||
|  | 	// Woff2 matches a Web Open Font Format version 2 file. | ||||||
|  | 	Woff2 = prefix([]byte("wOF2")) | ||||||
|  | 	// Otf matches an OpenType font file. | ||||||
|  | 	Otf = prefix([]byte{0x4F, 0x54, 0x54, 0x4F, 0x00}) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Ttf matches a TrueType font file. | ||||||
|  | func Ttf(raw []byte, limit uint32) bool { | ||||||
|  | 	if !bytes.HasPrefix(raw, []byte{0x00, 0x01, 0x00, 0x00}) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return !MsAccessAce(raw, limit) && !MsAccessMdb(raw, limit) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Eot matches an Embedded OpenType font file. | ||||||
|  | func Eot(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 35 && | ||||||
|  | 		bytes.Equal(raw[34:36], []byte{0x4C, 0x50}) && | ||||||
|  | 		(bytes.Equal(raw[8:11], []byte{0x02, 0x00, 0x01}) || | ||||||
|  | 			bytes.Equal(raw[8:11], []byte{0x01, 0x00, 0x00}) || | ||||||
|  | 			bytes.Equal(raw[8:11], []byte{0x02, 0x00, 0x02})) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Ttc matches a TrueType Collection font file. | ||||||
|  | func Ttc(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 7 && | ||||||
|  | 		bytes.HasPrefix(raw, []byte("ttcf")) && | ||||||
|  | 		(bytes.Equal(raw[4:8], []byte{0x00, 0x01, 0x00, 0x00}) || | ||||||
|  | 			bytes.Equal(raw[4:8], []byte{0x00, 0x02, 0x00, 0x00})) | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/ftyp.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/ftyp.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,88 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import "bytes" | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// AVIF matches an AV1 Image File Format still or animated. | ||||||
|  | 	// Wikipedia page seems outdated listing image/avif-sequence for animations. | ||||||
|  | 	// https://github.com/AOMediaCodec/av1-avif/issues/59 | ||||||
|  | 	AVIF = ftyp([]byte("avif"), []byte("avis")) | ||||||
|  | 	// Mp4 matches an MP4 file. | ||||||
|  | 	Mp4 = ftyp( | ||||||
|  | 		[]byte("avc1"), []byte("dash"), []byte("iso2"), []byte("iso3"), | ||||||
|  | 		[]byte("iso4"), []byte("iso5"), []byte("iso6"), []byte("isom"), | ||||||
|  | 		[]byte("mmp4"), []byte("mp41"), []byte("mp42"), []byte("mp4v"), | ||||||
|  | 		[]byte("mp71"), []byte("MSNV"), []byte("NDAS"), []byte("NDSC"), | ||||||
|  | 		[]byte("NSDC"), []byte("NSDH"), []byte("NDSM"), []byte("NDSP"), | ||||||
|  | 		[]byte("NDSS"), []byte("NDXC"), []byte("NDXH"), []byte("NDXM"), | ||||||
|  | 		[]byte("NDXP"), []byte("NDXS"), []byte("F4V "), []byte("F4P "), | ||||||
|  | 	) | ||||||
|  | 	// ThreeGP matches a 3GPP file. | ||||||
|  | 	ThreeGP = ftyp( | ||||||
|  | 		[]byte("3gp1"), []byte("3gp2"), []byte("3gp3"), []byte("3gp4"), | ||||||
|  | 		[]byte("3gp5"), []byte("3gp6"), []byte("3gp7"), []byte("3gs7"), | ||||||
|  | 		[]byte("3ge6"), []byte("3ge7"), []byte("3gg6"), | ||||||
|  | 	) | ||||||
|  | 	// ThreeG2 matches a 3GPP2 file. | ||||||
|  | 	ThreeG2 = ftyp( | ||||||
|  | 		[]byte("3g24"), []byte("3g25"), []byte("3g26"), []byte("3g2a"), | ||||||
|  | 		[]byte("3g2b"), []byte("3g2c"), []byte("KDDI"), | ||||||
|  | 	) | ||||||
|  | 	// AMp4 matches an audio MP4 file. | ||||||
|  | 	AMp4 = ftyp( | ||||||
|  | 		// audio for Adobe Flash Player 9+ | ||||||
|  | 		[]byte("F4A "), []byte("F4B "), | ||||||
|  | 		// Apple iTunes AAC-LC (.M4A) Audio | ||||||
|  | 		[]byte("M4B "), []byte("M4P "), | ||||||
|  | 		// MPEG-4 (.MP4) for SonyPSP | ||||||
|  | 		[]byte("MSNV"), | ||||||
|  | 		// Nero Digital AAC Audio | ||||||
|  | 		[]byte("NDAS"), | ||||||
|  | 	) | ||||||
|  | 	// Mqv matches a Sony / Mobile QuickTime  file. | ||||||
|  | 	Mqv = ftyp([]byte("mqt ")) | ||||||
|  | 	// M4a matches an audio M4A file. | ||||||
|  | 	M4a = ftyp([]byte("M4A ")) | ||||||
|  | 	// M4v matches an Appl4 M4V video file. | ||||||
|  | 	M4v = ftyp([]byte("M4V "), []byte("M4VH"), []byte("M4VP")) | ||||||
|  | 	// Heic matches a High Efficiency Image Coding (HEIC) file. | ||||||
|  | 	Heic = ftyp([]byte("heic"), []byte("heix")) | ||||||
|  | 	// HeicSequence matches a High Efficiency Image Coding (HEIC) file sequence. | ||||||
|  | 	HeicSequence = ftyp([]byte("hevc"), []byte("hevx")) | ||||||
|  | 	// Heif matches a High Efficiency Image File Format (HEIF) file. | ||||||
|  | 	Heif = ftyp([]byte("mif1"), []byte("heim"), []byte("heis"), []byte("avic")) | ||||||
|  | 	// HeifSequence matches a High Efficiency Image File Format (HEIF) file sequence. | ||||||
|  | 	HeifSequence = ftyp([]byte("msf1"), []byte("hevm"), []byte("hevs"), []byte("avcs")) | ||||||
|  | 	// TODO: add support for remaining video formats at ftyps.com. | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // QuickTime matches a QuickTime File Format file. | ||||||
|  | // https://www.loc.gov/preservation/digital/formats/fdd/fdd000052.shtml | ||||||
|  | // https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html#//apple_ref/doc/uid/TP40000939-CH203-38190 | ||||||
|  | // https://github.com/apache/tika/blob/0f5570691133c75ac4472c3340354a6c4080b104/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml#L7758-L7777 | ||||||
|  | func QuickTime(raw []byte, _ uint32) bool { | ||||||
|  | 	if len(raw) < 12 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// First 4 bytes represent the size of the atom as unsigned int. | ||||||
|  | 	// Next 4 bytes are the type of the atom. | ||||||
|  | 	// For `ftyp` atoms check if first byte in size is 0, otherwise, a text file | ||||||
|  | 	// which happens to contain 'ftypqt  ' at index 4 will trigger a false positive. | ||||||
|  | 	if bytes.Equal(raw[4:12], []byte("ftypqt  ")) || | ||||||
|  | 		bytes.Equal(raw[4:12], []byte("ftypmoov")) { | ||||||
|  | 		return raw[0] == 0x00 | ||||||
|  | 	} | ||||||
|  | 	basicAtomTypes := [][]byte{ | ||||||
|  | 		[]byte("moov\x00"), | ||||||
|  | 		[]byte("mdat\x00"), | ||||||
|  | 		[]byte("free\x00"), | ||||||
|  | 		[]byte("skip\x00"), | ||||||
|  | 		[]byte("pnot\x00"), | ||||||
|  | 	} | ||||||
|  | 	for _, a := range basicAtomTypes { | ||||||
|  | 		if bytes.Equal(raw[4:9], a) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return bytes.Equal(raw[:8], []byte("\x00\x00\x00\x08wide")) | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/geo.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/geo.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Shp matches a shape format file. | ||||||
|  | // https://www.esri.com/library/whitepapers/pdfs/shapefile.pdf | ||||||
|  | func Shp(raw []byte, limit uint32) bool { | ||||||
|  | 	if len(raw) < 112 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !(binary.BigEndian.Uint32(raw[0:4]) == 9994 && | ||||||
|  | 		binary.BigEndian.Uint32(raw[4:8]) == 0 && | ||||||
|  | 		binary.BigEndian.Uint32(raw[8:12]) == 0 && | ||||||
|  | 		binary.BigEndian.Uint32(raw[12:16]) == 0 && | ||||||
|  | 		binary.BigEndian.Uint32(raw[16:20]) == 0 && | ||||||
|  | 		binary.BigEndian.Uint32(raw[20:24]) == 0 && | ||||||
|  | 		binary.LittleEndian.Uint32(raw[28:32]) == 1000) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	shapeTypes := []int{ | ||||||
|  | 		0,  // Null shape | ||||||
|  | 		1,  // Point | ||||||
|  | 		3,  // Polyline | ||||||
|  | 		5,  // Polygon | ||||||
|  | 		8,  // MultiPoint | ||||||
|  | 		11, // PointZ | ||||||
|  | 		13, // PolylineZ | ||||||
|  | 		15, // PolygonZ | ||||||
|  | 		18, // MultiPointZ | ||||||
|  | 		21, // PointM | ||||||
|  | 		23, // PolylineM | ||||||
|  | 		25, // PolygonM | ||||||
|  | 		28, // MultiPointM | ||||||
|  | 		31, // MultiPatch | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, st := range shapeTypes { | ||||||
|  | 		if st == int(binary.LittleEndian.Uint32(raw[108:112])) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Shx matches a shape index format file. | ||||||
|  | // https://www.esri.com/library/whitepapers/pdfs/shapefile.pdf | ||||||
|  | func Shx(raw []byte, limit uint32) bool { | ||||||
|  | 	return bytes.HasPrefix(raw, []byte{0x00, 0x00, 0x27, 0x0A}) | ||||||
|  | } | ||||||
							
								
								
									
										110
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/image.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/image.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,110 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import "bytes" | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// Png matches a Portable Network Graphics file. | ||||||
|  | 	// https://www.w3.org/TR/PNG/ | ||||||
|  | 	Png = prefix([]byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}) | ||||||
|  | 	// Apng matches an Animated Portable Network Graphics file. | ||||||
|  | 	// https://wiki.mozilla.org/APNG_Specification | ||||||
|  | 	Apng = offset([]byte("acTL"), 37) | ||||||
|  | 	// Jpg matches a Joint Photographic Experts Group file. | ||||||
|  | 	Jpg = prefix([]byte{0xFF, 0xD8, 0xFF}) | ||||||
|  | 	// Jp2 matches a JPEG 2000 Image file (ISO 15444-1). | ||||||
|  | 	Jp2 = jpeg2k([]byte{0x6a, 0x70, 0x32, 0x20}) | ||||||
|  | 	// Jpx matches a JPEG 2000 Image file (ISO 15444-2). | ||||||
|  | 	Jpx = jpeg2k([]byte{0x6a, 0x70, 0x78, 0x20}) | ||||||
|  | 	// Jpm matches a JPEG 2000 Image file (ISO 15444-6). | ||||||
|  | 	Jpm = jpeg2k([]byte{0x6a, 0x70, 0x6D, 0x20}) | ||||||
|  | 	// Gif matches a Graphics Interchange Format file. | ||||||
|  | 	Gif = prefix([]byte("GIF87a"), []byte("GIF89a")) | ||||||
|  | 	// Bmp matches a bitmap image file. | ||||||
|  | 	Bmp = prefix([]byte{0x42, 0x4D}) | ||||||
|  | 	// Ps matches a PostScript file. | ||||||
|  | 	Ps = prefix([]byte("%!PS-Adobe-")) | ||||||
|  | 	// Psd matches a Photoshop Document file. | ||||||
|  | 	Psd = prefix([]byte("8BPS")) | ||||||
|  | 	// Ico matches an ICO file. | ||||||
|  | 	Ico = prefix([]byte{0x00, 0x00, 0x01, 0x00}, []byte{0x00, 0x00, 0x02, 0x00}) | ||||||
|  | 	// Icns matches an ICNS (Apple Icon Image format) file. | ||||||
|  | 	Icns = prefix([]byte("icns")) | ||||||
|  | 	// Tiff matches a Tagged Image File Format file. | ||||||
|  | 	Tiff = prefix([]byte{0x49, 0x49, 0x2A, 0x00}, []byte{0x4D, 0x4D, 0x00, 0x2A}) | ||||||
|  | 	// Bpg matches a Better Portable Graphics file. | ||||||
|  | 	Bpg = prefix([]byte{0x42, 0x50, 0x47, 0xFB}) | ||||||
|  | 	// Xcf matches GIMP image data. | ||||||
|  | 	Xcf = prefix([]byte("gimp xcf")) | ||||||
|  | 	// Pat matches GIMP pattern data. | ||||||
|  | 	Pat = offset([]byte("GPAT"), 20) | ||||||
|  | 	// Gbr matches GIMP brush data. | ||||||
|  | 	Gbr = offset([]byte("GIMP"), 20) | ||||||
|  | 	// Hdr matches Radiance HDR image. | ||||||
|  | 	// https://web.archive.org/web/20060913152809/http://local.wasp.uwa.edu.au/~pbourke/dataformats/pic/ | ||||||
|  | 	Hdr = prefix([]byte("#?RADIANCE\n")) | ||||||
|  | 	// Xpm matches X PixMap image data. | ||||||
|  | 	Xpm = prefix([]byte{0x2F, 0x2A, 0x20, 0x58, 0x50, 0x4D, 0x20, 0x2A, 0x2F}) | ||||||
|  | 	// Jxs matches a JPEG XS coded image file (ISO/IEC 21122-3). | ||||||
|  | 	Jxs = prefix([]byte{0x00, 0x00, 0x00, 0x0C, 0x4A, 0x58, 0x53, 0x20, 0x0D, 0x0A, 0x87, 0x0A}) | ||||||
|  | 	// Jxr matches Microsoft HD JXR photo file. | ||||||
|  | 	Jxr = prefix([]byte{0x49, 0x49, 0xBC, 0x01}) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func jpeg2k(sig []byte) Detector { | ||||||
|  | 	return func(raw []byte, _ uint32) bool { | ||||||
|  | 		if len(raw) < 24 { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if !bytes.Equal(raw[4:8], []byte{0x6A, 0x50, 0x20, 0x20}) && | ||||||
|  | 			!bytes.Equal(raw[4:8], []byte{0x6A, 0x50, 0x32, 0x20}) { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		return bytes.Equal(raw[20:24], sig) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Webp matches a WebP file. | ||||||
|  | func Webp(raw []byte, _ uint32) bool { | ||||||
|  | 	return len(raw) > 12 && | ||||||
|  | 		bytes.Equal(raw[0:4], []byte("RIFF")) && | ||||||
|  | 		bytes.Equal(raw[8:12], []byte{0x57, 0x45, 0x42, 0x50}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Dwg matches a CAD drawing file. | ||||||
|  | func Dwg(raw []byte, _ uint32) bool { | ||||||
|  | 	if len(raw) < 6 || raw[0] != 0x41 || raw[1] != 0x43 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	dwgVersions := [][]byte{ | ||||||
|  | 		{0x31, 0x2E, 0x34, 0x30}, | ||||||
|  | 		{0x31, 0x2E, 0x35, 0x30}, | ||||||
|  | 		{0x32, 0x2E, 0x31, 0x30}, | ||||||
|  | 		{0x31, 0x30, 0x30, 0x32}, | ||||||
|  | 		{0x31, 0x30, 0x30, 0x33}, | ||||||
|  | 		{0x31, 0x30, 0x30, 0x34}, | ||||||
|  | 		{0x31, 0x30, 0x30, 0x36}, | ||||||
|  | 		{0x31, 0x30, 0x30, 0x39}, | ||||||
|  | 		{0x31, 0x30, 0x31, 0x32}, | ||||||
|  | 		{0x31, 0x30, 0x31, 0x34}, | ||||||
|  | 		{0x31, 0x30, 0x31, 0x35}, | ||||||
|  | 		{0x31, 0x30, 0x31, 0x38}, | ||||||
|  | 		{0x31, 0x30, 0x32, 0x31}, | ||||||
|  | 		{0x31, 0x30, 0x32, 0x34}, | ||||||
|  | 		{0x31, 0x30, 0x33, 0x32}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, d := range dwgVersions { | ||||||
|  | 		if bytes.Equal(raw[2:6], d) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Jxl matches JPEG XL image file. | ||||||
|  | func Jxl(raw []byte, _ uint32) bool { | ||||||
|  | 	return bytes.HasPrefix(raw, []byte{0xFF, 0x0A}) || | ||||||
|  | 		bytes.HasPrefix(raw, []byte("\x00\x00\x00\x0cJXL\x20\x0d\x0a\x87\x0a")) | ||||||
|  | } | ||||||
							
								
								
									
										239
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/magic.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/magic.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,239 @@ | ||||||
|  | // Package magic holds the matching functions used to find MIME types. | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type ( | ||||||
|  | 	// Detector receiveѕ the raw data of a file and returns whether the data | ||||||
|  | 	// meets any conditions. The limit parameter is an upper limit to the number | ||||||
|  | 	// of bytes received and is used to tell if the byte slice represents the | ||||||
|  | 	// whole file or is just the header of a file: len(raw) < limit or len(raw)>limit. | ||||||
|  | 	Detector func(raw []byte, limit uint32) bool | ||||||
|  | 	xmlSig   struct { | ||||||
|  | 		// the local name of the root tag | ||||||
|  | 		localName []byte | ||||||
|  | 		// the namespace of the XML document | ||||||
|  | 		xmlns []byte | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // prefix creates a Detector which returns true if any of the provided signatures | ||||||
|  | // is the prefix of the raw input. | ||||||
|  | func prefix(sigs ...[]byte) Detector { | ||||||
|  | 	return func(raw []byte, limit uint32) bool { | ||||||
|  | 		for _, s := range sigs { | ||||||
|  | 			if bytes.HasPrefix(raw, s) { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // offset creates a Detector which returns true if the provided signature can be | ||||||
|  | // found at offset in the raw input. | ||||||
|  | func offset(sig []byte, offset int) Detector { | ||||||
|  | 	return func(raw []byte, limit uint32) bool { | ||||||
|  | 		return len(raw) > offset && bytes.HasPrefix(raw[offset:], sig) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ciPrefix is like prefix but the check is case insensitive. | ||||||
|  | func ciPrefix(sigs ...[]byte) Detector { | ||||||
|  | 	return func(raw []byte, limit uint32) bool { | ||||||
|  | 		for _, s := range sigs { | ||||||
|  | 			if ciCheck(s, raw) { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | func ciCheck(sig, raw []byte) bool { | ||||||
|  | 	if len(raw) < len(sig)+1 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// perform case insensitive check | ||||||
|  | 	for i, b := range sig { | ||||||
|  | 		db := raw[i] | ||||||
|  | 		if 'A' <= b && b <= 'Z' { | ||||||
|  | 			db &= 0xDF | ||||||
|  | 		} | ||||||
|  | 		if b != db { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // xml creates a Detector which returns true if any of the provided XML signatures | ||||||
|  | // matches the raw input. | ||||||
|  | func xml(sigs ...xmlSig) Detector { | ||||||
|  | 	return func(raw []byte, limit uint32) bool { | ||||||
|  | 		raw = trimLWS(raw) | ||||||
|  | 		if len(raw) == 0 { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		for _, s := range sigs { | ||||||
|  | 			if xmlCheck(s, raw) { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | func xmlCheck(sig xmlSig, raw []byte) bool { | ||||||
|  | 	raw = raw[:min(len(raw), 512)] | ||||||
|  | 
 | ||||||
|  | 	if len(sig.localName) == 0 { | ||||||
|  | 		return bytes.Index(raw, sig.xmlns) > 0 | ||||||
|  | 	} | ||||||
|  | 	if len(sig.xmlns) == 0 { | ||||||
|  | 		return bytes.Index(raw, sig.localName) > 0 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	localNameIndex := bytes.Index(raw, sig.localName) | ||||||
|  | 	return localNameIndex != -1 && localNameIndex < bytes.Index(raw, sig.xmlns) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // markup creates a Detector which returns true is any of the HTML signatures | ||||||
|  | // matches the raw input. | ||||||
|  | func markup(sigs ...[]byte) Detector { | ||||||
|  | 	return func(raw []byte, limit uint32) bool { | ||||||
|  | 		if bytes.HasPrefix(raw, []byte{0xEF, 0xBB, 0xBF}) { | ||||||
|  | 			// We skip the UTF-8 BOM if present to ensure we correctly | ||||||
|  | 			// process any leading whitespace. The presence of the BOM | ||||||
|  | 			// is taken into account during charset detection in charset.go. | ||||||
|  | 			raw = trimLWS(raw[3:]) | ||||||
|  | 		} else { | ||||||
|  | 			raw = trimLWS(raw) | ||||||
|  | 		} | ||||||
|  | 		if len(raw) == 0 { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		for _, s := range sigs { | ||||||
|  | 			if markupCheck(s, raw) { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | func markupCheck(sig, raw []byte) bool { | ||||||
|  | 	if len(raw) < len(sig)+1 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// perform case insensitive check | ||||||
|  | 	for i, b := range sig { | ||||||
|  | 		db := raw[i] | ||||||
|  | 		if 'A' <= b && b <= 'Z' { | ||||||
|  | 			db &= 0xDF | ||||||
|  | 		} | ||||||
|  | 		if b != db { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// Next byte must be space or right angle bracket. | ||||||
|  | 	if db := raw[len(sig)]; db != ' ' && db != '>' { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ftyp creates a Detector which returns true if any of the FTYP signatures | ||||||
|  | // matches the raw input. | ||||||
|  | func ftyp(sigs ...[]byte) Detector { | ||||||
|  | 	return func(raw []byte, limit uint32) bool { | ||||||
|  | 		if len(raw) < 12 { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		for _, s := range sigs { | ||||||
|  | 			if bytes.Equal(raw[4:12], append([]byte("ftyp"), s...)) { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newXMLSig(localName, xmlns string) xmlSig { | ||||||
|  | 	ret := xmlSig{xmlns: []byte(xmlns)} | ||||||
|  | 	if localName != "" { | ||||||
|  | 		ret.localName = []byte(fmt.Sprintf("<%s", localName)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // A valid shebang starts with the "#!" characters, | ||||||
|  | // followed by any number of spaces, | ||||||
|  | // followed by the path to the interpreter, | ||||||
|  | // and, optionally, followed by the arguments for the interpreter. | ||||||
|  | // | ||||||
|  | // Ex: | ||||||
|  | //  #! /usr/bin/env php | ||||||
|  | // /usr/bin/env is the interpreter, php is the first and only argument. | ||||||
|  | func shebang(sigs ...[]byte) Detector { | ||||||
|  | 	return func(raw []byte, limit uint32) bool { | ||||||
|  | 		for _, s := range sigs { | ||||||
|  | 			if shebangCheck(s, firstLine(raw)) { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func shebangCheck(sig, raw []byte) bool { | ||||||
|  | 	if len(raw) < len(sig)+2 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	if raw[0] != '#' || raw[1] != '!' { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return bytes.Equal(trimLWS(trimRWS(raw[2:])), sig) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // trimLWS trims whitespace from beginning of the input. | ||||||
|  | func trimLWS(in []byte) []byte { | ||||||
|  | 	firstNonWS := 0 | ||||||
|  | 	for ; firstNonWS < len(in) && isWS(in[firstNonWS]); firstNonWS++ { | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return in[firstNonWS:] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // trimRWS trims whitespace from the end of the input. | ||||||
|  | func trimRWS(in []byte) []byte { | ||||||
|  | 	lastNonWS := len(in) - 1 | ||||||
|  | 	for ; lastNonWS > 0 && isWS(in[lastNonWS]); lastNonWS-- { | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return in[:lastNonWS+1] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func firstLine(in []byte) []byte { | ||||||
|  | 	lineEnd := 0 | ||||||
|  | 	for ; lineEnd < len(in) && in[lineEnd] != '\n'; lineEnd++ { | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return in[:lineEnd] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func isWS(b byte) bool { | ||||||
|  | 	return b == '\t' || b == '\n' || b == '\x0c' || b == '\r' || b == ' ' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func min(a, b int) int { | ||||||
|  | 	if a < b { | ||||||
|  | 		return a | ||||||
|  | 	} | ||||||
|  | 	return b | ||||||
|  | } | ||||||
							
								
								
									
										225
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/ms_office.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/ms_office.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,225 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	xlsxSigFiles = []string{ | ||||||
|  | 		"xl/worksheets/", | ||||||
|  | 		"xl/drawings/", | ||||||
|  | 		"xl/theme/", | ||||||
|  | 		"xl/_rels/", | ||||||
|  | 		"xl/styles.xml", | ||||||
|  | 		"xl/workbook.xml", | ||||||
|  | 		"xl/sharedStrings.xml", | ||||||
|  | 	} | ||||||
|  | 	docxSigFiles = []string{ | ||||||
|  | 		"word/media/", | ||||||
|  | 		"word/_rels/document.xml.rels", | ||||||
|  | 		"word/document.xml", | ||||||
|  | 		"word/styles.xml", | ||||||
|  | 		"word/fontTable.xml", | ||||||
|  | 		"word/settings.xml", | ||||||
|  | 		"word/numbering.xml", | ||||||
|  | 		"word/header", | ||||||
|  | 		"word/footer", | ||||||
|  | 	} | ||||||
|  | 	pptxSigFiles = []string{ | ||||||
|  | 		"ppt/slides/", | ||||||
|  | 		"ppt/media/", | ||||||
|  | 		"ppt/slideLayouts/", | ||||||
|  | 		"ppt/theme/", | ||||||
|  | 		"ppt/slideMasters/", | ||||||
|  | 		"ppt/tags/", | ||||||
|  | 		"ppt/notesMasters/", | ||||||
|  | 		"ppt/_rels/", | ||||||
|  | 		"ppt/handoutMasters/", | ||||||
|  | 		"ppt/notesSlides/", | ||||||
|  | 		"ppt/presentation.xml", | ||||||
|  | 		"ppt/tableStyles.xml", | ||||||
|  | 		"ppt/presProps.xml", | ||||||
|  | 		"ppt/viewProps.xml", | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Xlsx matches a Microsoft Excel 2007 file. | ||||||
|  | func Xlsx(raw []byte, limit uint32) bool { | ||||||
|  | 	return zipContains(raw, xlsxSigFiles...) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Docx matches a Microsoft Word 2007 file. | ||||||
|  | func Docx(raw []byte, limit uint32) bool { | ||||||
|  | 	return zipContains(raw, docxSigFiles...) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Pptx matches a Microsoft PowerPoint 2007 file. | ||||||
|  | func Pptx(raw []byte, limit uint32) bool { | ||||||
|  | 	return zipContains(raw, pptxSigFiles...) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Ole matches an Open Linking and Embedding file. | ||||||
|  | // | ||||||
|  | // https://en.wikipedia.org/wiki/Object_Linking_and_Embedding | ||||||
|  | func Ole(raw []byte, limit uint32) bool { | ||||||
|  | 	return bytes.HasPrefix(raw, []byte{0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Aaf matches an Advanced Authoring Format file. | ||||||
|  | // See: https://pyaaf.readthedocs.io/en/latest/about.html | ||||||
|  | // See: https://en.wikipedia.org/wiki/Advanced_Authoring_Format | ||||||
|  | func Aaf(raw []byte, limit uint32) bool { | ||||||
|  | 	if len(raw) < 31 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return bytes.HasPrefix(raw[8:], []byte{0x41, 0x41, 0x46, 0x42, 0x0D, 0x00, 0x4F, 0x4D}) && | ||||||
|  | 		(raw[30] == 0x09 || raw[30] == 0x0C) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Doc matches a Microsoft Word 97-2003 file. | ||||||
|  | // See: https://github.com/decalage2/oletools/blob/412ee36ae45e70f42123e835871bac956d958461/oletools/common/clsid.py | ||||||
|  | func Doc(raw []byte, _ uint32) bool { | ||||||
|  | 	clsids := [][]byte{ | ||||||
|  | 		// Microsoft Word 97-2003 Document (Word.Document.8) | ||||||
|  | 		{0x06, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}, | ||||||
|  | 		// Microsoft Word 6.0-7.0 Document (Word.Document.6) | ||||||
|  | 		{0x00, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}, | ||||||
|  | 		// Microsoft Word Picture (Word.Picture.8) | ||||||
|  | 		{0x07, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, clsid := range clsids { | ||||||
|  | 		if matchOleClsid(raw, clsid) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Ppt matches a Microsoft PowerPoint 97-2003 file or a PowerPoint 95 presentation. | ||||||
|  | func Ppt(raw []byte, limit uint32) bool { | ||||||
|  | 	// Root CLSID test is the safest way to detect identify OLE, however, the format | ||||||
|  | 	// often places the root CLSID at the end of the file. | ||||||
|  | 	if matchOleClsid(raw, []byte{ | ||||||
|  | 		0x10, 0x8d, 0x81, 0x64, 0x9b, 0x4f, 0xcf, 0x11, | ||||||
|  | 		0x86, 0xea, 0x00, 0xaa, 0x00, 0xb9, 0x29, 0xe8, | ||||||
|  | 	}) || matchOleClsid(raw, []byte{ | ||||||
|  | 		0x70, 0xae, 0x7b, 0xea, 0x3b, 0xfb, 0xcd, 0x11, | ||||||
|  | 		0xa9, 0x03, 0x00, 0xaa, 0x00, 0x51, 0x0e, 0xa3, | ||||||
|  | 	}) { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	lin := len(raw) | ||||||
|  | 	if lin < 520 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	pptSubHeaders := [][]byte{ | ||||||
|  | 		{0xA0, 0x46, 0x1D, 0xF0}, | ||||||
|  | 		{0x00, 0x6E, 0x1E, 0xF0}, | ||||||
|  | 		{0x0F, 0x00, 0xE8, 0x03}, | ||||||
|  | 	} | ||||||
|  | 	for _, h := range pptSubHeaders { | ||||||
|  | 		if bytes.HasPrefix(raw[512:], h) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if bytes.HasPrefix(raw[512:], []byte{0xFD, 0xFF, 0xFF, 0xFF}) && | ||||||
|  | 		raw[518] == 0x00 && raw[519] == 0x00 { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return lin > 1152 && bytes.Contains(raw[1152:min(4096, lin)], | ||||||
|  | 		[]byte("P\x00o\x00w\x00e\x00r\x00P\x00o\x00i\x00n\x00t\x00 D\x00o\x00c\x00u\x00m\x00e\x00n\x00t")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Xls matches a Microsoft Excel 97-2003 file. | ||||||
|  | func Xls(raw []byte, limit uint32) bool { | ||||||
|  | 	// Root CLSID test is the safest way to detect identify OLE, however, the format | ||||||
|  | 	// often places the root CLSID at the end of the file. | ||||||
|  | 	if matchOleClsid(raw, []byte{ | ||||||
|  | 		0x10, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  | 	}) || matchOleClsid(raw, []byte{ | ||||||
|  | 		0x20, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  | 	}) { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	lin := len(raw) | ||||||
|  | 	if lin < 520 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	xlsSubHeaders := [][]byte{ | ||||||
|  | 		{0x09, 0x08, 0x10, 0x00, 0x00, 0x06, 0x05, 0x00}, | ||||||
|  | 		{0xFD, 0xFF, 0xFF, 0xFF, 0x10}, | ||||||
|  | 		{0xFD, 0xFF, 0xFF, 0xFF, 0x1F}, | ||||||
|  | 		{0xFD, 0xFF, 0xFF, 0xFF, 0x22}, | ||||||
|  | 		{0xFD, 0xFF, 0xFF, 0xFF, 0x23}, | ||||||
|  | 		{0xFD, 0xFF, 0xFF, 0xFF, 0x28}, | ||||||
|  | 		{0xFD, 0xFF, 0xFF, 0xFF, 0x29}, | ||||||
|  | 	} | ||||||
|  | 	for _, h := range xlsSubHeaders { | ||||||
|  | 		if bytes.HasPrefix(raw[512:], h) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return lin > 1152 && bytes.Contains(raw[1152:min(4096, lin)], | ||||||
|  | 		[]byte("W\x00k\x00s\x00S\x00S\x00W\x00o\x00r\x00k\x00B\x00o\x00o\x00k")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Pub matches a Microsoft Publisher file. | ||||||
|  | func Pub(raw []byte, limit uint32) bool { | ||||||
|  | 	return matchOleClsid(raw, []byte{ | ||||||
|  | 		0x01, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  | 		0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Msg matches a Microsoft Outlook email file. | ||||||
|  | func Msg(raw []byte, limit uint32) bool { | ||||||
|  | 	return matchOleClsid(raw, []byte{ | ||||||
|  | 		0x0B, 0x0D, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  | 		0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Msi matches a Microsoft Windows Installer file. | ||||||
|  | // http://fileformats.archiveteam.org/wiki/Microsoft_Compound_File | ||||||
|  | func Msi(raw []byte, limit uint32) bool { | ||||||
|  | 	return matchOleClsid(raw, []byte{ | ||||||
|  | 		0x84, 0x10, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||||
|  | 		0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Helper to match by a specific CLSID of a compound file. | ||||||
|  | // | ||||||
|  | // http://fileformats.archiveteam.org/wiki/Microsoft_Compound_File | ||||||
|  | func matchOleClsid(in []byte, clsid []byte) bool { | ||||||
|  | 	// Microsoft Compound files v3 have a sector length of 512, while v4 has 4096. | ||||||
|  | 	// Change sector offset depending on file version. | ||||||
|  | 	// https://www.loc.gov/preservation/digital/formats/fdd/fdd000392.shtml | ||||||
|  | 	sectorLength := 512 | ||||||
|  | 	if len(in) < sectorLength { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	if in[26] == 0x04 && in[27] == 0x00 { | ||||||
|  | 		sectorLength = 4096 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// SecID of first sector of the directory stream. | ||||||
|  | 	firstSecID := int(binary.LittleEndian.Uint32(in[48:52])) | ||||||
|  | 
 | ||||||
|  | 	// Expected offset of CLSID for root storage object. | ||||||
|  | 	clsidOffset := sectorLength*(1+firstSecID) + 80 | ||||||
|  | 
 | ||||||
|  | 	if len(in) <= clsidOffset+16 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return bytes.HasPrefix(in[clsidOffset:], clsid) | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/ogg.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/ogg.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  NOTE: | ||||||
|  | 
 | ||||||
|  |  In May 2003, two Internet RFCs were published relating to the format. | ||||||
|  |  The Ogg bitstream was defined in RFC 3533 (which is classified as | ||||||
|  |  'informative') and its Internet content type (application/ogg) in RFC | ||||||
|  |  3534 (which is, as of 2006, a proposed standard protocol). In | ||||||
|  |  September 2008, RFC 3534 was obsoleted by RFC 5334, which added | ||||||
|  |  content types video/ogg, audio/ogg and filename extensions .ogx, .ogv, | ||||||
|  |  .oga, .spx. | ||||||
|  | 
 | ||||||
|  |  See: | ||||||
|  |  https://tools.ietf.org/html/rfc3533 | ||||||
|  |  https://developer.mozilla.org/en-US/docs/Web/HTTP/Configuring_servers_for_Ogg_media#Serve_media_with_the_correct_MIME_type | ||||||
|  |  https://github.com/file/file/blob/master/magic/Magdir/vorbis | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | // Ogg matches an Ogg file. | ||||||
|  | func Ogg(raw []byte, limit uint32) bool { | ||||||
|  | 	return bytes.HasPrefix(raw, []byte("\x4F\x67\x67\x53\x00")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // OggAudio matches an audio ogg file. | ||||||
|  | func OggAudio(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) >= 37 && (bytes.HasPrefix(raw[28:], []byte("\x7fFLAC")) || | ||||||
|  | 		bytes.HasPrefix(raw[28:], []byte("\x01vorbis")) || | ||||||
|  | 		bytes.HasPrefix(raw[28:], []byte("OpusHead")) || | ||||||
|  | 		bytes.HasPrefix(raw[28:], []byte("Speex\x20\x20\x20"))) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // OggVideo matches a video ogg file. | ||||||
|  | func OggVideo(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) >= 37 && (bytes.HasPrefix(raw[28:], []byte("\x80theora")) || | ||||||
|  | 		bytes.HasPrefix(raw[28:], []byte("fishead\x00")) || | ||||||
|  | 		bytes.HasPrefix(raw[28:], []byte("\x01video\x00\x00\x00"))) // OGM video | ||||||
|  | } | ||||||
							
								
								
									
										375
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/text.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										375
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/text.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,375 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/gabriel-vasile/mimetype/internal/charset" | ||||||
|  | 	"github.com/gabriel-vasile/mimetype/internal/json" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// HTML matches a Hypertext Markup Language file. | ||||||
|  | 	HTML = markup( | ||||||
|  | 		[]byte("<!DOCTYPE HTML"), | ||||||
|  | 		[]byte("<HTML"), | ||||||
|  | 		[]byte("<HEAD"), | ||||||
|  | 		[]byte("<SCRIPT"), | ||||||
|  | 		[]byte("<IFRAME"), | ||||||
|  | 		[]byte("<H1"), | ||||||
|  | 		[]byte("<DIV"), | ||||||
|  | 		[]byte("<FONT"), | ||||||
|  | 		[]byte("<TABLE"), | ||||||
|  | 		[]byte("<A"), | ||||||
|  | 		[]byte("<STYLE"), | ||||||
|  | 		[]byte("<TITLE"), | ||||||
|  | 		[]byte("<B"), | ||||||
|  | 		[]byte("<BODY"), | ||||||
|  | 		[]byte("<BR"), | ||||||
|  | 		[]byte("<P"), | ||||||
|  | 	) | ||||||
|  | 	// XML matches an Extensible Markup Language file. | ||||||
|  | 	XML = markup([]byte("<?XML")) | ||||||
|  | 	// Owl2 matches an Owl ontology file. | ||||||
|  | 	Owl2 = xml(newXMLSig("Ontology", `xmlns="http://www.w3.org/2002/07/owl#"`)) | ||||||
|  | 	// Rss matches a Rich Site Summary file. | ||||||
|  | 	Rss = xml(newXMLSig("rss", "")) | ||||||
|  | 	// Atom matches an Atom Syndication Format file. | ||||||
|  | 	Atom = xml(newXMLSig("feed", `xmlns="http://www.w3.org/2005/Atom"`)) | ||||||
|  | 	// Kml matches a Keyhole Markup Language file. | ||||||
|  | 	Kml = xml( | ||||||
|  | 		newXMLSig("kml", `xmlns="http://www.opengis.net/kml/2.2"`), | ||||||
|  | 		newXMLSig("kml", `xmlns="http://earth.google.com/kml/2.0"`), | ||||||
|  | 		newXMLSig("kml", `xmlns="http://earth.google.com/kml/2.1"`), | ||||||
|  | 		newXMLSig("kml", `xmlns="http://earth.google.com/kml/2.2"`), | ||||||
|  | 	) | ||||||
|  | 	// Xliff matches a XML Localization Interchange File Format file. | ||||||
|  | 	Xliff = xml(newXMLSig("xliff", `xmlns="urn:oasis:names:tc:xliff:document:1.2"`)) | ||||||
|  | 	// Collada matches a COLLAborative Design Activity file. | ||||||
|  | 	Collada = xml(newXMLSig("COLLADA", `xmlns="http://www.collada.org/2005/11/COLLADASchema"`)) | ||||||
|  | 	// Gml matches a Geography Markup Language file. | ||||||
|  | 	Gml = xml( | ||||||
|  | 		newXMLSig("", `xmlns:gml="http://www.opengis.net/gml"`), | ||||||
|  | 		newXMLSig("", `xmlns:gml="http://www.opengis.net/gml/3.2"`), | ||||||
|  | 		newXMLSig("", `xmlns:gml="http://www.opengis.net/gml/3.3/exr"`), | ||||||
|  | 	) | ||||||
|  | 	// Gpx matches a GPS Exchange Format file. | ||||||
|  | 	Gpx = xml(newXMLSig("gpx", `xmlns="http://www.topografix.com/GPX/1/1"`)) | ||||||
|  | 	// Tcx matches a Training Center XML file. | ||||||
|  | 	Tcx = xml(newXMLSig("TrainingCenterDatabase", `xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"`)) | ||||||
|  | 	// X3d matches an Extensible 3D Graphics file. | ||||||
|  | 	X3d = xml(newXMLSig("X3D", `xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance"`)) | ||||||
|  | 	// Amf matches an Additive Manufacturing XML file. | ||||||
|  | 	Amf = xml(newXMLSig("amf", "")) | ||||||
|  | 	// Threemf matches a 3D Manufacturing Format file. | ||||||
|  | 	Threemf = xml(newXMLSig("model", `xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02"`)) | ||||||
|  | 	// Xfdf matches a XML Forms Data Format file. | ||||||
|  | 	Xfdf = xml(newXMLSig("xfdf", `xmlns="http://ns.adobe.com/xfdf/"`)) | ||||||
|  | 	// VCard matches a Virtual Contact File. | ||||||
|  | 	VCard = ciPrefix([]byte("BEGIN:VCARD\n"), []byte("BEGIN:VCARD\r\n")) | ||||||
|  | 	// ICalendar matches a iCalendar file. | ||||||
|  | 	ICalendar = ciPrefix([]byte("BEGIN:VCALENDAR\n"), []byte("BEGIN:VCALENDAR\r\n")) | ||||||
|  | 	phpPageF  = ciPrefix( | ||||||
|  | 		[]byte("<?PHP"), | ||||||
|  | 		[]byte("<?\n"), | ||||||
|  | 		[]byte("<?\r"), | ||||||
|  | 		[]byte("<? "), | ||||||
|  | 	) | ||||||
|  | 	phpScriptF = shebang( | ||||||
|  | 		[]byte("/usr/local/bin/php"), | ||||||
|  | 		[]byte("/usr/bin/php"), | ||||||
|  | 		[]byte("/usr/bin/env php"), | ||||||
|  | 	) | ||||||
|  | 	// Js matches a Javascript file. | ||||||
|  | 	Js = shebang( | ||||||
|  | 		[]byte("/bin/node"), | ||||||
|  | 		[]byte("/usr/bin/node"), | ||||||
|  | 		[]byte("/bin/nodejs"), | ||||||
|  | 		[]byte("/usr/bin/nodejs"), | ||||||
|  | 		[]byte("/usr/bin/env node"), | ||||||
|  | 		[]byte("/usr/bin/env nodejs"), | ||||||
|  | 	) | ||||||
|  | 	// Lua matches a Lua programming language file. | ||||||
|  | 	Lua = shebang( | ||||||
|  | 		[]byte("/usr/bin/lua"), | ||||||
|  | 		[]byte("/usr/local/bin/lua"), | ||||||
|  | 		[]byte("/usr/bin/env lua"), | ||||||
|  | 	) | ||||||
|  | 	// Perl matches a Perl programming language file. | ||||||
|  | 	Perl = shebang( | ||||||
|  | 		[]byte("/usr/bin/perl"), | ||||||
|  | 		[]byte("/usr/bin/env perl"), | ||||||
|  | 	) | ||||||
|  | 	// Python matches a Python programming language file. | ||||||
|  | 	Python = shebang( | ||||||
|  | 		[]byte("/usr/bin/python"), | ||||||
|  | 		[]byte("/usr/local/bin/python"), | ||||||
|  | 		[]byte("/usr/bin/env python"), | ||||||
|  | 	) | ||||||
|  | 	// Tcl matches a Tcl programming language file. | ||||||
|  | 	Tcl = shebang( | ||||||
|  | 		[]byte("/usr/bin/tcl"), | ||||||
|  | 		[]byte("/usr/local/bin/tcl"), | ||||||
|  | 		[]byte("/usr/bin/env tcl"), | ||||||
|  | 		[]byte("/usr/bin/tclsh"), | ||||||
|  | 		[]byte("/usr/local/bin/tclsh"), | ||||||
|  | 		[]byte("/usr/bin/env tclsh"), | ||||||
|  | 		[]byte("/usr/bin/wish"), | ||||||
|  | 		[]byte("/usr/local/bin/wish"), | ||||||
|  | 		[]byte("/usr/bin/env wish"), | ||||||
|  | 	) | ||||||
|  | 	// Rtf matches a Rich Text Format file. | ||||||
|  | 	Rtf = prefix([]byte("{\\rtf1")) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Text matches a plain text file. | ||||||
|  | // | ||||||
|  | // TODO: This function does not parse BOM-less UTF16 and UTF32 files. Not really | ||||||
|  | // sure it should. Linux file utility also requires a BOM for UTF16 and UTF32. | ||||||
|  | func Text(raw []byte, limit uint32) bool { | ||||||
|  | 	// First look for BOM. | ||||||
|  | 	if cset := charset.FromBOM(raw); cset != "" { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	// Binary data bytes as defined here: https://mimesniff.spec.whatwg.org/#binary-data-byte | ||||||
|  | 	for _, b := range raw { | ||||||
|  | 		if b <= 0x08 || | ||||||
|  | 			b == 0x0B || | ||||||
|  | 			0x0E <= b && b <= 0x1A || | ||||||
|  | 			0x1C <= b && b <= 0x1F { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Php matches a PHP: Hypertext Preprocessor file. | ||||||
|  | func Php(raw []byte, limit uint32) bool { | ||||||
|  | 	if res := phpPageF(raw, limit); res { | ||||||
|  | 		return res | ||||||
|  | 	} | ||||||
|  | 	return phpScriptF(raw, limit) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // JSON matches a JavaScript Object Notation file. | ||||||
|  | func JSON(raw []byte, limit uint32) bool { | ||||||
|  | 	raw = trimLWS(raw) | ||||||
|  | 	// #175 A single JSON string, number or bool is not considered JSON. | ||||||
|  | 	// JSON objects and arrays are reported as JSON. | ||||||
|  | 	if len(raw) < 2 || (raw[0] != '[' && raw[0] != '{') { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	parsed, err := json.Scan(raw) | ||||||
|  | 	// If the full file content was provided, check there is no error. | ||||||
|  | 	if limit == 0 || len(raw) < int(limit) { | ||||||
|  | 		return err == nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// If a section of the file was provided, check if all of it was parsed. | ||||||
|  | 	return parsed == len(raw) && len(raw) > 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GeoJSON matches a RFC 7946 GeoJSON file. | ||||||
|  | // | ||||||
|  | // GeoJSON detection implies searching for key:value pairs like: `"type": "Feature"` | ||||||
|  | // in the input. | ||||||
|  | // BUG(gabriel-vasile): The "type" key should be searched for in the root object. | ||||||
|  | func GeoJSON(raw []byte, limit uint32) bool { | ||||||
|  | 	raw = trimLWS(raw) | ||||||
|  | 	if len(raw) == 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// GeoJSON is always a JSON object, not a JSON array or any other JSON value. | ||||||
|  | 	if raw[0] != '{' { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	s := []byte(`"type"`) | ||||||
|  | 	si, sl := bytes.Index(raw, s), len(s) | ||||||
|  | 
 | ||||||
|  | 	if si == -1 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// If the "type" string is the suffix of the input, | ||||||
|  | 	// there is no need to search for the value of the key. | ||||||
|  | 	if si+sl == len(raw) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// Skip the "type" part. | ||||||
|  | 	raw = raw[si+sl:] | ||||||
|  | 	// Skip any whitespace before the colon. | ||||||
|  | 	raw = trimLWS(raw) | ||||||
|  | 	// Check for colon. | ||||||
|  | 	if len(raw) == 0 || raw[0] != ':' { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// Skip any whitespace after the colon. | ||||||
|  | 	raw = trimLWS(raw[1:]) | ||||||
|  | 
 | ||||||
|  | 	geoJSONTypes := [][]byte{ | ||||||
|  | 		[]byte(`"Feature"`), | ||||||
|  | 		[]byte(`"FeatureCollection"`), | ||||||
|  | 		[]byte(`"Point"`), | ||||||
|  | 		[]byte(`"LineString"`), | ||||||
|  | 		[]byte(`"Polygon"`), | ||||||
|  | 		[]byte(`"MultiPoint"`), | ||||||
|  | 		[]byte(`"MultiLineString"`), | ||||||
|  | 		[]byte(`"MultiPolygon"`), | ||||||
|  | 		[]byte(`"GeometryCollection"`), | ||||||
|  | 	} | ||||||
|  | 	for _, t := range geoJSONTypes { | ||||||
|  | 		if bytes.HasPrefix(raw, t) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NdJSON matches a Newline delimited JSON file. All complete lines from raw | ||||||
|  | // must be valid JSON documents meaning they contain one of the valid JSON data | ||||||
|  | // types. | ||||||
|  | func NdJSON(raw []byte, limit uint32) bool { | ||||||
|  | 	lCount, hasObjOrArr := 0, false | ||||||
|  | 	sc := bufio.NewScanner(dropLastLine(raw, limit)) | ||||||
|  | 	for sc.Scan() { | ||||||
|  | 		l := sc.Bytes() | ||||||
|  | 		// Empty lines are allowed in NDJSON. | ||||||
|  | 		if l = trimRWS(trimLWS(l)); len(l) == 0 { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		_, err := json.Scan(l) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		if l[0] == '[' || l[0] == '{' { | ||||||
|  | 			hasObjOrArr = true | ||||||
|  | 		} | ||||||
|  | 		lCount++ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return lCount > 1 && hasObjOrArr | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // HAR matches a HAR Spec file. | ||||||
|  | // Spec: http://www.softwareishard.com/blog/har-12-spec/ | ||||||
|  | func HAR(raw []byte, limit uint32) bool { | ||||||
|  | 	s := []byte(`"log"`) | ||||||
|  | 	si, sl := bytes.Index(raw, s), len(s) | ||||||
|  | 
 | ||||||
|  | 	if si == -1 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// If the "log" string is the suffix of the input, | ||||||
|  | 	// there is no need to search for the value of the key. | ||||||
|  | 	if si+sl == len(raw) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// Skip the "log" part. | ||||||
|  | 	raw = raw[si+sl:] | ||||||
|  | 	// Skip any whitespace before the colon. | ||||||
|  | 	raw = trimLWS(raw) | ||||||
|  | 	// Check for colon. | ||||||
|  | 	if len(raw) == 0 || raw[0] != ':' { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// Skip any whitespace after the colon. | ||||||
|  | 	raw = trimLWS(raw[1:]) | ||||||
|  | 
 | ||||||
|  | 	harJSONTypes := [][]byte{ | ||||||
|  | 		[]byte(`"version"`), | ||||||
|  | 		[]byte(`"creator"`), | ||||||
|  | 		[]byte(`"entries"`), | ||||||
|  | 	} | ||||||
|  | 	for _, t := range harJSONTypes { | ||||||
|  | 		si := bytes.Index(raw, t) | ||||||
|  | 		if si > -1 { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Svg matches a SVG file. | ||||||
|  | func Svg(raw []byte, limit uint32) bool { | ||||||
|  | 	return bytes.Contains(raw, []byte("<svg")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Srt matches a SubRip file. | ||||||
|  | func Srt(in []byte, _ uint32) bool { | ||||||
|  | 	s := bufio.NewScanner(bytes.NewReader(in)) | ||||||
|  | 	if !s.Scan() { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// First line must be 1. | ||||||
|  | 	if s.Text() != "1" { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if !s.Scan() { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	secondLine := s.Text() | ||||||
|  | 	// Timestamp format (e.g: 00:02:16,612 --> 00:02:19,376) limits secondLine | ||||||
|  | 	// length to exactly 29 characters. | ||||||
|  | 	if len(secondLine) != 29 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// Decimal separator of fractional seconds in the timestamps must be a | ||||||
|  | 	// comma, not a period. | ||||||
|  | 	if strings.Contains(secondLine, ".") { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	// For Go <1.17, comma is not recognised as a decimal separator by `time.Parse`. | ||||||
|  | 	secondLine = strings.ReplaceAll(secondLine, ",", ".") | ||||||
|  | 	// Second line must be a time range. | ||||||
|  | 	ts := strings.Split(secondLine, " --> ") | ||||||
|  | 	if len(ts) != 2 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	const layout = "15:04:05.000" | ||||||
|  | 	t0, err := time.Parse(layout, ts[0]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	t1, err := time.Parse(layout, ts[1]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	if t0.After(t1) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// A third line must exist and not be empty. This is the actual subtitle text. | ||||||
|  | 	return s.Scan() && len(s.Bytes()) != 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Vtt matches a Web Video Text Tracks (WebVTT) file. See | ||||||
|  | // https://www.iana.org/assignments/media-types/text/vtt. | ||||||
|  | func Vtt(raw []byte, limit uint32) bool { | ||||||
|  | 	// Prefix match. | ||||||
|  | 	prefixes := [][]byte{ | ||||||
|  | 		{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54, 0x0A}, // UTF-8 BOM, "WEBVTT" and a line feed | ||||||
|  | 		{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54, 0x0D}, // UTF-8 BOM, "WEBVTT" and a carriage return | ||||||
|  | 		{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54, 0x20}, // UTF-8 BOM, "WEBVTT" and a space | ||||||
|  | 		{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54, 0x09}, // UTF-8 BOM, "WEBVTT" and a horizontal tab | ||||||
|  | 		{0x57, 0x45, 0x42, 0x56, 0x54, 0x54, 0x0A},                   // "WEBVTT" and a line feed | ||||||
|  | 		{0x57, 0x45, 0x42, 0x56, 0x54, 0x54, 0x0D},                   // "WEBVTT" and a carriage return | ||||||
|  | 		{0x57, 0x45, 0x42, 0x56, 0x54, 0x54, 0x20},                   // "WEBVTT" and a space | ||||||
|  | 		{0x57, 0x45, 0x42, 0x56, 0x54, 0x54, 0x09},                   // "WEBVTT" and a horizontal tab | ||||||
|  | 	} | ||||||
|  | 	for _, p := range prefixes { | ||||||
|  | 		if bytes.HasPrefix(raw, p) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Exact match. | ||||||
|  | 	return bytes.Equal(raw, []byte{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) || // UTF-8 BOM and "WEBVTT" | ||||||
|  | 		bytes.Equal(raw, []byte{0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) // "WEBVTT" | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/text_csv.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/text_csv.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/csv" | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Csv matches a comma-separated values file. | ||||||
|  | func Csv(raw []byte, limit uint32) bool { | ||||||
|  | 	return sv(raw, ',', limit) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Tsv matches a tab-separated values file. | ||||||
|  | func Tsv(raw []byte, limit uint32) bool { | ||||||
|  | 	return sv(raw, '\t', limit) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func sv(in []byte, comma rune, limit uint32) bool { | ||||||
|  | 	r := csv.NewReader(dropLastLine(in, limit)) | ||||||
|  | 	r.Comma = comma | ||||||
|  | 	r.TrimLeadingSpace = true | ||||||
|  | 	r.LazyQuotes = true | ||||||
|  | 	r.Comment = '#' | ||||||
|  | 
 | ||||||
|  | 	lines, err := r.ReadAll() | ||||||
|  | 	return err == nil && r.FieldsPerRecord > 1 && len(lines) > 1 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // dropLastLine drops the last incomplete line from b. | ||||||
|  | // | ||||||
|  | // mimetype limits itself to ReadLimit bytes when performing a detection. | ||||||
|  | // This means, for file formats like CSV for NDJSON, the last line of the input | ||||||
|  | // can be an incomplete line. | ||||||
|  | func dropLastLine(b []byte, cutAt uint32) io.Reader { | ||||||
|  | 	if cutAt == 0 { | ||||||
|  | 		return bytes.NewReader(b) | ||||||
|  | 	} | ||||||
|  | 	if uint32(len(b)) >= cutAt { | ||||||
|  | 		for i := cutAt - 1; i > 0; i-- { | ||||||
|  | 			if b[i] == '\n' { | ||||||
|  | 				return bytes.NewReader(b[:i]) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// No newline was found between the 0 index and cutAt. | ||||||
|  | 		return bytes.NewReader(b[:cutAt]) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return bytes.NewReader(b) | ||||||
|  | } | ||||||
							
								
								
									
										85
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/video.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/video.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// Flv matches a Flash video file. | ||||||
|  | 	Flv = prefix([]byte("\x46\x4C\x56\x01")) | ||||||
|  | 	// Asf matches an Advanced Systems Format file. | ||||||
|  | 	Asf = prefix([]byte{ | ||||||
|  | 		0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, | ||||||
|  | 		0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C, | ||||||
|  | 	}) | ||||||
|  | 	// Rmvb matches a RealMedia Variable Bitrate file. | ||||||
|  | 	Rmvb = prefix([]byte{0x2E, 0x52, 0x4D, 0x46}) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // WebM matches a WebM file. | ||||||
|  | func WebM(raw []byte, limit uint32) bool { | ||||||
|  | 	return isMatroskaFileTypeMatched(raw, "webm") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Mkv matches a mkv file. | ||||||
|  | func Mkv(raw []byte, limit uint32) bool { | ||||||
|  | 	return isMatroskaFileTypeMatched(raw, "matroska") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // isMatroskaFileTypeMatched is used for webm and mkv file matching. | ||||||
|  | // It checks for .Eߣ sequence. If the sequence is found, | ||||||
|  | // then it means it is Matroska media container, including WebM. | ||||||
|  | // Then it verifies which of the file type it is representing by matching the | ||||||
|  | // file specific string. | ||||||
|  | func isMatroskaFileTypeMatched(in []byte, flType string) bool { | ||||||
|  | 	if bytes.HasPrefix(in, []byte("\x1A\x45\xDF\xA3")) { | ||||||
|  | 		return isFileTypeNamePresent(in, flType) | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // isFileTypeNamePresent accepts the matroska input data stream and searches | ||||||
|  | // for the given file type in the stream. Return whether a match is found. | ||||||
|  | // The logic of search is: find first instance of \x42\x82 and then | ||||||
|  | // search for given string after n bytes of above instance. | ||||||
|  | func isFileTypeNamePresent(in []byte, flType string) bool { | ||||||
|  | 	ind, maxInd, lenIn := 0, 4096, len(in) | ||||||
|  | 	if lenIn < maxInd { // restricting length to 4096 | ||||||
|  | 		maxInd = lenIn | ||||||
|  | 	} | ||||||
|  | 	ind = bytes.Index(in[:maxInd], []byte("\x42\x82")) | ||||||
|  | 	if ind > 0 && lenIn > ind+2 { | ||||||
|  | 		ind += 2 | ||||||
|  | 
 | ||||||
|  | 		// filetype name will be present exactly | ||||||
|  | 		// n bytes after the match of the two bytes "\x42\x82" | ||||||
|  | 		n := vintWidth(int(in[ind])) | ||||||
|  | 		if lenIn > ind+n { | ||||||
|  | 			return bytes.HasPrefix(in[ind+n:], []byte(flType)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // vintWidth parses the variable-integer width in matroska containers | ||||||
|  | func vintWidth(v int) int { | ||||||
|  | 	mask, max, num := 128, 8, 1 | ||||||
|  | 	for num < max && v&mask == 0 { | ||||||
|  | 		mask = mask >> 1 | ||||||
|  | 		num++ | ||||||
|  | 	} | ||||||
|  | 	return num | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Mpeg matches a Moving Picture Experts Group file. | ||||||
|  | func Mpeg(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 3 && bytes.HasPrefix(raw, []byte{0x00, 0x00, 0x01}) && | ||||||
|  | 		raw[3] >= 0xB0 && raw[3] <= 0xBF | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Avi matches an Audio Video Interleaved file. | ||||||
|  | func Avi(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 16 && | ||||||
|  | 		bytes.Equal(raw[:4], []byte("RIFF")) && | ||||||
|  | 		bytes.Equal(raw[8:16], []byte("AVI LIST")) | ||||||
|  | } | ||||||
							
								
								
									
										92
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/zip.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								vendor/github.com/gabriel-vasile/mimetype/internal/magic/zip.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | ||||||
|  | package magic | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var ( | ||||||
|  | 	// Odt matches an OpenDocument Text file. | ||||||
|  | 	Odt = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.text"), 30) | ||||||
|  | 	// Ott matches an OpenDocument Text Template file. | ||||||
|  | 	Ott = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.text-template"), 30) | ||||||
|  | 	// Ods matches an OpenDocument Spreadsheet file. | ||||||
|  | 	Ods = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.spreadsheet"), 30) | ||||||
|  | 	// Ots matches an OpenDocument Spreadsheet Template file. | ||||||
|  | 	Ots = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.spreadsheet-template"), 30) | ||||||
|  | 	// Odp matches an OpenDocument Presentation file. | ||||||
|  | 	Odp = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.presentation"), 30) | ||||||
|  | 	// Otp matches an OpenDocument Presentation Template file. | ||||||
|  | 	Otp = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.presentation-template"), 30) | ||||||
|  | 	// Odg matches an OpenDocument Drawing file. | ||||||
|  | 	Odg = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.graphics"), 30) | ||||||
|  | 	// Otg matches an OpenDocument Drawing Template file. | ||||||
|  | 	Otg = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.graphics-template"), 30) | ||||||
|  | 	// Odf matches an OpenDocument Formula file. | ||||||
|  | 	Odf = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.formula"), 30) | ||||||
|  | 	// Odc matches an OpenDocument Chart file. | ||||||
|  | 	Odc = offset([]byte("mimetypeapplication/vnd.oasis.opendocument.chart"), 30) | ||||||
|  | 	// Epub matches an EPUB file. | ||||||
|  | 	Epub = offset([]byte("mimetypeapplication/epub+zip"), 30) | ||||||
|  | 	// Sxc matches an OpenOffice Spreadsheet file. | ||||||
|  | 	Sxc = offset([]byte("mimetypeapplication/vnd.sun.xml.calc"), 30) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Zip matches a zip archive. | ||||||
|  | func Zip(raw []byte, limit uint32) bool { | ||||||
|  | 	return len(raw) > 3 && | ||||||
|  | 		raw[0] == 0x50 && raw[1] == 0x4B && | ||||||
|  | 		(raw[2] == 0x3 || raw[2] == 0x5 || raw[2] == 0x7) && | ||||||
|  | 		(raw[3] == 0x4 || raw[3] == 0x6 || raw[3] == 0x8) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Jar matches a Java archive file. | ||||||
|  | func Jar(raw []byte, limit uint32) bool { | ||||||
|  | 	return zipContains(raw, "META-INF/MANIFEST.MF") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // zipTokenizer holds the source zip file and scanned index. | ||||||
|  | type zipTokenizer struct { | ||||||
|  | 	in []byte | ||||||
|  | 	i  int // current index | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // next returns the next file name from the zip headers. | ||||||
|  | // https://web.archive.org/web/20191129114319/https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html | ||||||
|  | func (t *zipTokenizer) next() (fileName string) { | ||||||
|  | 	if t.i > len(t.in) { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	in := t.in[t.i:] | ||||||
|  | 	// pkSig is the signature of the zip local file header. | ||||||
|  | 	pkSig := []byte("PK\003\004") | ||||||
|  | 	pkIndex := bytes.Index(in, pkSig) | ||||||
|  | 	// 30 is the offset of the file name in the header. | ||||||
|  | 	fNameOffset := pkIndex + 30 | ||||||
|  | 	// end if signature not found or file name offset outside of file. | ||||||
|  | 	if pkIndex == -1 || fNameOffset > len(in) { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fNameLen := int(binary.LittleEndian.Uint16(in[pkIndex+26 : pkIndex+28])) | ||||||
|  | 	if fNameLen <= 0 || fNameOffset+fNameLen > len(in) { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	t.i += fNameOffset + fNameLen | ||||||
|  | 	return string(in[fNameOffset : fNameOffset+fNameLen]) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // zipContains returns true if the zip file headers from in contain any of the paths. | ||||||
|  | func zipContains(in []byte, paths ...string) bool { | ||||||
|  | 	t := zipTokenizer{in: in} | ||||||
|  | 	for i, tok := 0, t.next(); tok != ""; i, tok = i+1, t.next() { | ||||||
|  | 		for p := range paths { | ||||||
|  | 			if strings.HasPrefix(tok, paths[p]) { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
							
								
								
									
										186
									
								
								vendor/github.com/gabriel-vasile/mimetype/mime.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								vendor/github.com/gabriel-vasile/mimetype/mime.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,186 @@ | ||||||
|  | package mimetype | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"mime" | ||||||
|  | 
 | ||||||
|  | 	"github.com/gabriel-vasile/mimetype/internal/charset" | ||||||
|  | 	"github.com/gabriel-vasile/mimetype/internal/magic" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // MIME struct holds information about a file format: the string representation | ||||||
|  | // of the MIME type, the extension and the parent file format. | ||||||
|  | type MIME struct { | ||||||
|  | 	mime      string | ||||||
|  | 	aliases   []string | ||||||
|  | 	extension string | ||||||
|  | 	// detector receives the raw input and a limit for the number of bytes it is | ||||||
|  | 	// allowed to check. It returns whether the input matches a signature or not. | ||||||
|  | 	detector magic.Detector | ||||||
|  | 	children []*MIME | ||||||
|  | 	parent   *MIME | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // String returns the string representation of the MIME type, e.g., "application/zip". | ||||||
|  | func (m *MIME) String() string { | ||||||
|  | 	return m.mime | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Extension returns the file extension associated with the MIME type. | ||||||
|  | // It includes the leading dot, as in ".html". When the file format does not | ||||||
|  | // have an extension, the empty string is returned. | ||||||
|  | func (m *MIME) Extension() string { | ||||||
|  | 	return m.extension | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Parent returns the parent MIME type from the hierarchy. | ||||||
|  | // Each MIME type has a non-nil parent, except for the root MIME type. | ||||||
|  | // | ||||||
|  | // For example, the application/json and text/html MIME types have text/plain as | ||||||
|  | // their parent because they are text files who happen to contain JSON or HTML. | ||||||
|  | // Another example is the ZIP format, which is used as container | ||||||
|  | // for Microsoft Office files, EPUB files, JAR files, and others. | ||||||
|  | func (m *MIME) Parent() *MIME { | ||||||
|  | 	return m.parent | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Is checks whether this MIME type, or any of its aliases, is equal to the | ||||||
|  | // expected MIME type. MIME type equality test is done on the "type/subtype" | ||||||
|  | // section, ignores any optional MIME parameters, ignores any leading and | ||||||
|  | // trailing whitespace, and is case insensitive. | ||||||
|  | func (m *MIME) Is(expectedMIME string) bool { | ||||||
|  | 	// Parsing is needed because some detected MIME types contain parameters | ||||||
|  | 	// that need to be stripped for the comparison. | ||||||
|  | 	expectedMIME, _, _ = mime.ParseMediaType(expectedMIME) | ||||||
|  | 	found, _, _ := mime.ParseMediaType(m.mime) | ||||||
|  | 
 | ||||||
|  | 	if expectedMIME == found { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, alias := range m.aliases { | ||||||
|  | 		if alias == expectedMIME { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newMIME( | ||||||
|  | 	mime, extension string, | ||||||
|  | 	detector magic.Detector, | ||||||
|  | 	children ...*MIME) *MIME { | ||||||
|  | 	m := &MIME{ | ||||||
|  | 		mime:      mime, | ||||||
|  | 		extension: extension, | ||||||
|  | 		detector:  detector, | ||||||
|  | 		children:  children, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, c := range children { | ||||||
|  | 		c.parent = m | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return m | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (m *MIME) alias(aliases ...string) *MIME { | ||||||
|  | 	m.aliases = aliases | ||||||
|  | 	return m | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // match does a depth-first search on the signature tree. It returns the deepest | ||||||
|  | // successful node for which all the children detection functions fail. | ||||||
|  | func (m *MIME) match(in []byte, readLimit uint32) *MIME { | ||||||
|  | 	for _, c := range m.children { | ||||||
|  | 		if c.detector(in, readLimit) { | ||||||
|  | 			return c.match(in, readLimit) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	needsCharset := map[string]func([]byte) string{ | ||||||
|  | 		"text/plain": charset.FromPlain, | ||||||
|  | 		"text/html":  charset.FromHTML, | ||||||
|  | 		"text/xml":   charset.FromXML, | ||||||
|  | 	} | ||||||
|  | 	// ps holds optional MIME parameters. | ||||||
|  | 	ps := map[string]string{} | ||||||
|  | 	if f, ok := needsCharset[m.mime]; ok { | ||||||
|  | 		if cset := f(in); cset != "" { | ||||||
|  | 			ps["charset"] = cset | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return m.cloneHierarchy(ps) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // flatten transforms an hierarchy of MIMEs into a slice of MIMEs. | ||||||
|  | func (m *MIME) flatten() []*MIME { | ||||||
|  | 	out := []*MIME{m} | ||||||
|  | 	for _, c := range m.children { | ||||||
|  | 		out = append(out, c.flatten()...) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // clone creates a new MIME with the provided optional MIME parameters. | ||||||
|  | func (m *MIME) clone(ps map[string]string) *MIME { | ||||||
|  | 	clonedMIME := m.mime | ||||||
|  | 	if len(ps) > 0 { | ||||||
|  | 		clonedMIME = mime.FormatMediaType(m.mime, ps) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return &MIME{ | ||||||
|  | 		mime:      clonedMIME, | ||||||
|  | 		aliases:   m.aliases, | ||||||
|  | 		extension: m.extension, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // cloneHierarchy creates a clone of m and all its ancestors. The optional MIME | ||||||
|  | // parameters are set on the last child of the hierarchy. | ||||||
|  | func (m *MIME) cloneHierarchy(ps map[string]string) *MIME { | ||||||
|  | 	ret := m.clone(ps) | ||||||
|  | 	lastChild := ret | ||||||
|  | 	for p := m.Parent(); p != nil; p = p.Parent() { | ||||||
|  | 		pClone := p.clone(nil) | ||||||
|  | 		lastChild.parent = pClone | ||||||
|  | 		lastChild = pClone | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (m *MIME) lookup(mime string) *MIME { | ||||||
|  | 	for _, n := range append(m.aliases, m.mime) { | ||||||
|  | 		if n == mime { | ||||||
|  | 			return m | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, c := range m.children { | ||||||
|  | 		if m := c.lookup(mime); m != nil { | ||||||
|  | 			return m | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Extend adds detection for a sub-format. The detector is a function | ||||||
|  | // returning true when the raw input file satisfies a signature. | ||||||
|  | // The sub-format will be detected if all the detectors in the parent chain return true. | ||||||
|  | // The extension should include the leading dot, as in ".html". | ||||||
|  | func (m *MIME) Extend(detector func(raw []byte, limit uint32) bool, mime, extension string, aliases ...string) { | ||||||
|  | 	c := &MIME{ | ||||||
|  | 		mime:      mime, | ||||||
|  | 		extension: extension, | ||||||
|  | 		detector:  detector, | ||||||
|  | 		parent:    m, | ||||||
|  | 		aliases:   aliases, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mu.Lock() | ||||||
|  | 	m.children = append([]*MIME{c}, m.children...) | ||||||
|  | 	mu.Unlock() | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								vendor/github.com/gabriel-vasile/mimetype/mimetype.gif
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								vendor/github.com/gabriel-vasile/mimetype/mimetype.gif
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.3 MiB | 
							
								
								
									
										123
									
								
								vendor/github.com/gabriel-vasile/mimetype/mimetype.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								vendor/github.com/gabriel-vasile/mimetype/mimetype.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,123 @@ | ||||||
|  | // Package mimetype uses magic number signatures to detect the MIME type of a file. | ||||||
|  | // | ||||||
|  | // File formats are stored in a hierarchy with application/octet-stream at its root. | ||||||
|  | // For example, the hierarchy for HTML format is application/octet-stream -> | ||||||
|  | // text/plain -> text/html. | ||||||
|  | package mimetype | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"mime" | ||||||
|  | 	"os" | ||||||
|  | 	"sync/atomic" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // readLimit is the maximum number of bytes from the input used when detecting. | ||||||
|  | var readLimit uint32 = 3072 | ||||||
|  | 
 | ||||||
|  | // Detect returns the MIME type found from the provided byte slice. | ||||||
|  | // | ||||||
|  | // The result is always a valid MIME type, with application/octet-stream | ||||||
|  | // returned when identification failed. | ||||||
|  | func Detect(in []byte) *MIME { | ||||||
|  | 	// Using atomic because readLimit can be written at the same time in other goroutine. | ||||||
|  | 	l := atomic.LoadUint32(&readLimit) | ||||||
|  | 	if l > 0 && len(in) > int(l) { | ||||||
|  | 		in = in[:l] | ||||||
|  | 	} | ||||||
|  | 	mu.RLock() | ||||||
|  | 	defer mu.RUnlock() | ||||||
|  | 	return root.match(in, l) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DetectReader returns the MIME type of the provided reader. | ||||||
|  | // | ||||||
|  | // The result is always a valid MIME type, with application/octet-stream | ||||||
|  | // returned when identification failed with or without an error. | ||||||
|  | // Any error returned is related to the reading from the input reader. | ||||||
|  | // | ||||||
|  | // DetectReader assumes the reader offset is at the start. If the input is an | ||||||
|  | // io.ReadSeeker you previously read from, it should be rewinded before detection: | ||||||
|  | //  reader.Seek(0, io.SeekStart) | ||||||
|  | func DetectReader(r io.Reader) (*MIME, error) { | ||||||
|  | 	var in []byte | ||||||
|  | 	var err error | ||||||
|  | 
 | ||||||
|  | 	// Using atomic because readLimit can be written at the same time in other goroutine. | ||||||
|  | 	l := atomic.LoadUint32(&readLimit) | ||||||
|  | 	if l == 0 { | ||||||
|  | 		in, err = ioutil.ReadAll(r) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return errMIME, err | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		var n int | ||||||
|  | 		in = make([]byte, l) | ||||||
|  | 		// io.UnexpectedEOF means len(r) < len(in). It is not an error in this case, | ||||||
|  | 		// it just means the input file is smaller than the allocated bytes slice. | ||||||
|  | 		n, err = io.ReadFull(r, in) | ||||||
|  | 		if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { | ||||||
|  | 			return errMIME, err | ||||||
|  | 		} | ||||||
|  | 		in = in[:n] | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mu.RLock() | ||||||
|  | 	defer mu.RUnlock() | ||||||
|  | 	return root.match(in, l), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DetectFile returns the MIME type of the provided file. | ||||||
|  | // | ||||||
|  | // The result is always a valid MIME type, with application/octet-stream | ||||||
|  | // returned when identification failed with or without an error. | ||||||
|  | // Any error returned is related to the opening and reading from the input file. | ||||||
|  | func DetectFile(path string) (*MIME, error) { | ||||||
|  | 	f, err := os.Open(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return errMIME, err | ||||||
|  | 	} | ||||||
|  | 	defer f.Close() | ||||||
|  | 
 | ||||||
|  | 	return DetectReader(f) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // EqualsAny reports whether s MIME type is equal to any MIME type in mimes. | ||||||
|  | // MIME type equality test is done on the "type/subtype" section, ignores | ||||||
|  | // any optional MIME parameters, ignores any leading and trailing whitespace, | ||||||
|  | // and is case insensitive. | ||||||
|  | func EqualsAny(s string, mimes ...string) bool { | ||||||
|  | 	s, _, _ = mime.ParseMediaType(s) | ||||||
|  | 	for _, m := range mimes { | ||||||
|  | 		m, _, _ = mime.ParseMediaType(m) | ||||||
|  | 		if s == m { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SetLimit sets the maximum number of bytes read from input when detecting the MIME type. | ||||||
|  | // Increasing the limit provides better detection for file formats which store | ||||||
|  | // their magical numbers towards the end of the file: docx, pptx, xlsx, etc. | ||||||
|  | // A limit of 0 means the whole input file will be used. | ||||||
|  | func SetLimit(limit uint32) { | ||||||
|  | 	// Using atomic because readLimit can be read at the same time in other goroutine. | ||||||
|  | 	atomic.StoreUint32(&readLimit, limit) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Extend adds detection for other file formats. | ||||||
|  | // It is equivalent to calling Extend() on the root mime type "application/octet-stream". | ||||||
|  | func Extend(detector func(raw []byte, limit uint32) bool, mime, extension string, aliases ...string) { | ||||||
|  | 	root.Extend(detector, mime, extension, aliases...) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Lookup finds a MIME object by its string representation. | ||||||
|  | // The representation can be the main mime type, or any of its aliases. | ||||||
|  | func Lookup(mime string) *MIME { | ||||||
|  | 	mu.RLock() | ||||||
|  | 	defer mu.RUnlock() | ||||||
|  | 	return root.lookup(mime) | ||||||
|  | } | ||||||
							
								
								
									
										178
									
								
								vendor/github.com/gabriel-vasile/mimetype/supported_mimes.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								vendor/github.com/gabriel-vasile/mimetype/supported_mimes.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,178 @@ | ||||||
|  | ## 172 Supported MIME types | ||||||
|  | This file is automatically generated when running tests. Do not edit manually. | ||||||
|  | 
 | ||||||
|  | Extension | MIME type | Aliases | ||||||
|  | --------- | --------- | ------- | ||||||
|  | **n/a** | application/octet-stream | - | ||||||
|  | **.xpm** | image/x-xpixmap | - | ||||||
|  | **.7z** | application/x-7z-compressed | - | ||||||
|  | **.zip** | application/zip | application/x-zip, application/x-zip-compressed | ||||||
|  | **.xlsx** | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | - | ||||||
|  | **.docx** | application/vnd.openxmlformats-officedocument.wordprocessingml.document | - | ||||||
|  | **.pptx** | application/vnd.openxmlformats-officedocument.presentationml.presentation | - | ||||||
|  | **.epub** | application/epub+zip | - | ||||||
|  | **.jar** | application/jar | - | ||||||
|  | **.odt** | application/vnd.oasis.opendocument.text | application/x-vnd.oasis.opendocument.text | ||||||
|  | **.ott** | application/vnd.oasis.opendocument.text-template | application/x-vnd.oasis.opendocument.text-template | ||||||
|  | **.ods** | application/vnd.oasis.opendocument.spreadsheet | application/x-vnd.oasis.opendocument.spreadsheet | ||||||
|  | **.ots** | application/vnd.oasis.opendocument.spreadsheet-template | application/x-vnd.oasis.opendocument.spreadsheet-template | ||||||
|  | **.odp** | application/vnd.oasis.opendocument.presentation | application/x-vnd.oasis.opendocument.presentation | ||||||
|  | **.otp** | application/vnd.oasis.opendocument.presentation-template | application/x-vnd.oasis.opendocument.presentation-template | ||||||
|  | **.odg** | application/vnd.oasis.opendocument.graphics | application/x-vnd.oasis.opendocument.graphics | ||||||
|  | **.otg** | application/vnd.oasis.opendocument.graphics-template | application/x-vnd.oasis.opendocument.graphics-template | ||||||
|  | **.odf** | application/vnd.oasis.opendocument.formula | application/x-vnd.oasis.opendocument.formula | ||||||
|  | **.odc** | application/vnd.oasis.opendocument.chart | application/x-vnd.oasis.opendocument.chart | ||||||
|  | **.sxc** | application/vnd.sun.xml.calc | - | ||||||
|  | **.pdf** | application/pdf | application/x-pdf | ||||||
|  | **.fdf** | application/vnd.fdf | - | ||||||
|  | **n/a** | application/x-ole-storage | - | ||||||
|  | **.msi** | application/x-ms-installer | application/x-windows-installer, application/x-msi | ||||||
|  | **.aaf** | application/octet-stream | - | ||||||
|  | **.msg** | application/vnd.ms-outlook | - | ||||||
|  | **.xls** | application/vnd.ms-excel | application/msexcel | ||||||
|  | **.pub** | application/vnd.ms-publisher | - | ||||||
|  | **.ppt** | application/vnd.ms-powerpoint | application/mspowerpoint | ||||||
|  | **.doc** | application/msword | application/vnd.ms-word | ||||||
|  | **.ps** | application/postscript | - | ||||||
|  | **.psd** | image/vnd.adobe.photoshop | image/x-psd, application/photoshop | ||||||
|  | **.p7s** | application/pkcs7-signature | - | ||||||
|  | **.ogg** | application/ogg | application/x-ogg | ||||||
|  | **.oga** | audio/ogg | - | ||||||
|  | **.ogv** | video/ogg | - | ||||||
|  | **.png** | image/png | - | ||||||
|  | **.png** | image/vnd.mozilla.apng | - | ||||||
|  | **.jpg** | image/jpeg | - | ||||||
|  | **.jxl** | image/jxl | - | ||||||
|  | **.jp2** | image/jp2 | - | ||||||
|  | **.jpf** | image/jpx | - | ||||||
|  | **.jpm** | image/jpm | video/jpm | ||||||
|  | **.jxs** | image/jxs | - | ||||||
|  | **.gif** | image/gif | - | ||||||
|  | **.webp** | image/webp | - | ||||||
|  | **.exe** | application/vnd.microsoft.portable-executable | - | ||||||
|  | **n/a** | application/x-elf | - | ||||||
|  | **n/a** | application/x-object | - | ||||||
|  | **n/a** | application/x-executable | - | ||||||
|  | **.so** | application/x-sharedlib | - | ||||||
|  | **n/a** | application/x-coredump | - | ||||||
|  | **.a** | application/x-archive | application/x-unix-archive | ||||||
|  | **.deb** | application/vnd.debian.binary-package | - | ||||||
|  | **.tar** | application/x-tar | - | ||||||
|  | **.xar** | application/x-xar | - | ||||||
|  | **.bz2** | application/x-bzip2 | - | ||||||
|  | **.fits** | application/fits | - | ||||||
|  | **.tiff** | image/tiff | - | ||||||
|  | **.bmp** | image/bmp | image/x-bmp, image/x-ms-bmp | ||||||
|  | **.ico** | image/x-icon | - | ||||||
|  | **.mp3** | audio/mpeg | audio/x-mpeg, audio/mp3 | ||||||
|  | **.flac** | audio/flac | - | ||||||
|  | **.midi** | audio/midi | audio/mid, audio/sp-midi, audio/x-mid, audio/x-midi | ||||||
|  | **.ape** | audio/ape | - | ||||||
|  | **.mpc** | audio/musepack | - | ||||||
|  | **.amr** | audio/amr | audio/amr-nb | ||||||
|  | **.wav** | audio/wav | audio/x-wav, audio/vnd.wave, audio/wave | ||||||
|  | **.aiff** | audio/aiff | audio/x-aiff | ||||||
|  | **.au** | audio/basic | - | ||||||
|  | **.mpeg** | video/mpeg | - | ||||||
|  | **.mov** | video/quicktime | - | ||||||
|  | **.mqv** | video/quicktime | - | ||||||
|  | **.mp4** | video/mp4 | - | ||||||
|  | **.webm** | video/webm | audio/webm | ||||||
|  | **.3gp** | video/3gpp | video/3gp, audio/3gpp | ||||||
|  | **.3g2** | video/3gpp2 | video/3g2, audio/3gpp2 | ||||||
|  | **.avi** | video/x-msvideo | video/avi, video/msvideo | ||||||
|  | **.flv** | video/x-flv | - | ||||||
|  | **.mkv** | video/x-matroska | - | ||||||
|  | **.asf** | video/x-ms-asf | video/asf, video/x-ms-wmv | ||||||
|  | **.aac** | audio/aac | - | ||||||
|  | **.voc** | audio/x-unknown | - | ||||||
|  | **.mp4** | audio/mp4 | audio/x-m4a, audio/x-mp4a | ||||||
|  | **.m4a** | audio/x-m4a | - | ||||||
|  | **.m3u** | application/vnd.apple.mpegurl | audio/mpegurl | ||||||
|  | **.m4v** | video/x-m4v | - | ||||||
|  | **.rmvb** | application/vnd.rn-realmedia-vbr | - | ||||||
|  | **.gz** | application/gzip | application/x-gzip, application/x-gunzip, application/gzipped, application/gzip-compressed, application/x-gzip-compressed, gzip/document | ||||||
|  | **.class** | application/x-java-applet | - | ||||||
|  | **.swf** | application/x-shockwave-flash | - | ||||||
|  | **.crx** | application/x-chrome-extension | - | ||||||
|  | **.ttf** | font/ttf | font/sfnt, application/x-font-ttf, application/font-sfnt | ||||||
|  | **.woff** | font/woff | - | ||||||
|  | **.woff2** | font/woff2 | - | ||||||
|  | **.otf** | font/otf | - | ||||||
|  | **.ttc** | font/collection | - | ||||||
|  | **.eot** | application/vnd.ms-fontobject | - | ||||||
|  | **.wasm** | application/wasm | - | ||||||
|  | **.shx** | application/vnd.shx | - | ||||||
|  | **.shp** | application/vnd.shp | - | ||||||
|  | **.dbf** | application/x-dbf | - | ||||||
|  | **.dcm** | application/dicom | - | ||||||
|  | **.rar** | application/x-rar-compressed | application/x-rar | ||||||
|  | **.djvu** | image/vnd.djvu | - | ||||||
|  | **.mobi** | application/x-mobipocket-ebook | - | ||||||
|  | **.lit** | application/x-ms-reader | - | ||||||
|  | **.bpg** | image/bpg | - | ||||||
|  | **.sqlite** | application/vnd.sqlite3 | application/x-sqlite3 | ||||||
|  | **.dwg** | image/vnd.dwg | image/x-dwg, application/acad, application/x-acad, application/autocad_dwg, application/dwg, application/x-dwg, application/x-autocad, drawing/dwg | ||||||
|  | **.nes** | application/vnd.nintendo.snes.rom | - | ||||||
|  | **.lnk** | application/x-ms-shortcut | - | ||||||
|  | **.macho** | application/x-mach-binary | - | ||||||
|  | **.qcp** | audio/qcelp | - | ||||||
|  | **.icns** | image/x-icns | - | ||||||
|  | **.heic** | image/heic | - | ||||||
|  | **.heic** | image/heic-sequence | - | ||||||
|  | **.heif** | image/heif | - | ||||||
|  | **.heif** | image/heif-sequence | - | ||||||
|  | **.hdr** | image/vnd.radiance | - | ||||||
|  | **.mrc** | application/marc | - | ||||||
|  | **.mdb** | application/x-msaccess | - | ||||||
|  | **.accdb** | application/x-msaccess | - | ||||||
|  | **.zst** | application/zstd | - | ||||||
|  | **.cab** | application/vnd.ms-cab-compressed | - | ||||||
|  | **.rpm** | application/x-rpm | - | ||||||
|  | **.xz** | application/x-xz | - | ||||||
|  | **.lz** | application/lzip | application/x-lzip | ||||||
|  | **.torrent** | application/x-bittorrent | - | ||||||
|  | **.cpio** | application/x-cpio | - | ||||||
|  | **n/a** | application/tzif | - | ||||||
|  | **.xcf** | image/x-xcf | - | ||||||
|  | **.pat** | image/x-gimp-pat | - | ||||||
|  | **.gbr** | image/x-gimp-gbr | - | ||||||
|  | **.glb** | model/gltf-binary | - | ||||||
|  | **.avif** | image/avif | - | ||||||
|  | **.cab** | application/x-installshield | - | ||||||
|  | **.jxr** | image/jxr | image/vnd.ms-photo | ||||||
|  | **.txt** | text/plain | - | ||||||
|  | **.html** | text/html | - | ||||||
|  | **.svg** | image/svg+xml | - | ||||||
|  | **.xml** | text/xml | - | ||||||
|  | **.rss** | application/rss+xml | text/rss | ||||||
|  | **.atom** | application/atom+xml | - | ||||||
|  | **.x3d** | model/x3d+xml | - | ||||||
|  | **.kml** | application/vnd.google-earth.kml+xml | - | ||||||
|  | **.xlf** | application/x-xliff+xml | - | ||||||
|  | **.dae** | model/vnd.collada+xml | - | ||||||
|  | **.gml** | application/gml+xml | - | ||||||
|  | **.gpx** | application/gpx+xml | - | ||||||
|  | **.tcx** | application/vnd.garmin.tcx+xml | - | ||||||
|  | **.amf** | application/x-amf | - | ||||||
|  | **.3mf** | application/vnd.ms-package.3dmanufacturing-3dmodel+xml | - | ||||||
|  | **.xfdf** | application/vnd.adobe.xfdf | - | ||||||
|  | **.owl** | application/owl+xml | - | ||||||
|  | **.php** | text/x-php | - | ||||||
|  | **.js** | application/javascript | application/x-javascript, text/javascript | ||||||
|  | **.lua** | text/x-lua | - | ||||||
|  | **.pl** | text/x-perl | - | ||||||
|  | **.py** | text/x-python | text/x-script.python, application/x-python | ||||||
|  | **.json** | application/json | - | ||||||
|  | **.geojson** | application/geo+json | - | ||||||
|  | **.har** | application/json | - | ||||||
|  | **.ndjson** | application/x-ndjson | - | ||||||
|  | **.rtf** | text/rtf | - | ||||||
|  | **.srt** | application/x-subrip | application/x-srt, text/x-srt | ||||||
|  | **.tcl** | text/x-tcl | application/x-tcl | ||||||
|  | **.csv** | text/csv | - | ||||||
|  | **.tsv** | text/tab-separated-values | - | ||||||
|  | **.vcf** | text/vcard | - | ||||||
|  | **.ics** | text/calendar | - | ||||||
|  | **.warc** | application/warc | - | ||||||
|  | **.vtt** | text/vtt | - | ||||||
							
								
								
									
										260
									
								
								vendor/github.com/gabriel-vasile/mimetype/tree.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								vendor/github.com/gabriel-vasile/mimetype/tree.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,260 @@ | ||||||
|  | package mimetype | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"sync" | ||||||
|  | 
 | ||||||
|  | 	"github.com/gabriel-vasile/mimetype/internal/magic" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // mimetype stores the list of MIME types in a tree structure with | ||||||
|  | // "application/octet-stream" at the root of the hierarchy. The hierarchy | ||||||
|  | // approach minimizes the number of checks that need to be done on the input | ||||||
|  | // and allows for more precise results once the base type of file has been | ||||||
|  | // identified. | ||||||
|  | // | ||||||
|  | // root is a detector which passes for any slice of bytes. | ||||||
|  | // When a detector passes the check, the children detectors | ||||||
|  | // are tried in order to find a more accurate MIME type. | ||||||
|  | var root = newMIME("application/octet-stream", "", | ||||||
|  | 	func([]byte, uint32) bool { return true }, | ||||||
|  | 	xpm, sevenZ, zip, pdf, fdf, ole, ps, psd, p7s, ogg, png, jpg, jxl, jp2, jpx, | ||||||
|  | 	jpm, jxs, gif, webp, exe, elf, ar, tar, xar, bz2, fits, tiff, bmp, ico, mp3, flac, | ||||||
|  | 	midi, ape, musePack, amr, wav, aiff, au, mpeg, quickTime, mqv, mp4, webM, | ||||||
|  | 	threeGP, threeG2, avi, flv, mkv, asf, aac, voc, aMp4, m4a, m3u, m4v, rmvb, | ||||||
|  | 	gzip, class, swf, crx, ttf, woff, woff2, otf, ttc, eot, wasm, shx, dbf, dcm, rar, | ||||||
|  | 	djvu, mobi, lit, bpg, sqlite3, dwg, nes, lnk, macho, qcp, icns, heic, | ||||||
|  | 	heicSeq, heif, heifSeq, hdr, mrc, mdb, accdb, zstd, cab, rpm, xz, lzip, | ||||||
|  | 	torrent, cpio, tzif, xcf, pat, gbr, glb, avif, cabIS, jxr, | ||||||
|  | 	// Keep text last because it is the slowest check | ||||||
|  | 	text, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // errMIME is returned from Detect functions when err is not nil. | ||||||
|  | // Detect could return root for erroneous cases, but it needs to lock mu in order to do so. | ||||||
|  | // errMIME is same as root but it does not require locking. | ||||||
|  | var errMIME = newMIME("application/octet-stream", "", func([]byte, uint32) bool { return false }) | ||||||
|  | 
 | ||||||
|  | // mu guards access to the root MIME tree. Access to root must be synchronized with this lock. | ||||||
|  | var mu = &sync.RWMutex{} | ||||||
|  | 
 | ||||||
|  | // The list of nodes appended to the root node. | ||||||
|  | var ( | ||||||
|  | 	xz   = newMIME("application/x-xz", ".xz", magic.Xz) | ||||||
|  | 	gzip = newMIME("application/gzip", ".gz", magic.Gzip).alias( | ||||||
|  | 		"application/x-gzip", "application/x-gunzip", "application/gzipped", | ||||||
|  | 		"application/gzip-compressed", "application/x-gzip-compressed", | ||||||
|  | 		"gzip/document") | ||||||
|  | 	sevenZ = newMIME("application/x-7z-compressed", ".7z", magic.SevenZ) | ||||||
|  | 	zip    = newMIME("application/zip", ".zip", magic.Zip, xlsx, docx, pptx, epub, jar, odt, ods, odp, odg, odf, odc, sxc). | ||||||
|  | 		alias("application/x-zip", "application/x-zip-compressed") | ||||||
|  | 	tar = newMIME("application/x-tar", ".tar", magic.Tar) | ||||||
|  | 	xar = newMIME("application/x-xar", ".xar", magic.Xar) | ||||||
|  | 	bz2 = newMIME("application/x-bzip2", ".bz2", magic.Bz2) | ||||||
|  | 	pdf = newMIME("application/pdf", ".pdf", magic.Pdf). | ||||||
|  | 		alias("application/x-pdf") | ||||||
|  | 	fdf  = newMIME("application/vnd.fdf", ".fdf", magic.Fdf) | ||||||
|  | 	xlsx = newMIME("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".xlsx", magic.Xlsx) | ||||||
|  | 	docx = newMIME("application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".docx", magic.Docx) | ||||||
|  | 	pptx = newMIME("application/vnd.openxmlformats-officedocument.presentationml.presentation", ".pptx", magic.Pptx) | ||||||
|  | 	epub = newMIME("application/epub+zip", ".epub", magic.Epub) | ||||||
|  | 	jar  = newMIME("application/jar", ".jar", magic.Jar) | ||||||
|  | 	ole  = newMIME("application/x-ole-storage", "", magic.Ole, msi, aaf, msg, xls, pub, ppt, doc) | ||||||
|  | 	msi  = newMIME("application/x-ms-installer", ".msi", magic.Msi). | ||||||
|  | 		alias("application/x-windows-installer", "application/x-msi") | ||||||
|  | 	aaf = newMIME("application/octet-stream", ".aaf", magic.Aaf) | ||||||
|  | 	doc = newMIME("application/msword", ".doc", magic.Doc). | ||||||
|  | 		alias("application/vnd.ms-word") | ||||||
|  | 	ppt = newMIME("application/vnd.ms-powerpoint", ".ppt", magic.Ppt). | ||||||
|  | 		alias("application/mspowerpoint") | ||||||
|  | 	pub = newMIME("application/vnd.ms-publisher", ".pub", magic.Pub) | ||||||
|  | 	xls = newMIME("application/vnd.ms-excel", ".xls", magic.Xls). | ||||||
|  | 		alias("application/msexcel") | ||||||
|  | 	msg  = newMIME("application/vnd.ms-outlook", ".msg", magic.Msg) | ||||||
|  | 	ps   = newMIME("application/postscript", ".ps", magic.Ps) | ||||||
|  | 	fits = newMIME("application/fits", ".fits", magic.Fits) | ||||||
|  | 	ogg  = newMIME("application/ogg", ".ogg", magic.Ogg, oggAudio, oggVideo). | ||||||
|  | 		alias("application/x-ogg") | ||||||
|  | 	oggAudio = newMIME("audio/ogg", ".oga", magic.OggAudio) | ||||||
|  | 	oggVideo = newMIME("video/ogg", ".ogv", magic.OggVideo) | ||||||
|  | 	text     = newMIME("text/plain", ".txt", magic.Text, html, svg, xml, php, js, lua, perl, python, json, ndJSON, rtf, srt, tcl, csv, tsv, vCard, iCalendar, warc, vtt) | ||||||
|  | 	xml      = newMIME("text/xml", ".xml", magic.XML, rss, atom, x3d, kml, xliff, collada, gml, gpx, tcx, amf, threemf, xfdf, owl2) | ||||||
|  | 	json     = newMIME("application/json", ".json", magic.JSON, geoJSON, har) | ||||||
|  | 	har      = newMIME("application/json", ".har", magic.HAR) | ||||||
|  | 	csv      = newMIME("text/csv", ".csv", magic.Csv) | ||||||
|  | 	tsv      = newMIME("text/tab-separated-values", ".tsv", magic.Tsv) | ||||||
|  | 	geoJSON  = newMIME("application/geo+json", ".geojson", magic.GeoJSON) | ||||||
|  | 	ndJSON   = newMIME("application/x-ndjson", ".ndjson", magic.NdJSON) | ||||||
|  | 	html     = newMIME("text/html", ".html", magic.HTML) | ||||||
|  | 	php      = newMIME("text/x-php", ".php", magic.Php) | ||||||
|  | 	rtf      = newMIME("text/rtf", ".rtf", magic.Rtf) | ||||||
|  | 	js       = newMIME("application/javascript", ".js", magic.Js). | ||||||
|  | 			alias("application/x-javascript", "text/javascript") | ||||||
|  | 	srt = newMIME("application/x-subrip", ".srt", magic.Srt). | ||||||
|  | 		alias("application/x-srt", "text/x-srt") | ||||||
|  | 	vtt    = newMIME("text/vtt", ".vtt", magic.Vtt) | ||||||
|  | 	lua    = newMIME("text/x-lua", ".lua", magic.Lua) | ||||||
|  | 	perl   = newMIME("text/x-perl", ".pl", magic.Perl) | ||||||
|  | 	python = newMIME("text/x-python", ".py", magic.Python). | ||||||
|  | 		alias("text/x-script.python", "application/x-python") | ||||||
|  | 	tcl = newMIME("text/x-tcl", ".tcl", magic.Tcl). | ||||||
|  | 		alias("application/x-tcl") | ||||||
|  | 	vCard     = newMIME("text/vcard", ".vcf", magic.VCard) | ||||||
|  | 	iCalendar = newMIME("text/calendar", ".ics", magic.ICalendar) | ||||||
|  | 	svg       = newMIME("image/svg+xml", ".svg", magic.Svg) | ||||||
|  | 	rss       = newMIME("application/rss+xml", ".rss", magic.Rss). | ||||||
|  | 			alias("text/rss") | ||||||
|  | 	owl2    = newMIME("application/owl+xml", ".owl", magic.Owl2) | ||||||
|  | 	atom    = newMIME("application/atom+xml", ".atom", magic.Atom) | ||||||
|  | 	x3d     = newMIME("model/x3d+xml", ".x3d", magic.X3d) | ||||||
|  | 	kml     = newMIME("application/vnd.google-earth.kml+xml", ".kml", magic.Kml) | ||||||
|  | 	xliff   = newMIME("application/x-xliff+xml", ".xlf", magic.Xliff) | ||||||
|  | 	collada = newMIME("model/vnd.collada+xml", ".dae", magic.Collada) | ||||||
|  | 	gml     = newMIME("application/gml+xml", ".gml", magic.Gml) | ||||||
|  | 	gpx     = newMIME("application/gpx+xml", ".gpx", magic.Gpx) | ||||||
|  | 	tcx     = newMIME("application/vnd.garmin.tcx+xml", ".tcx", magic.Tcx) | ||||||
|  | 	amf     = newMIME("application/x-amf", ".amf", magic.Amf) | ||||||
|  | 	threemf = newMIME("application/vnd.ms-package.3dmanufacturing-3dmodel+xml", ".3mf", magic.Threemf) | ||||||
|  | 	png     = newMIME("image/png", ".png", magic.Png, apng) | ||||||
|  | 	apng    = newMIME("image/vnd.mozilla.apng", ".png", magic.Apng) | ||||||
|  | 	jpg     = newMIME("image/jpeg", ".jpg", magic.Jpg) | ||||||
|  | 	jxl     = newMIME("image/jxl", ".jxl", magic.Jxl) | ||||||
|  | 	jp2     = newMIME("image/jp2", ".jp2", magic.Jp2) | ||||||
|  | 	jpx     = newMIME("image/jpx", ".jpf", magic.Jpx) | ||||||
|  | 	jpm     = newMIME("image/jpm", ".jpm", magic.Jpm). | ||||||
|  | 		alias("video/jpm") | ||||||
|  | 	jxs  = newMIME("image/jxs", ".jxs", magic.Jxs) | ||||||
|  | 	xpm  = newMIME("image/x-xpixmap", ".xpm", magic.Xpm) | ||||||
|  | 	bpg  = newMIME("image/bpg", ".bpg", magic.Bpg) | ||||||
|  | 	gif  = newMIME("image/gif", ".gif", magic.Gif) | ||||||
|  | 	webp = newMIME("image/webp", ".webp", magic.Webp) | ||||||
|  | 	tiff = newMIME("image/tiff", ".tiff", magic.Tiff) | ||||||
|  | 	bmp  = newMIME("image/bmp", ".bmp", magic.Bmp). | ||||||
|  | 		alias("image/x-bmp", "image/x-ms-bmp") | ||||||
|  | 	ico  = newMIME("image/x-icon", ".ico", magic.Ico) | ||||||
|  | 	icns = newMIME("image/x-icns", ".icns", magic.Icns) | ||||||
|  | 	psd  = newMIME("image/vnd.adobe.photoshop", ".psd", magic.Psd). | ||||||
|  | 		alias("image/x-psd", "application/photoshop") | ||||||
|  | 	heic    = newMIME("image/heic", ".heic", magic.Heic) | ||||||
|  | 	heicSeq = newMIME("image/heic-sequence", ".heic", magic.HeicSequence) | ||||||
|  | 	heif    = newMIME("image/heif", ".heif", magic.Heif) | ||||||
|  | 	heifSeq = newMIME("image/heif-sequence", ".heif", magic.HeifSequence) | ||||||
|  | 	hdr     = newMIME("image/vnd.radiance", ".hdr", magic.Hdr) | ||||||
|  | 	avif    = newMIME("image/avif", ".avif", magic.AVIF) | ||||||
|  | 	mp3     = newMIME("audio/mpeg", ".mp3", magic.Mp3). | ||||||
|  | 		alias("audio/x-mpeg", "audio/mp3") | ||||||
|  | 	flac = newMIME("audio/flac", ".flac", magic.Flac) | ||||||
|  | 	midi = newMIME("audio/midi", ".midi", magic.Midi). | ||||||
|  | 		alias("audio/mid", "audio/sp-midi", "audio/x-mid", "audio/x-midi") | ||||||
|  | 	ape      = newMIME("audio/ape", ".ape", magic.Ape) | ||||||
|  | 	musePack = newMIME("audio/musepack", ".mpc", magic.MusePack) | ||||||
|  | 	wav      = newMIME("audio/wav", ".wav", magic.Wav). | ||||||
|  | 			alias("audio/x-wav", "audio/vnd.wave", "audio/wave") | ||||||
|  | 	aiff = newMIME("audio/aiff", ".aiff", magic.Aiff).alias("audio/x-aiff") | ||||||
|  | 	au   = newMIME("audio/basic", ".au", magic.Au) | ||||||
|  | 	amr  = newMIME("audio/amr", ".amr", magic.Amr). | ||||||
|  | 		alias("audio/amr-nb") | ||||||
|  | 	aac  = newMIME("audio/aac", ".aac", magic.AAC) | ||||||
|  | 	voc  = newMIME("audio/x-unknown", ".voc", magic.Voc) | ||||||
|  | 	aMp4 = newMIME("audio/mp4", ".mp4", magic.AMp4). | ||||||
|  | 		alias("audio/x-m4a", "audio/x-mp4a") | ||||||
|  | 	m4a = newMIME("audio/x-m4a", ".m4a", magic.M4a) | ||||||
|  | 	m3u = newMIME("application/vnd.apple.mpegurl", ".m3u", magic.M3u). | ||||||
|  | 		alias("audio/mpegurl") | ||||||
|  | 	m4v  = newMIME("video/x-m4v", ".m4v", magic.M4v) | ||||||
|  | 	mp4  = newMIME("video/mp4", ".mp4", magic.Mp4) | ||||||
|  | 	webM = newMIME("video/webm", ".webm", magic.WebM). | ||||||
|  | 		alias("audio/webm") | ||||||
|  | 	mpeg      = newMIME("video/mpeg", ".mpeg", magic.Mpeg) | ||||||
|  | 	quickTime = newMIME("video/quicktime", ".mov", magic.QuickTime) | ||||||
|  | 	mqv       = newMIME("video/quicktime", ".mqv", magic.Mqv) | ||||||
|  | 	threeGP   = newMIME("video/3gpp", ".3gp", magic.ThreeGP). | ||||||
|  | 			alias("video/3gp", "audio/3gpp") | ||||||
|  | 	threeG2 = newMIME("video/3gpp2", ".3g2", magic.ThreeG2). | ||||||
|  | 		alias("video/3g2", "audio/3gpp2") | ||||||
|  | 	avi = newMIME("video/x-msvideo", ".avi", magic.Avi). | ||||||
|  | 		alias("video/avi", "video/msvideo") | ||||||
|  | 	flv = newMIME("video/x-flv", ".flv", magic.Flv) | ||||||
|  | 	mkv = newMIME("video/x-matroska", ".mkv", magic.Mkv) | ||||||
|  | 	asf = newMIME("video/x-ms-asf", ".asf", magic.Asf). | ||||||
|  | 		alias("video/asf", "video/x-ms-wmv") | ||||||
|  | 	rmvb  = newMIME("application/vnd.rn-realmedia-vbr", ".rmvb", magic.Rmvb) | ||||||
|  | 	class = newMIME("application/x-java-applet", ".class", magic.Class) | ||||||
|  | 	swf   = newMIME("application/x-shockwave-flash", ".swf", magic.SWF) | ||||||
|  | 	crx   = newMIME("application/x-chrome-extension", ".crx", magic.CRX) | ||||||
|  | 	ttf   = newMIME("font/ttf", ".ttf", magic.Ttf). | ||||||
|  | 		alias("font/sfnt", "application/x-font-ttf", "application/font-sfnt") | ||||||
|  | 	woff    = newMIME("font/woff", ".woff", magic.Woff) | ||||||
|  | 	woff2   = newMIME("font/woff2", ".woff2", magic.Woff2) | ||||||
|  | 	otf     = newMIME("font/otf", ".otf", magic.Otf) | ||||||
|  | 	ttc     = newMIME("font/collection", ".ttc", magic.Ttc) | ||||||
|  | 	eot     = newMIME("application/vnd.ms-fontobject", ".eot", magic.Eot) | ||||||
|  | 	wasm    = newMIME("application/wasm", ".wasm", magic.Wasm) | ||||||
|  | 	shp     = newMIME("application/vnd.shp", ".shp", magic.Shp) | ||||||
|  | 	shx     = newMIME("application/vnd.shx", ".shx", magic.Shx, shp) | ||||||
|  | 	dbf     = newMIME("application/x-dbf", ".dbf", magic.Dbf) | ||||||
|  | 	exe     = newMIME("application/vnd.microsoft.portable-executable", ".exe", magic.Exe) | ||||||
|  | 	elf     = newMIME("application/x-elf", "", magic.Elf, elfObj, elfExe, elfLib, elfDump) | ||||||
|  | 	elfObj  = newMIME("application/x-object", "", magic.ElfObj) | ||||||
|  | 	elfExe  = newMIME("application/x-executable", "", magic.ElfExe) | ||||||
|  | 	elfLib  = newMIME("application/x-sharedlib", ".so", magic.ElfLib) | ||||||
|  | 	elfDump = newMIME("application/x-coredump", "", magic.ElfDump) | ||||||
|  | 	ar      = newMIME("application/x-archive", ".a", magic.Ar, deb). | ||||||
|  | 		alias("application/x-unix-archive") | ||||||
|  | 	deb = newMIME("application/vnd.debian.binary-package", ".deb", magic.Deb) | ||||||
|  | 	rpm = newMIME("application/x-rpm", ".rpm", magic.RPM) | ||||||
|  | 	dcm = newMIME("application/dicom", ".dcm", magic.Dcm) | ||||||
|  | 	odt = newMIME("application/vnd.oasis.opendocument.text", ".odt", magic.Odt, ott). | ||||||
|  | 		alias("application/x-vnd.oasis.opendocument.text") | ||||||
|  | 	ott = newMIME("application/vnd.oasis.opendocument.text-template", ".ott", magic.Ott). | ||||||
|  | 		alias("application/x-vnd.oasis.opendocument.text-template") | ||||||
|  | 	ods = newMIME("application/vnd.oasis.opendocument.spreadsheet", ".ods", magic.Ods, ots). | ||||||
|  | 		alias("application/x-vnd.oasis.opendocument.spreadsheet") | ||||||
|  | 	ots = newMIME("application/vnd.oasis.opendocument.spreadsheet-template", ".ots", magic.Ots). | ||||||
|  | 		alias("application/x-vnd.oasis.opendocument.spreadsheet-template") | ||||||
|  | 	odp = newMIME("application/vnd.oasis.opendocument.presentation", ".odp", magic.Odp, otp). | ||||||
|  | 		alias("application/x-vnd.oasis.opendocument.presentation") | ||||||
|  | 	otp = newMIME("application/vnd.oasis.opendocument.presentation-template", ".otp", magic.Otp). | ||||||
|  | 		alias("application/x-vnd.oasis.opendocument.presentation-template") | ||||||
|  | 	odg = newMIME("application/vnd.oasis.opendocument.graphics", ".odg", magic.Odg, otg). | ||||||
|  | 		alias("application/x-vnd.oasis.opendocument.graphics") | ||||||
|  | 	otg = newMIME("application/vnd.oasis.opendocument.graphics-template", ".otg", magic.Otg). | ||||||
|  | 		alias("application/x-vnd.oasis.opendocument.graphics-template") | ||||||
|  | 	odf = newMIME("application/vnd.oasis.opendocument.formula", ".odf", magic.Odf). | ||||||
|  | 		alias("application/x-vnd.oasis.opendocument.formula") | ||||||
|  | 	odc = newMIME("application/vnd.oasis.opendocument.chart", ".odc", magic.Odc). | ||||||
|  | 		alias("application/x-vnd.oasis.opendocument.chart") | ||||||
|  | 	sxc = newMIME("application/vnd.sun.xml.calc", ".sxc", magic.Sxc) | ||||||
|  | 	rar = newMIME("application/x-rar-compressed", ".rar", magic.RAR). | ||||||
|  | 		alias("application/x-rar") | ||||||
|  | 	djvu    = newMIME("image/vnd.djvu", ".djvu", magic.DjVu) | ||||||
|  | 	mobi    = newMIME("application/x-mobipocket-ebook", ".mobi", magic.Mobi) | ||||||
|  | 	lit     = newMIME("application/x-ms-reader", ".lit", magic.Lit) | ||||||
|  | 	sqlite3 = newMIME("application/vnd.sqlite3", ".sqlite", magic.Sqlite). | ||||||
|  | 		alias("application/x-sqlite3") | ||||||
|  | 	dwg = newMIME("image/vnd.dwg", ".dwg", magic.Dwg). | ||||||
|  | 		alias("image/x-dwg", "application/acad", "application/x-acad", | ||||||
|  | 			"application/autocad_dwg", "application/dwg", "application/x-dwg", | ||||||
|  | 			"application/x-autocad", "drawing/dwg") | ||||||
|  | 	warc    = newMIME("application/warc", ".warc", magic.Warc) | ||||||
|  | 	nes     = newMIME("application/vnd.nintendo.snes.rom", ".nes", magic.Nes) | ||||||
|  | 	lnk     = newMIME("application/x-ms-shortcut", ".lnk", magic.Lnk) | ||||||
|  | 	macho   = newMIME("application/x-mach-binary", ".macho", magic.MachO) | ||||||
|  | 	qcp     = newMIME("audio/qcelp", ".qcp", magic.Qcp) | ||||||
|  | 	mrc     = newMIME("application/marc", ".mrc", magic.Marc) | ||||||
|  | 	mdb     = newMIME("application/x-msaccess", ".mdb", magic.MsAccessMdb) | ||||||
|  | 	accdb   = newMIME("application/x-msaccess", ".accdb", magic.MsAccessAce) | ||||||
|  | 	zstd    = newMIME("application/zstd", ".zst", magic.Zstd) | ||||||
|  | 	cab     = newMIME("application/vnd.ms-cab-compressed", ".cab", magic.Cab) | ||||||
|  | 	cabIS   = newMIME("application/x-installshield", ".cab", magic.InstallShieldCab) | ||||||
|  | 	lzip    = newMIME("application/lzip", ".lz", magic.Lzip).alias("application/x-lzip") | ||||||
|  | 	torrent = newMIME("application/x-bittorrent", ".torrent", magic.Torrent) | ||||||
|  | 	cpio    = newMIME("application/x-cpio", ".cpio", magic.Cpio) | ||||||
|  | 	tzif    = newMIME("application/tzif", "", magic.TzIf) | ||||||
|  | 	p7s     = newMIME("application/pkcs7-signature", ".p7s", magic.P7s) | ||||||
|  | 	xcf     = newMIME("image/x-xcf", ".xcf", magic.Xcf) | ||||||
|  | 	pat     = newMIME("image/x-gimp-pat", ".pat", magic.Pat) | ||||||
|  | 	gbr     = newMIME("image/x-gimp-gbr", ".gbr", magic.Gbr) | ||||||
|  | 	xfdf    = newMIME("application/vnd.adobe.xfdf", ".xfdf", magic.Xfdf) | ||||||
|  | 	glb     = newMIME("model/gltf-binary", ".glb", magic.Glb) | ||||||
|  | 	jxr     = newMIME("image/jxr", ".jxr", magic.Jxr).alias("image/vnd.ms-photo") | ||||||
|  | ) | ||||||
							
								
								
									
										1
									
								
								vendor/github.com/go-playground/validator/v10/.gitignore
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/go-playground/validator/v10/.gitignore
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -26,6 +26,7 @@ _testmain.go | ||||||
| *.test | *.test | ||||||
| *.out | *.out | ||||||
| *.txt | *.txt | ||||||
|  | /**/*.DS_Store | ||||||
| cover.html | cover.html | ||||||
| README.html | README.html | ||||||
| .idea | .idea | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								vendor/github.com/go-playground/validator/v10/README.md
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/go-playground/validator/v10/README.md
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,7 +1,7 @@ | ||||||
| Package validator | Package validator | ||||||
| ================= | ================= | ||||||
| <img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v10/logo.png">[](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | <img align="right" src="https://raw.githubusercontent.com/go-playground/validator/v10/logo.png">[](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||||||
|  |  | ||||||
| [](https://travis-ci.org/go-playground/validator) | [](https://travis-ci.org/go-playground/validator) | ||||||
| [](https://coveralls.io/github/go-playground/validator?branch=master) | [](https://coveralls.io/github/go-playground/validator?branch=master) | ||||||
| [](https://goreportcard.com/report/github.com/go-playground/validator) | [](https://goreportcard.com/report/github.com/go-playground/validator) | ||||||
|  | @ -228,6 +228,7 @@ Baked-in Validations | ||||||
| | dirpath | Directory Path | | | dirpath | Directory Path | | ||||||
| | file | Existing File | | | file | Existing File | | ||||||
| | filepath | File Path | | | filepath | File Path | | ||||||
|  | | image | Image | | ||||||
| | isdefault | Is Default | | | isdefault | Is Default | | ||||||
| | len | Length | | | len | Length | | ||||||
| | max | Maximum | | | max | Maximum | | ||||||
|  |  | ||||||
							
								
								
									
										63
									
								
								vendor/github.com/go-playground/validator/v10/baked_in.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										63
									
								
								vendor/github.com/go-playground/validator/v10/baked_in.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -22,6 +22,7 @@ import ( | ||||||
| 	"golang.org/x/crypto/sha3" | 	"golang.org/x/crypto/sha3" | ||||||
| 	"golang.org/x/text/language" | 	"golang.org/x/text/language" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/gabriel-vasile/mimetype" | ||||||
| 	"github.com/leodido/go-urn" | 	"github.com/leodido/go-urn" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -144,6 +145,7 @@ var ( | ||||||
| 		"endswith":                      endsWith, | 		"endswith":                      endsWith, | ||||||
| 		"startsnotwith":                 startsNotWith, | 		"startsnotwith":                 startsNotWith, | ||||||
| 		"endsnotwith":                   endsNotWith, | 		"endsnotwith":                   endsNotWith, | ||||||
|  | 		"image":                         isImage, | ||||||
| 		"isbn":                          isISBN, | 		"isbn":                          isISBN, | ||||||
| 		"isbn10":                        isISBN10, | 		"isbn10":                        isISBN10, | ||||||
| 		"isbn13":                        isISBN13, | 		"isbn13":                        isISBN13, | ||||||
|  | @ -1488,6 +1490,67 @@ func isFile(fl FieldLevel) bool { | ||||||
| 	panic(fmt.Sprintf("Bad field type %T", field.Interface())) | 	panic(fmt.Sprintf("Bad field type %T", field.Interface())) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // isImage is the validation function for validating if the current field's value contains the path to a valid image file | ||||||
|  | func isImage(fl FieldLevel) bool { | ||||||
|  | 	mimetypes := map[string]bool{ | ||||||
|  | 		"image/bmp":                true, | ||||||
|  | 		"image/cis-cod":            true, | ||||||
|  | 		"image/gif":                true, | ||||||
|  | 		"image/ief":                true, | ||||||
|  | 		"image/jpeg":               true, | ||||||
|  | 		"image/jp2":                true, | ||||||
|  | 		"image/jpx":                true, | ||||||
|  | 		"image/jpm":                true, | ||||||
|  | 		"image/pipeg":              true, | ||||||
|  | 		"image/png":                true, | ||||||
|  | 		"image/svg+xml":            true, | ||||||
|  | 		"image/tiff":               true, | ||||||
|  | 		"image/webp":               true, | ||||||
|  | 		"image/x-cmu-raster":       true, | ||||||
|  | 		"image/x-cmx":              true, | ||||||
|  | 		"image/x-icon":             true, | ||||||
|  | 		"image/x-portable-anymap":  true, | ||||||
|  | 		"image/x-portable-bitmap":  true, | ||||||
|  | 		"image/x-portable-graymap": true, | ||||||
|  | 		"image/x-portable-pixmap":  true, | ||||||
|  | 		"image/x-rgb":              true, | ||||||
|  | 		"image/x-xbitmap":          true, | ||||||
|  | 		"image/x-xpixmap":          true, | ||||||
|  | 		"image/x-xwindowdump":      true, | ||||||
|  | 	} | ||||||
|  | 	field := fl.Field() | ||||||
|  | 
 | ||||||
|  | 	switch field.Kind() { | ||||||
|  | 	case reflect.String: | ||||||
|  | 		filePath := field.String() | ||||||
|  | 		fileInfo, err := os.Stat(filePath) | ||||||
|  | 
 | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if fileInfo.IsDir() { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		file, err := os.Open(filePath) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		defer file.Close() | ||||||
|  | 
 | ||||||
|  | 		mime, err := mimetype.DetectReader(file) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if _, ok := mimetypes[mime.String()]; ok { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // isFilePath is the validation function for validating if the current field's value is a valid file path. | // isFilePath is the validation function for validating if the current field's value is a valid file path. | ||||||
| func isFilePath(fl FieldLevel) bool { | func isFilePath(fl FieldLevel) bool { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								vendor/github.com/go-playground/validator/v10/country_codes.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/go-playground/validator/v10/country_codes.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1135,7 +1135,7 @@ var iso3166_2 = map[string]bool{ | ||||||
| 	"VN-69": true, "VN-70": true, "VN-71": true, "VN-72": true, "VN-73": true, | 	"VN-69": true, "VN-70": true, "VN-71": true, "VN-72": true, "VN-73": true, | ||||||
| 	"VN-CT": true, "VN-DN": true, "VN-HN": true, "VN-HP": true, "VN-SG": true, | 	"VN-CT": true, "VN-DN": true, "VN-HN": true, "VN-HP": true, "VN-SG": true, | ||||||
| 	"VU-MAP": true, "VU-PAM": true, "VU-SAM": true, "VU-SEE": true, "VU-TAE": true, | 	"VU-MAP": true, "VU-PAM": true, "VU-SAM": true, "VU-SEE": true, "VU-TAE": true, | ||||||
| 	"VU-TOB": true, "WF-SG": true,"WF-UV": true,  "WS-AA": true, "WS-AL": true, "WS-AT": true, "WS-FA": true, | 	"VU-TOB": true, "WF-SG": true, "WF-UV": true, "WS-AA": true, "WS-AL": true, "WS-AT": true, "WS-FA": true, | ||||||
| 	"WS-GE": true, "WS-GI": true, "WS-PA": true, "WS-SA": true, "WS-TU": true, | 	"WS-GE": true, "WS-GI": true, "WS-PA": true, "WS-SA": true, "WS-TU": true, | ||||||
| 	"WS-VF": true, "WS-VS": true, "YE-AB": true, "YE-AD": true, "YE-AM": true, | 	"WS-VF": true, "WS-VS": true, "YE-AB": true, "YE-AD": true, "YE-AM": true, | ||||||
| 	"YE-BA": true, "YE-DA": true, "YE-DH": true, "YE-HD": true, "YE-HJ": true, "YE-HU": true, | 	"YE-BA": true, "YE-DA": true, "YE-DH": true, "YE-HD": true, "YE-HJ": true, "YE-HU": true, | ||||||
|  |  | ||||||
							
								
								
									
										21
									
								
								vendor/github.com/go-playground/validator/v10/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/go-playground/validator/v10/doc.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -863,7 +863,6 @@ This validates that a string value is a valid JWT | ||||||
| 
 | 
 | ||||||
| 	Usage: jwt | 	Usage: jwt | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # File | # File | ||||||
| 
 | 
 | ||||||
| This validates that a string value contains a valid file path and that | This validates that a string value contains a valid file path and that | ||||||
|  | @ -872,6 +871,15 @@ This is done using os.Stat, which is a platform independent function. | ||||||
| 
 | 
 | ||||||
| 	Usage: file | 	Usage: file | ||||||
| 
 | 
 | ||||||
|  | # Image path | ||||||
|  | 
 | ||||||
|  | This validates that a string value contains a valid file path and that | ||||||
|  | the file exists on the machine and is an image. | ||||||
|  | This is done using os.Stat and github.com/gabriel-vasile/mimetype | ||||||
|  | 
 | ||||||
|  | 	Usage: image | ||||||
|  | 
 | ||||||
|  | # URL String | ||||||
| 
 | 
 | ||||||
| # File Path | # File Path | ||||||
| 
 | 
 | ||||||
|  | @ -881,7 +889,6 @@ This is done using os.Stat, which is a platform independent function. | ||||||
| 
 | 
 | ||||||
| 	Usage: filepath | 	Usage: filepath | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # URL String | # URL String | ||||||
| 
 | 
 | ||||||
| This validates that a string value contains a valid url | This validates that a string value contains a valid url | ||||||
|  | @ -923,7 +930,6 @@ you can use this with the omitempty tag. | ||||||
| 
 | 
 | ||||||
| 	Usage: base64url | 	Usage: base64url | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Base64RawURL String | # Base64RawURL String | ||||||
| 
 | 
 | ||||||
| This validates that a string value contains a valid base64 URL safe value, | This validates that a string value contains a valid base64 URL safe value, | ||||||
|  | @ -934,7 +940,6 @@ you can use this with the omitempty tag. | ||||||
| 
 | 
 | ||||||
| 	Usage: base64url | 	Usage: base64url | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Bitcoin Address | # Bitcoin Address | ||||||
| 
 | 
 | ||||||
| This validates that a string value contains a valid bitcoin address. | This validates that a string value contains a valid bitcoin address. | ||||||
|  | @ -1267,7 +1272,6 @@ This is done using os.Stat, which is a platform independent function. | ||||||
| 
 | 
 | ||||||
| 	Usage: dir | 	Usage: dir | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Directory Path | # Directory Path | ||||||
| 
 | 
 | ||||||
| This validates that a string value contains a valid directory but does | This validates that a string value contains a valid directory but does | ||||||
|  | @ -1278,7 +1282,6 @@ may not exist at the time of validation. | ||||||
| 
 | 
 | ||||||
| 	Usage: dirpath | 	Usage: dirpath | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # HostPort | # HostPort | ||||||
| 
 | 
 | ||||||
| This validates that a string value contains a valid DNS hostname and port that | This validates that a string value contains a valid DNS hostname and port that | ||||||
|  | @ -1350,7 +1353,6 @@ More information on https://semver.org/ | ||||||
| 
 | 
 | ||||||
| 	Usage: semver | 	Usage: semver | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # CVE Identifier | # CVE Identifier | ||||||
| 
 | 
 | ||||||
| This validates that a string value is a valid cve id, defined in cve mitre. | This validates that a string value is a valid cve id, defined in cve mitre. | ||||||
|  | @ -1358,14 +1360,12 @@ More information on https://cve.mitre.org/ | ||||||
| 
 | 
 | ||||||
| 	Usage: cve | 	Usage: cve | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Credit Card | # Credit Card | ||||||
| 
 | 
 | ||||||
| This validates that a string value contains a valid credit card number using Luhn algorithm. | This validates that a string value contains a valid credit card number using Luhn algorithm. | ||||||
| 
 | 
 | ||||||
| 	Usage: credit_card | 	Usage: credit_card | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Luhn Checksum | # Luhn Checksum | ||||||
| 
 | 
 | ||||||
| 	Usage: luhn_checksum | 	Usage: luhn_checksum | ||||||
|  | @ -1378,14 +1378,13 @@ This validates that a string is a valid 24 character hexadecimal string. | ||||||
| 
 | 
 | ||||||
| 	Usage: mongodb | 	Usage: mongodb | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # Cron | # Cron | ||||||
| 
 | 
 | ||||||
| This validates that a string value contains a valid cron expression. | This validates that a string value contains a valid cron expression. | ||||||
| 
 | 
 | ||||||
| 	Usage: cron | 	Usage: cron | ||||||
| 
 | 
 | ||||||
| Alias Validators and Tags | # Alias Validators and Tags | ||||||
| 
 | 
 | ||||||
| Alias Validators and Tags | Alias Validators and Tags | ||||||
| NOTE: When returning an error, the tag returned in "FieldError" will be | NOTE: When returning an error, the tag returned in "FieldError" will be | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								vendor/github.com/leodido/go-urn/machine.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/leodido/go-urn/machine.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -61,11 +61,9 @@ func (m *machine) Parse(input []byte) (*URN, error) { | ||||||
| 	m.err = nil | 	m.err = nil | ||||||
| 	m.tolower = []int{} | 	m.tolower = []int{} | ||||||
| 	output := &URN{} | 	output := &URN{} | ||||||
| 
 |  | ||||||
| 	{ | 	{ | ||||||
| 		m.cs = start | 		m.cs = start | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	{ | 	{ | ||||||
| 		if (m.p) == (m.pe) { | 		if (m.p) == (m.pe) { | ||||||
| 			goto _testEof | 			goto _testEof | ||||||
|  | @ -1674,7 +1672,6 @@ func (m *machine) Parse(input []byte) (*URN, error) { | ||||||
| 				{ | 				{ | ||||||
| 					goto st46 | 					goto st46 | ||||||
| 				} | 				} | ||||||
| 
 |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								vendor/github.com/leodido/go-urn/makefile
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/leodido/go-urn/makefile
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -17,7 +17,7 @@ images: docs/urn.png | ||||||
| 
 | 
 | ||||||
| .PHONY: removecomments | .PHONY: removecomments | ||||||
| removecomments: | removecomments: | ||||||
| 	@cd ./tools/removecomments; go build -o ../../removecomments ./main.go | 	@cd ./tools/removecomments; go build -o ../../removecomments . | ||||||
| 
 | 
 | ||||||
| machine.go: machine.go.rl | machine.go: machine.go.rl | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								vendor/modules.txt
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/modules.txt
									
										
									
									
										vendored
									
									
								
							|  | @ -174,6 +174,12 @@ github.com/dustin/go-humanize | ||||||
| # github.com/fsnotify/fsnotify v1.6.0 | # github.com/fsnotify/fsnotify v1.6.0 | ||||||
| ## explicit; go 1.16 | ## explicit; go 1.16 | ||||||
| github.com/fsnotify/fsnotify | github.com/fsnotify/fsnotify | ||||||
|  | # github.com/gabriel-vasile/mimetype v1.4.2 | ||||||
|  | ## explicit; go 1.20 | ||||||
|  | github.com/gabriel-vasile/mimetype | ||||||
|  | github.com/gabriel-vasile/mimetype/internal/charset | ||||||
|  | github.com/gabriel-vasile/mimetype/internal/json | ||||||
|  | github.com/gabriel-vasile/mimetype/internal/magic | ||||||
| # github.com/gin-contrib/cors v1.4.0 | # github.com/gin-contrib/cors v1.4.0 | ||||||
| ## explicit; go 1.13 | ## explicit; go 1.13 | ||||||
| github.com/gin-contrib/cors | github.com/gin-contrib/cors | ||||||
|  | @ -222,7 +228,7 @@ github.com/go-playground/locales/currency | ||||||
| # github.com/go-playground/universal-translator v0.18.1 | # github.com/go-playground/universal-translator v0.18.1 | ||||||
| ## explicit; go 1.18 | ## explicit; go 1.18 | ||||||
| github.com/go-playground/universal-translator | github.com/go-playground/universal-translator | ||||||
| # github.com/go-playground/validator/v10 v10.13.0 | # github.com/go-playground/validator/v10 v10.14.0 | ||||||
| ## explicit; go 1.18 | ## explicit; go 1.18 | ||||||
| github.com/go-playground/validator/v10 | github.com/go-playground/validator/v10 | ||||||
| # github.com/go-xmlfmt/xmlfmt v0.0.0-20211206191508-7fd73a941850 | # github.com/go-xmlfmt/xmlfmt v0.0.0-20211206191508-7fd73a941850 | ||||||
|  | @ -359,7 +365,7 @@ github.com/klauspost/compress/zlib | ||||||
| # github.com/klauspost/cpuid/v2 v2.2.4 | # github.com/klauspost/cpuid/v2 v2.2.4 | ||||||
| ## explicit; go 1.15 | ## explicit; go 1.15 | ||||||
| github.com/klauspost/cpuid/v2 | github.com/klauspost/cpuid/v2 | ||||||
| # github.com/leodido/go-urn v1.2.3 | # github.com/leodido/go-urn v1.2.4 | ||||||
| ## explicit; go 1.16 | ## explicit; go 1.16 | ||||||
| github.com/leodido/go-urn | github.com/leodido/go-urn | ||||||
| # github.com/magiconair/properties v1.8.7 | # github.com/magiconair/properties v1.8.7 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue