mimemagic-dorian 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.travis.yml +21 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +216 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +71 -0
- data/Rakefile +22 -0
- data/ext/mimemagic/Rakefile +38 -0
- data/lib/mimemagic/tables.rb +168 -0
- data/lib/mimemagic/version.rb +5 -0
- data/lib/mimemagic.rb +446 -0
- data/mimemagic.gemspec +36 -0
- metadata +106 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 060e2ae0726ea36fcb9f30276d9a4337f2a59b76a8dc0c0f9bc2d747966a850a
|
|
4
|
+
data.tar.gz: afc690980aaed5df5e70a6794a34189d380ac71392877c61aa7846c49ee71ee0
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d141cc2c0bb627b671771e64f3ab309784ac0d42b2bbfff7d73e1c480632cd994520ae320c5ae08386f0bc812cfbf5875902c87fe9bfcc019f207653b424fcc6
|
|
7
|
+
data.tar.gz: bfbdfa6941490d426dad7dec017de72f92b6312be59b89730c87162027309ada8174b72b9ec70b88b7c51db3171befc77167e44d9990700be12c637bea7c0a35
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
language: ruby
|
|
2
|
+
jobs:
|
|
3
|
+
include:
|
|
4
|
+
- rvm: 1.9.3
|
|
5
|
+
- rvm: 2.0.0
|
|
6
|
+
- rvm: 2.1
|
|
7
|
+
- rvm: 2.2
|
|
8
|
+
- rvm: 2.3
|
|
9
|
+
- rvm: 2.4
|
|
10
|
+
env: RUBYOPT="--enable-frozen-string-literal"
|
|
11
|
+
- rvm: 2.5
|
|
12
|
+
env: RUBYOPT="--enable-frozen-string-literal"
|
|
13
|
+
- rvm: ruby-head
|
|
14
|
+
env: RUBYOPT="--enable-frozen-string-literal"
|
|
15
|
+
before_install:
|
|
16
|
+
# 1. The pre-installed Bundler version on Travis is very old; causes 1.9.3 build issues
|
|
17
|
+
# 2. Bundler 2.0 is not supported by the whole matrix
|
|
18
|
+
- gem install bundler -v'< 2'
|
|
19
|
+
|
|
20
|
+
script:
|
|
21
|
+
- bundle exec rake
|
data/.yardopts
ADDED
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.5.4
|
|
4
|
+
|
|
5
|
+
This gem implements [PR
|
|
6
|
+
#175](https://github.com/mimemagicrb/mimemagic/issues/175) upstream,
|
|
7
|
+
from 2023-08-09. It will be dissolved if/when the patch is ever
|
|
8
|
+
merged.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
* `.binary?` predicate will tell if the input (`IO`, `String`, file
|
|
13
|
+
extension, path, type, whatever) is binary
|
|
14
|
+
* `#binary?` instance method likewise
|
|
15
|
+
* `.default_type` will return either text/plain or
|
|
16
|
+
application/octet-stream depending on whether the input is perceived
|
|
17
|
+
to be binary
|
|
18
|
+
* `#aliases` (and `.aliases`) will return the list of aliases for a
|
|
19
|
+
given type
|
|
20
|
+
* `#alias?` predicate will determine if a given type is an alias of a
|
|
21
|
+
canonical type
|
|
22
|
+
* `#canonical` (and `.canonical`) will return a canonical type for a
|
|
23
|
+
(potentially aliased) type
|
|
24
|
+
* `#parents` will return the immediate parent types of the given type
|
|
25
|
+
* `#lineage` will return the entire (flattened) inheritance hierarchy
|
|
26
|
+
of the given type, including itself
|
|
27
|
+
* fancy new `MimeMagic[…]` constructor will instantiate from a type or
|
|
28
|
+
file extension
|
|
29
|
+
* constructor now handles type parameters; `params` accessor
|
|
30
|
+
* explicit `#inspect` method shows abridged diagnostic representation
|
|
31
|
+
* `default:` keyword parameter on `.by_extension`, `.by_path`,
|
|
32
|
+
`.by_magic`, `.all_by_magic` will guarantee a return value when
|
|
33
|
+
truthy (either the result of `.default_type` for the given input or
|
|
34
|
+
a user-supplied value)
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
* internal database now contains aliases and the canonical type identifier
|
|
39
|
+
* normalized all the documentation to YARD
|
|
40
|
+
|
|
41
|
+
## 0.4.3
|
|
42
|
+
|
|
43
|
+
???
|
|
44
|
+
|
|
45
|
+
## 0.4.2
|
|
46
|
+
|
|
47
|
+
???
|
|
48
|
+
|
|
49
|
+
## 0.4.1
|
|
50
|
+
|
|
51
|
+
### Breaking Changes
|
|
52
|
+
|
|
53
|
+
Remove `mimemagic/overlay` as it contains outdated, little used, data.
|
|
54
|
+
|
|
55
|
+
## 0.3.7 (2021-03-25)
|
|
56
|
+
|
|
57
|
+
You will now need to ensure you have a copy of the fd.o shared MIME
|
|
58
|
+
types information available before installing this gem. More details
|
|
59
|
+
can be found in the readme.
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
None
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
|
|
67
|
+
None
|
|
68
|
+
## 0.4.3
|
|
69
|
+
|
|
70
|
+
* Improve the development/test experience (@coldnebo, @kachick)
|
|
71
|
+
|
|
72
|
+
* Ensure the gem works in environments with gem caching (@haines)
|
|
73
|
+
|
|
74
|
+
* Add support for MacPorts installed dependencies (@brlanier)
|
|
75
|
+
|
|
76
|
+
* Allow using a dummy XML file in cases where the gem is just a transient
|
|
77
|
+
dependency. (@Scharrels)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
## 0.4.2
|
|
81
|
+
|
|
82
|
+
* Resolve issues parsing the version of freedesktop.org.xml shipped with
|
|
83
|
+
Ubuntu Trusty.
|
|
84
|
+
|
|
85
|
+
* Make Rake a runtime dependency.
|
|
86
|
+
|
|
87
|
+
* Fix the test suite.
|
|
88
|
+
|
|
89
|
+
* Relax the dependency on Nokogiri to something less specific in order
|
|
90
|
+
to avoid conflicting with other dependencies in people's applications.
|
|
91
|
+
|
|
92
|
+
## 0.4.1
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
## 0.4.0
|
|
96
|
+
|
|
97
|
+
Yanked release.
|
|
98
|
+
|
|
99
|
+
## 0.3.10
|
|
100
|
+
|
|
101
|
+
* Improve the development/test experience (@coldnebo, @kachick)
|
|
102
|
+
|
|
103
|
+
* Ensure the gem works in environments with gem caching (@haines)
|
|
104
|
+
|
|
105
|
+
* Add support for MacPorts installed dependencies (@brlanier)
|
|
106
|
+
|
|
107
|
+
* Allow using a dummy XML file in cases where the gem is just a transient
|
|
108
|
+
dependency. (@Scharrels)
|
|
109
|
+
|
|
110
|
+
## 0.3.9 (2021-03-25)
|
|
111
|
+
|
|
112
|
+
* Resolve issues parsing the version of freedesktop.org.xml shipped with
|
|
113
|
+
Ubuntu Trusty.
|
|
114
|
+
|
|
115
|
+
* Reintroduce overlays, since it seems at least some people were using
|
|
116
|
+
them.
|
|
117
|
+
|
|
118
|
+
* Make Rake a runtime dependency.
|
|
119
|
+
|
|
120
|
+
* Fix the test suite.
|
|
121
|
+
## 0.3.8 (2021-03-25)
|
|
122
|
+
|
|
123
|
+
Relax the dependency on Nokogiri to something less specific in order
|
|
124
|
+
to avoid conflicting with other dependencies in people's applications.
|
|
125
|
+
|
|
126
|
+
## 0.3.7 (2021-03-25)
|
|
127
|
+
|
|
128
|
+
Add a dependency on having a preinstalled version of the fd.o shared
|
|
129
|
+
MIME types info to resolve licensing concerns, and allow this gem to
|
|
130
|
+
remain MIT licensed.
|
|
131
|
+
|
|
132
|
+
See the readme for details on ensuring you have a copy of the database
|
|
133
|
+
available at install time.
|
|
134
|
+
## 0.3.6 (2021-03-23)
|
|
135
|
+
|
|
136
|
+
Yanked release, relicensing to GPL due to licensing concerns.
|
|
137
|
+
## 0.3.5 (2020-05-04)
|
|
138
|
+
|
|
139
|
+
Mimetype extensions are now ordered by freedesktop.org's priority
|
|
140
|
+
|
|
141
|
+
## 0.3.4 (2020-01-28)
|
|
142
|
+
|
|
143
|
+
Added frozen string literal comments
|
|
144
|
+
|
|
145
|
+
## 0.3.3 (2018-12-20)
|
|
146
|
+
|
|
147
|
+
Upgrade to shared-mime-info-1.10
|
|
148
|
+
|
|
149
|
+
## 0.3.2 (2016-08-02)
|
|
150
|
+
|
|
151
|
+
### Breaking Changes
|
|
152
|
+
|
|
153
|
+
None
|
|
154
|
+
|
|
155
|
+
### Added
|
|
156
|
+
|
|
157
|
+
- [#37](https://github.com/minad/mimemagic/pull/37)
|
|
158
|
+
A convenient way to get all possible mime types by magic
|
|
159
|
+
|
|
160
|
+
### Fixed
|
|
161
|
+
|
|
162
|
+
- [#40](https://github.com/minad/mimemagic/pull/40),
|
|
163
|
+
[#41](https://github.com/minad/mimemagic/pull/41)
|
|
164
|
+
Performance improvements
|
|
165
|
+
- [#38](https://github.com/minad/mimemagic/pull/38)
|
|
166
|
+
Updated to shared-mime-info 1.6
|
|
167
|
+
|
|
168
|
+
## 0.3.1 (2016-01-04)
|
|
169
|
+
|
|
170
|
+
No release notes yet. Contributions welcome.
|
|
171
|
+
|
|
172
|
+
## 0.3.0 (2015-03-25)
|
|
173
|
+
|
|
174
|
+
No release notes yet. Contributions welcome.
|
|
175
|
+
|
|
176
|
+
## 0.2.1 (2013-07-29)
|
|
177
|
+
|
|
178
|
+
No release notes yet. Contributions welcome.
|
|
179
|
+
|
|
180
|
+
## 0.2.0 (2012-10-19)
|
|
181
|
+
|
|
182
|
+
No release notes yet. Contributions welcome.
|
|
183
|
+
|
|
184
|
+
## 0.1.9 (2012-09-20)
|
|
185
|
+
|
|
186
|
+
No release notes yet. Contributions welcome.
|
|
187
|
+
|
|
188
|
+
## 0.1.8 (2009-05-08)
|
|
189
|
+
|
|
190
|
+
No release notes yet. Contributions welcome.
|
|
191
|
+
|
|
192
|
+
## 0.1.7 (2009-05-08)
|
|
193
|
+
|
|
194
|
+
No release notes yet. Contributions welcome.
|
|
195
|
+
|
|
196
|
+
## 0.1.5 (2009-05-08)
|
|
197
|
+
|
|
198
|
+
No release notes yet. Contributions welcome.
|
|
199
|
+
|
|
200
|
+
## 0.1.4 (2009-05-08)
|
|
201
|
+
|
|
202
|
+
No release notes yet. Contributions welcome.
|
|
203
|
+
|
|
204
|
+
## 0.1.3 (2009-05-08)
|
|
205
|
+
|
|
206
|
+
No release notes yet. Contributions welcome.
|
|
207
|
+
|
|
208
|
+
## 0.1.2 (2009-05-08)
|
|
209
|
+
|
|
210
|
+
No release notes yet. Contributions welcome.
|
|
211
|
+
|
|
212
|
+
## 0.1.1 (2009-05-08)
|
|
213
|
+
|
|
214
|
+
No release notes yet. Contributions welcome.
|
|
215
|
+
|
|
216
|
+
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2011 Daniel Mendler
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
> This version of `mimemagic` implements [PR #175](https://github.com/mimemagicrb/mimemagic/pull/175) upstream. It will be dissolved if/when that patch is merged.
|
|
2
|
+
|
|
3
|
+
MimeMagic is a library to detect the mime type of a file by extension or by content. It uses the mime database
|
|
4
|
+
provided by freedesktop.org (see http://freedesktop.org/wiki/Software/shared-mime-info/).
|
|
5
|
+
|
|
6
|
+
[](http://rubygems.org/gems/mimemagic-dorian)
|
|
7
|
+
|
|
8
|
+
Dependencies
|
|
9
|
+
============
|
|
10
|
+
|
|
11
|
+
You will require a copy of the Freedesktop.org shared-mime-info database to be available. If you're on Linux,
|
|
12
|
+
it's probably available via your package manager, and will probably be in the location it's being looked for
|
|
13
|
+
when the gem is installed.
|
|
14
|
+
|
|
15
|
+
macOS users can install the database via Homebrew with `brew install shared-mime-info`.
|
|
16
|
+
|
|
17
|
+
Should you be unable to use a package manager you can obtain a copy of the needed file by extracting it from
|
|
18
|
+
the Debian package. This process will also work on a Windows machine.
|
|
19
|
+
|
|
20
|
+
1. Download the package from https://packages.debian.org/sid/amd64/shared-mime-info/download
|
|
21
|
+
2. Ensure the command line version of 7-Zip is installed
|
|
22
|
+
3. `7z x -so shared-mime-info_2.0-1_amd64.deb data.tar | 7z e -sidata.tar "./usr/share/mime/packages/freedesktop.org.xml"`
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
Place the file `freedesktop.org.xml` in an appropriate location, and then set the environment variable
|
|
26
|
+
`FREEDESKTOP_MIME_TYPES_PATH` to that path. Once that has been done the gem should install successfully. Please
|
|
27
|
+
note that the gem will depend upon the file remaining in that location at run time.
|
|
28
|
+
|
|
29
|
+
Usage
|
|
30
|
+
=====
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
require 'mimemagic'
|
|
34
|
+
MimeMagic.by_extension('html').text?
|
|
35
|
+
MimeMagic.by_extension('.html').child_of? 'text/plain'
|
|
36
|
+
MimeMagic.by_path('filename.txt')
|
|
37
|
+
MimeMagic.by_magic(File.open('test.html'))
|
|
38
|
+
# etc...
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
You can add your own magic with `MimeMagic.add`.
|
|
42
|
+
|
|
43
|
+
API
|
|
44
|
+
===
|
|
45
|
+
|
|
46
|
+
http://www.rubydoc.info/gems/mimemagic-dorian/
|
|
47
|
+
|
|
48
|
+
Tests
|
|
49
|
+
=====
|
|
50
|
+
|
|
51
|
+
```console
|
|
52
|
+
$ bundle install
|
|
53
|
+
|
|
54
|
+
$ bundle exec rake test
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Authors
|
|
58
|
+
=======
|
|
59
|
+
|
|
60
|
+
[The author of this patch](https://github.com/doriantaylor) is [Dorian Taylor](https://doriantaylor.com/).
|
|
61
|
+
|
|
62
|
+
Original authors:
|
|
63
|
+
|
|
64
|
+
* Daniel Mendler
|
|
65
|
+
* Jon Wood
|
|
66
|
+
* [MimeMagic Contributors](https://github.com/mimemagicrb/mimemagic/graphs/contributors)
|
|
67
|
+
|
|
68
|
+
LICENSE
|
|
69
|
+
=======
|
|
70
|
+
|
|
71
|
+
{file:LICENSE MIT}
|
data/Rakefile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'rake/testtask'
|
|
2
|
+
require 'rake/clean'
|
|
3
|
+
|
|
4
|
+
namespace :ext do
|
|
5
|
+
load 'ext/mimemagic/Rakefile'
|
|
6
|
+
end
|
|
7
|
+
CLOBBER.include("lib/mimemagic/path.rb")
|
|
8
|
+
|
|
9
|
+
task :default => %w(test)
|
|
10
|
+
|
|
11
|
+
desc 'Run tests with minitest'
|
|
12
|
+
Rake::TestTask.new("test" => "ext:default") do |t|
|
|
13
|
+
t.libs << 'test'
|
|
14
|
+
t.pattern = 'test/*_test.rb'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc 'Generate mime tables'
|
|
18
|
+
task :tables => 'lib/mimemagic/tables.rb'
|
|
19
|
+
file 'lib/mimemagic/tables.rb' => FileList['script/freedesktop.org.xml'] do |f|
|
|
20
|
+
sh "script/generate-mime.rb #{f.prerequisites.join(' ')} > #{f.name}"
|
|
21
|
+
end
|
|
22
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require "rubygems"
|
|
2
|
+
require "rake/clean"
|
|
3
|
+
|
|
4
|
+
def locate_mime_database
|
|
5
|
+
possible_paths = [
|
|
6
|
+
(File.expand_path(ENV["FREEDESKTOP_MIME_TYPES_PATH"]) if ENV["FREEDESKTOP_MIME_TYPES_PATH"]),
|
|
7
|
+
"/usr/local/share/mime/packages/freedesktop.org.xml",
|
|
8
|
+
"/opt/homebrew/share/mime/packages/freedesktop.org.xml",
|
|
9
|
+
"/opt/local/share/mime/packages/freedesktop.org.xml",
|
|
10
|
+
"/usr/share/mime/packages/freedesktop.org.xml"
|
|
11
|
+
].compact
|
|
12
|
+
path = possible_paths.find { |candidate| File.exist?(candidate) }
|
|
13
|
+
|
|
14
|
+
return path unless path.nil?
|
|
15
|
+
raise(<<-ERROR.gsub(/^ {3}/, ""))
|
|
16
|
+
Could not find MIME type database in the following locations: #{possible_paths}
|
|
17
|
+
|
|
18
|
+
Ensure you have either installed the shared-mime-info package for your distribution, or
|
|
19
|
+
obtain a version of freedesktop.org.xml and set FREEDESKTOP_MIME_TYPES_PATH to the location
|
|
20
|
+
of that file.
|
|
21
|
+
ERROR
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc "Build a file pointing at the database"
|
|
25
|
+
task :default do
|
|
26
|
+
mime_database_path = locate_mime_database
|
|
27
|
+
target_dir = "#{ENV.fetch("RUBYARCHDIR", "../lib")}/mimemagic"
|
|
28
|
+
mkdir_p target_dir
|
|
29
|
+
|
|
30
|
+
open("#{target_dir}/path.rb", "w") do |f|
|
|
31
|
+
f.print(<<~SOURCE
|
|
32
|
+
class MimeMagic
|
|
33
|
+
DATABASE_PATH="#{mime_database_path}"
|
|
34
|
+
end
|
|
35
|
+
SOURCE
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
# Generated from script/freedesktop.org.xml
|
|
4
|
+
require 'nokogiri'
|
|
5
|
+
require 'mimemagic/path'
|
|
6
|
+
|
|
7
|
+
class MimeMagic
|
|
8
|
+
EXTENSIONS = {}
|
|
9
|
+
TYPES = {}
|
|
10
|
+
MAGIC = []
|
|
11
|
+
|
|
12
|
+
def self.str2int(s)
|
|
13
|
+
return s.to_i(16) if s[0..1].downcase == '0x'
|
|
14
|
+
return s.to_i(8) if s[0..0].downcase == '0'
|
|
15
|
+
s.to_i(10)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.get_matches(parent)
|
|
19
|
+
parent.elements.map {|match|
|
|
20
|
+
if match['mask']
|
|
21
|
+
nil
|
|
22
|
+
else
|
|
23
|
+
type = match['type']
|
|
24
|
+
value = match['value']
|
|
25
|
+
offset = match['offset'].split(':').map {|x| x.to_i }
|
|
26
|
+
offset = offset.size == 2 ? offset[0]..offset[1] : offset[0]
|
|
27
|
+
case type
|
|
28
|
+
when 'string'
|
|
29
|
+
# This *one* pattern match, in the entirety of fd.o's mime types blows up the parser
|
|
30
|
+
# because of the escape character \c, so right here we have a hideous hack to
|
|
31
|
+
# accommodate that.
|
|
32
|
+
if value == '\chapter'
|
|
33
|
+
'\chapter'
|
|
34
|
+
else
|
|
35
|
+
value.gsub!(/\\(x[\dA-Fa-f]{1,2}|0\d{1,3}|\d{1,3}|.)/) {
|
|
36
|
+
eval("\"\\#{$1}\"")
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
when 'big16'
|
|
40
|
+
value = str2int(value)
|
|
41
|
+
value = ((value >> 8).chr + (value & 0xFF).chr)
|
|
42
|
+
when 'big32'
|
|
43
|
+
value = str2int(value)
|
|
44
|
+
value = (((value >> 24) & 0xFF).chr + ((value >> 16) & 0xFF).chr + ((value >> 8) & 0xFF).chr + (value & 0xFF).chr)
|
|
45
|
+
when 'little16'
|
|
46
|
+
value = str2int(value)
|
|
47
|
+
value = ((value & 0xFF).chr + (value >> 8).chr)
|
|
48
|
+
when 'little32'
|
|
49
|
+
value = str2int(value)
|
|
50
|
+
value = ((value & 0xFF).chr + ((value >> 8) & 0xFF).chr + ((value >> 16) & 0xFF).chr + ((value >> 24) & 0xFF).chr)
|
|
51
|
+
when 'host16' # use little endian
|
|
52
|
+
value = str2int(value)
|
|
53
|
+
value = ((value & 0xFF).chr + (value >> 8).chr)
|
|
54
|
+
when 'host32' # use little endian
|
|
55
|
+
value = str2int(value)
|
|
56
|
+
value = ((value & 0xFF).chr + ((value >> 8) & 0xFF).chr + ((value >> 16) & 0xFF).chr + ((value >> 24) & 0xFF).chr)
|
|
57
|
+
when 'byte'
|
|
58
|
+
value = str2int(value)
|
|
59
|
+
value = value.chr
|
|
60
|
+
end
|
|
61
|
+
children = get_matches(match)
|
|
62
|
+
children.empty? ? [offset, value] : [offset, value, children]
|
|
63
|
+
end
|
|
64
|
+
}.compact
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.open_mime_database
|
|
68
|
+
path = MimeMagic::DATABASE_PATH
|
|
69
|
+
File.open(path)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.parse_database
|
|
73
|
+
file = open_mime_database
|
|
74
|
+
|
|
75
|
+
doc = Nokogiri::XML(file)
|
|
76
|
+
extensions = {}
|
|
77
|
+
types = {}
|
|
78
|
+
magics = []
|
|
79
|
+
(doc/'mime-info/mime-type').each do |mime|
|
|
80
|
+
comments = Hash[*(mime/'comment').map {|comment| [comment['xml:lang'], comment.inner_text] }.flatten]
|
|
81
|
+
type = mime['type']
|
|
82
|
+
subclass = (mime/'sub-class-of').map{|x| x['type']}
|
|
83
|
+
exts = (mime/'glob').map do |x|
|
|
84
|
+
x['pattern'] =~ /^\*\.([^\[\]]+)$/ ? $1.downcase : nil
|
|
85
|
+
end.compact
|
|
86
|
+
|
|
87
|
+
(mime/'magic').each do |magic|
|
|
88
|
+
priority = magic['priority'].to_i
|
|
89
|
+
matches = get_matches(magic)
|
|
90
|
+
magics << [priority, type, matches]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
aliases = (mime/'alias/@type').map { |a| a.value.downcase.strip.freeze }
|
|
94
|
+
|
|
95
|
+
# XXX uhh do we only use the type if it has a file extension??
|
|
96
|
+
unless exts.empty?
|
|
97
|
+
exts.each { |x| extensions[x] ||= type }
|
|
98
|
+
types[type] = [exts, subclass, comments[nil], type, aliases]
|
|
99
|
+
# don't add the aliases yet; we do that below
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
magics = magics.sort {|a,b| [-a[0],a[1]] <=> [-b[0],b[1]] }
|
|
104
|
+
|
|
105
|
+
common_types = [
|
|
106
|
+
"image/jpeg", # .jpg
|
|
107
|
+
"image/png", # .png
|
|
108
|
+
"image/gif", # .gif
|
|
109
|
+
"image/tiff", # .tiff
|
|
110
|
+
"image/bmp", # .bmp
|
|
111
|
+
"image/vnd.adobe.photoshop", # .psd
|
|
112
|
+
"image/webp", # .webp
|
|
113
|
+
"image/svg+xml", # .svg
|
|
114
|
+
|
|
115
|
+
"video/x-msvideo", # .avi
|
|
116
|
+
"video/x-ms-wmv", # .wmv
|
|
117
|
+
"video/mp4", # .mp4, .m4v
|
|
118
|
+
"video/quicktime", # .mov
|
|
119
|
+
"video/mpeg", # .mpeg
|
|
120
|
+
"video/ogg", # .ogv
|
|
121
|
+
"video/webm", # .webm
|
|
122
|
+
"video/x-matroska", # .mkv
|
|
123
|
+
"video/x-flv", # .flv
|
|
124
|
+
|
|
125
|
+
"audio/mpeg", # .mp3
|
|
126
|
+
"audio/x-wav", # .wav
|
|
127
|
+
"audio/aac", # .aac
|
|
128
|
+
"audio/flac", # .flac
|
|
129
|
+
"audio/mp4", # .m4a
|
|
130
|
+
"audio/ogg", # .ogg
|
|
131
|
+
|
|
132
|
+
"application/pdf", # .pdf
|
|
133
|
+
"application/msword", # .doc
|
|
134
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", # .docx
|
|
135
|
+
"application/vnd.ms-powerpoint", # .pps
|
|
136
|
+
"application/vnd.openxmlformats-officedocument.presentationml.slideshow", # .ppsx
|
|
137
|
+
"application/vnd.ms-excel", # .pps
|
|
138
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", # .ppsx
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
common_magics = common_types.map do |common_type|
|
|
142
|
+
magics.find { |_, type, _| type == common_type }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
magics = (common_magics.compact + magics).uniq
|
|
146
|
+
|
|
147
|
+
extensions.keys.sort.each do |key|
|
|
148
|
+
EXTENSIONS[key] = extensions[key]
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
types.keys.sort.each do |key|
|
|
152
|
+
exts, parents, comment, canon, aliases = *types[key]
|
|
153
|
+
|
|
154
|
+
parents.sort!
|
|
155
|
+
aliases.sort!
|
|
156
|
+
|
|
157
|
+
# we are copying it i guess
|
|
158
|
+
t = TYPES[key] = [exts, parents, comment, canon, aliases].freeze
|
|
159
|
+
|
|
160
|
+
# now do the aliases oops they'll be out of order oh well
|
|
161
|
+
aliases.each { |a| TYPES[a] = t }
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
magics.each do |priority, type, matches|
|
|
165
|
+
MAGIC << [type, matches]
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
data/lib/mimemagic.rb
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'mimemagic/tables'
|
|
4
|
+
require 'mimemagic/version'
|
|
5
|
+
|
|
6
|
+
require 'stringio'
|
|
7
|
+
|
|
8
|
+
MimeMagic.parse_database
|
|
9
|
+
|
|
10
|
+
# Mime type detection
|
|
11
|
+
class MimeMagic
|
|
12
|
+
attr_reader :type, :mediatype, :subtype, :params
|
|
13
|
+
|
|
14
|
+
# Initialize a new MIME type by its string representation.
|
|
15
|
+
#
|
|
16
|
+
# @param type [#to_s] the type to parse.
|
|
17
|
+
#
|
|
18
|
+
def initialize(type)
|
|
19
|
+
@type, *params = type.to_s.strip.split(/(?:\s*;\s*)+/) # chop off params
|
|
20
|
+
@type.downcase! # normalize the case
|
|
21
|
+
# split parameter-value pairs if present
|
|
22
|
+
@params = params.map { |x| x.split(/\s*=\s*/, 2) } unless params.empty?
|
|
23
|
+
@mediatype, @subtype = @type.split ?/, 2 # split major and minor
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Syntactic sugar alias for constructor. No-op if `type` is already
|
|
27
|
+
# a {MimeMagic} object. The argument is treated as a file extension
|
|
28
|
+
# if it doesn't contain a `/`, and may return `nil` if it doesn't
|
|
29
|
+
# resolve.
|
|
30
|
+
#
|
|
31
|
+
# @param type [#to_s] a string-like object representing a MIME type
|
|
32
|
+
# or file extension.
|
|
33
|
+
#
|
|
34
|
+
# @return [MimeMagic, nil] the instantiated object.
|
|
35
|
+
#
|
|
36
|
+
def self.[] type
|
|
37
|
+
# try noop first
|
|
38
|
+
return type if type.is_a? self
|
|
39
|
+
|
|
40
|
+
# now we handle the string
|
|
41
|
+
type = type.to_s.strip
|
|
42
|
+
# empty string should be default
|
|
43
|
+
return default_type if type.empty?
|
|
44
|
+
|
|
45
|
+
# this may return null
|
|
46
|
+
return by_extension type unless type.include? ?/
|
|
47
|
+
|
|
48
|
+
# otherwise pass to constructor
|
|
49
|
+
new type
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Add a custom MIME type to the internal dictionary.
|
|
53
|
+
#
|
|
54
|
+
# @param type [#to_s] the type
|
|
55
|
+
# @param extensions [Array<#to_s>] file extensions
|
|
56
|
+
# @param parents [Array<#to_s>] parent types
|
|
57
|
+
# @param magic [Array] MIME "magic" specification
|
|
58
|
+
# @param aliases [Array<#to_s>] alternative names for the type
|
|
59
|
+
# @param comment [#to_s] a comment
|
|
60
|
+
#
|
|
61
|
+
def self.add type,
|
|
62
|
+
extensions: [], parents: [], magic: [], comment: nil, aliases: []
|
|
63
|
+
type = type.to_s.strip.downcase
|
|
64
|
+
extensions = [extensions].flatten.compact
|
|
65
|
+
aliases = [[aliases] || []].flatten.compact
|
|
66
|
+
t = TYPES[type] = [extensions, [parents].flatten.compact,
|
|
67
|
+
comment, type, aliases]
|
|
68
|
+
aliases.each { |a| TYPES[a] = t }
|
|
69
|
+
extensions.each {|ext| EXTENSIONS[ext] ||= type }
|
|
70
|
+
|
|
71
|
+
MAGIC.unshift [type, magic] if magic
|
|
72
|
+
|
|
73
|
+
true # output is ignored
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Removes a MIME type from the dictionary. You might want to do this if
|
|
77
|
+
# you're seeing impossible conflicts (for instance, application/x-gmc-link).
|
|
78
|
+
#
|
|
79
|
+
# @note All associated extensions and magic are removed too.
|
|
80
|
+
#
|
|
81
|
+
# @param type [#to_s] the type to remove.
|
|
82
|
+
#
|
|
83
|
+
def self.remove(type)
|
|
84
|
+
EXTENSIONS.delete_if {|ext, t| t == type }
|
|
85
|
+
MAGIC.delete_if {|t, m| t == type }
|
|
86
|
+
TYPES.delete(type)
|
|
87
|
+
|
|
88
|
+
true # output is also ignored
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Returns true if type is a text format.
|
|
92
|
+
def text?; mediatype == 'text' || descendant_of?('text/plain'); end
|
|
93
|
+
|
|
94
|
+
# Determine if the type is an image.
|
|
95
|
+
def image?; mediatype == 'image'; end
|
|
96
|
+
|
|
97
|
+
# Determine if the type is audio.
|
|
98
|
+
def audio?; mediatype == 'audio'; end
|
|
99
|
+
|
|
100
|
+
# Determine if the type is video.
|
|
101
|
+
def video?; mediatype == 'video'; end
|
|
102
|
+
|
|
103
|
+
# Get string list of file extensions.
|
|
104
|
+
#
|
|
105
|
+
# @return [Array<String>] associated file extensions.
|
|
106
|
+
#
|
|
107
|
+
def extensions
|
|
108
|
+
TYPES.fetch(type, [[]]).first.map { |e| e.to_s.dup }
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Get MIME comment.
|
|
112
|
+
#
|
|
113
|
+
# @return [nil, String] the comment
|
|
114
|
+
#
|
|
115
|
+
def comment
|
|
116
|
+
TYPES.fetch(type, [nil, nil, nil])[2].to_s.dup
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Return the canonical type. Returns `nil` if the type is unknown to
|
|
120
|
+
# the registry.
|
|
121
|
+
#
|
|
122
|
+
# @return [MimeMagic, nil] the canonical type, if present.
|
|
123
|
+
#
|
|
124
|
+
def canonical
|
|
125
|
+
t = TYPES[type.downcase] or return
|
|
126
|
+
return self if type == t[3]
|
|
127
|
+
self.class.new t[3]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Return the type's aliases.
|
|
131
|
+
#
|
|
132
|
+
# @return [Array<MimeMagic>] the aliases, if any.
|
|
133
|
+
#
|
|
134
|
+
def aliases
|
|
135
|
+
TYPES.fetch(type.downcase, [nil, nil, nil, nil, []])[4].map do |t|
|
|
136
|
+
self.class.new t
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Determine if the type is an alias.
|
|
141
|
+
#
|
|
142
|
+
# @return [false, true] whether the type is an alias.
|
|
143
|
+
#
|
|
144
|
+
def alias?
|
|
145
|
+
type != canonical.type
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Returns true if the ancestor type is anywhere in the subject
|
|
149
|
+
# type's lineage. Always returns `false` if either `self` or
|
|
150
|
+
# `ancestor` are unknown to the type registry.
|
|
151
|
+
#
|
|
152
|
+
# @param ancestor [MimeType,#to_s] the candidate ancestor type
|
|
153
|
+
#
|
|
154
|
+
# @return [true, false] whether `self` is a descendant of `ancestor`
|
|
155
|
+
#
|
|
156
|
+
def descendant_of? ancestor
|
|
157
|
+
# always false if we don't know what this is
|
|
158
|
+
return unless c = canonical
|
|
159
|
+
|
|
160
|
+
# ancestor canonical could be nil which will be false
|
|
161
|
+
c.lineage.include? self.class[ancestor].canonical
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Returns true if type is child of parent type. Behaves the same as
|
|
165
|
+
# #descendant_of? if `recurse` is true, which is the default.
|
|
166
|
+
#
|
|
167
|
+
# @param parent [#to_s] a candidate parent type
|
|
168
|
+
# @param recurse [true, false] whether to recurse
|
|
169
|
+
#
|
|
170
|
+
# @return [true, false] whether `self` is a child of `parent`
|
|
171
|
+
#
|
|
172
|
+
def child_of?(parent, recurse: true)
|
|
173
|
+
return descendant_of? parent if recurse
|
|
174
|
+
return unless c = canonical
|
|
175
|
+
c.parents.include? self.class[parent].canonical
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Fetches the immediate parent types.
|
|
179
|
+
#
|
|
180
|
+
# @return [Array<MimeMagic>] the type's parents
|
|
181
|
+
#
|
|
182
|
+
def parents
|
|
183
|
+
out = TYPES.fetch(type.to_s.downcase, [nil, []])[1].map do |x|
|
|
184
|
+
self.class.new x
|
|
185
|
+
end
|
|
186
|
+
# add this unless we're it
|
|
187
|
+
out << self.class.new('application/octet-stream') if
|
|
188
|
+
out.empty? and type.downcase != 'application/octet-stream'
|
|
189
|
+
|
|
190
|
+
out.uniq
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Fetches the entire inheritance hierarchy for the given MIME type.
|
|
194
|
+
#
|
|
195
|
+
# @return [Array<MimeMagic>] the type's lineage
|
|
196
|
+
#
|
|
197
|
+
def lineage
|
|
198
|
+
([canonical || self] + parents.map { |t| t.lineage }.flatten).uniq
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
alias_method :ancestor_types, :lineage
|
|
202
|
+
|
|
203
|
+
# Determine if the _type_ is a descendant of `text/plain`. Not to be
|
|
204
|
+
# confused with the class method {.binary?}, which concerns
|
|
205
|
+
# arbitrary input.
|
|
206
|
+
#
|
|
207
|
+
# @return [true, false, nil] whether the type is binary.
|
|
208
|
+
#
|
|
209
|
+
def binary?
|
|
210
|
+
not lineage.include? 'text/plain'
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Compare the equality of the type with another (or plain string).
|
|
214
|
+
#
|
|
215
|
+
# @param other [#to_s] the other to test
|
|
216
|
+
#
|
|
217
|
+
# @return [false, true] whether the two are equal.
|
|
218
|
+
#
|
|
219
|
+
def eql?(other)
|
|
220
|
+
# coerce the rhs
|
|
221
|
+
other = self.class[other] || self.class.default_type
|
|
222
|
+
|
|
223
|
+
# check for an exact match
|
|
224
|
+
return true if type == other.type
|
|
225
|
+
|
|
226
|
+
# now canonicalize both sides and check
|
|
227
|
+
lhs = canonical
|
|
228
|
+
rhs = other.canonical
|
|
229
|
+
|
|
230
|
+
lhs && rhs && lhs.type == rhs.type
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
alias_method :==, :eql?
|
|
234
|
+
|
|
235
|
+
# Return the object's (the underlying type string) hash.
|
|
236
|
+
#
|
|
237
|
+
# @return [Integer] the hash value.
|
|
238
|
+
#
|
|
239
|
+
def hash
|
|
240
|
+
type.hash
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Return the type as a string.
|
|
244
|
+
#
|
|
245
|
+
# @return [String] the type, as a string.
|
|
246
|
+
#
|
|
247
|
+
def to_s
|
|
248
|
+
type
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Return a diagnostic representation of the object.
|
|
252
|
+
#
|
|
253
|
+
# @return [String] a string representing the object.
|
|
254
|
+
#
|
|
255
|
+
def inspect
|
|
256
|
+
out = @type
|
|
257
|
+
out = [out, @params.map { |x| x.join ?= }].join ?; if
|
|
258
|
+
@params and !@params.empty?
|
|
259
|
+
%q[<%s "%s">] % [self.class, out]
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Look up MIME type by file extension. When `default` is true or a
|
|
263
|
+
# value, this method will always return a value.
|
|
264
|
+
#
|
|
265
|
+
# @param path [#to_s]
|
|
266
|
+
# @param default [false, true, #to_s, MimeMagic] a default fallback type
|
|
267
|
+
#
|
|
268
|
+
# @return [nil, MimeMagic] the type, if found.
|
|
269
|
+
#
|
|
270
|
+
def self.by_extension ext, default: false
|
|
271
|
+
ext = ext.to_s.downcase.delete_prefix ?.
|
|
272
|
+
default = coerce_default '', default
|
|
273
|
+
mime = EXTENSIONS[ext]
|
|
274
|
+
mime ? new(mime) : default
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Look up MIME type by file path. When `default` is true or a value,
|
|
278
|
+
# this method will always return a value.
|
|
279
|
+
#
|
|
280
|
+
# @param path [#to_s] the file/path to check
|
|
281
|
+
# @param default [false, true, #to_s, MimeMagic] a default fallback type
|
|
282
|
+
#
|
|
283
|
+
# @return [nil, MimeMagic] the type, if found.
|
|
284
|
+
#
|
|
285
|
+
def self.by_path path, default: false
|
|
286
|
+
by_extension(File.extname(path), default: default)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Look up MIME type by magic content analysis. When `default` is true or a
|
|
290
|
+
# value, this method will always return a value.
|
|
291
|
+
#
|
|
292
|
+
# @note This is a relatively slow operation.
|
|
293
|
+
#
|
|
294
|
+
# @param io [#read, #to_s] the IO/String-like object to check for magic
|
|
295
|
+
# @param default [false, true, #to_s, MimeMagic] a default fallback type
|
|
296
|
+
#
|
|
297
|
+
# @return [nil, MimeMagic] a matching type, if found.
|
|
298
|
+
#
|
|
299
|
+
def self.by_magic io, default: false
|
|
300
|
+
default = coerce_default io, default
|
|
301
|
+
mime = magic_match(io, :find) or return default
|
|
302
|
+
new mime.first
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Return all matching MIME types by magic content analysis. When
|
|
306
|
+
# `default` is true or a value, the result will never be empty.
|
|
307
|
+
#
|
|
308
|
+
# @note This is a relatively slow operation.
|
|
309
|
+
#
|
|
310
|
+
# @param io [#read, #to_s] the IO/String-like object to check for magic
|
|
311
|
+
# @param default [false, true, #to_s, MimeMagic] a default fallback type
|
|
312
|
+
#
|
|
313
|
+
# @return [Array<MimeMagic>] all matching types
|
|
314
|
+
#
|
|
315
|
+
def self.all_by_magic io, default: false
|
|
316
|
+
default = coerce_default io, default
|
|
317
|
+
out = magic_match(io, :select).map { |mime| new mime.first }
|
|
318
|
+
out << default if out.empty? and default
|
|
319
|
+
out
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Returns true if type is child of parent type.
|
|
323
|
+
#
|
|
324
|
+
# @param child [#to_s] a candidate child type
|
|
325
|
+
# @param parent [#to_s] a candidate parent type
|
|
326
|
+
#
|
|
327
|
+
# @return [true, false] whether `self` is a child of `parent`
|
|
328
|
+
#
|
|
329
|
+
def self.child?(child, parent, recurse: true)
|
|
330
|
+
self[child].child_of? parent, recurse: recurse
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Return the canonical type.
|
|
334
|
+
#
|
|
335
|
+
# @param type [#to_s] the type to test
|
|
336
|
+
#
|
|
337
|
+
# @return [MimeMagic, nil] the canonical type, if present.
|
|
338
|
+
#
|
|
339
|
+
def self.canonical type
|
|
340
|
+
self[type].canonical
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# Return the type's aliases.
|
|
344
|
+
#
|
|
345
|
+
# @param type [#to_s] the type to check
|
|
346
|
+
#
|
|
347
|
+
# @return [Array<MimeMagic>] the aliases, if any.
|
|
348
|
+
#
|
|
349
|
+
def self.aliases type
|
|
350
|
+
self[type].aliases
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# Determine if an _input_ is binary. Not to be confused with the
|
|
354
|
+
# instance method {#binary?}, which concerns the _type_.
|
|
355
|
+
#
|
|
356
|
+
# @param thing [#read, #to_s] the IO-like or String-like thing to
|
|
357
|
+
# test; can also be a file name/path/extension or MIME type.
|
|
358
|
+
#
|
|
359
|
+
# @return [true, false, nil] whether the input is binary (`nil` if
|
|
360
|
+
# indeterminate).
|
|
361
|
+
#
|
|
362
|
+
def self.binary? thing
|
|
363
|
+
sample = ''
|
|
364
|
+
|
|
365
|
+
# get some stuff out of the IO or get a substring
|
|
366
|
+
if thing.is_a? MimeMagic
|
|
367
|
+
return thing.binary?
|
|
368
|
+
elsif %i[seek tell read].all? { |m| thing.respond_to? m }
|
|
369
|
+
pos = thing.tell
|
|
370
|
+
thing.seek 0, 0
|
|
371
|
+
sample = thing.read(256).to_s # handle empty
|
|
372
|
+
thing.seek pos
|
|
373
|
+
elsif thing.respond_to? :to_s
|
|
374
|
+
str = thing.to_s
|
|
375
|
+
# if it contains a slash it could be either a path or mimetype
|
|
376
|
+
test = if str.include? ?/
|
|
377
|
+
canonical(str) || by_extension(str.split(?.).last)
|
|
378
|
+
else
|
|
379
|
+
by_extension str.split(?.).last
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
return test.binary? if test
|
|
383
|
+
|
|
384
|
+
sample = str[0, 256]
|
|
385
|
+
else
|
|
386
|
+
# nil if we don't know what this thing is
|
|
387
|
+
return
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# consider this to be 'binary' if empty
|
|
391
|
+
return true if sample.empty?
|
|
392
|
+
# control codes minus ordinary whitespace
|
|
393
|
+
/[\x0-\x8\xe-\x1f\x7f]/n.match? sample.b
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# Return either `application/octet-stream` or `text/plain` depending
|
|
397
|
+
# on whether the thing is binary.
|
|
398
|
+
#
|
|
399
|
+
# @param thing [#read, #to_s] the thing (IO-like, String-like, MIME type,
|
|
400
|
+
#
|
|
401
|
+
# @return [MimeMagic] the default type
|
|
402
|
+
#
|
|
403
|
+
def self.default_type thing = nil
|
|
404
|
+
return new 'application/octet-stream' unless thing
|
|
405
|
+
new(binary?(thing) ? 'application/octet-stream' : 'text/plain')
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
private
|
|
409
|
+
|
|
410
|
+
def self.coerce_default thing, default
|
|
411
|
+
case default
|
|
412
|
+
when nil, false then nil
|
|
413
|
+
when true then default_type thing
|
|
414
|
+
when MimeMagic then default
|
|
415
|
+
when String, -> x { x.respond_to? :to_s } then new default
|
|
416
|
+
else default_type thing
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def self.magic_match(io, method)
|
|
421
|
+
return magic_match(StringIO.new(io.to_s), method) unless io.respond_to?(:read)
|
|
422
|
+
|
|
423
|
+
io.binmode if io.respond_to?(:binmode)
|
|
424
|
+
io.set_encoding(Encoding::BINARY) if io.respond_to?(:set_encoding)
|
|
425
|
+
buffer = "".encode(Encoding::BINARY)
|
|
426
|
+
|
|
427
|
+
MAGIC.send(method) { |type, matches| magic_match_io(io, matches, buffer) }
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def self.magic_match_io(io, matches, buffer)
|
|
431
|
+
matches.any? do |offset, value, children|
|
|
432
|
+
match =
|
|
433
|
+
if Range === offset
|
|
434
|
+
io.read(offset.begin, buffer)
|
|
435
|
+
x = io.read(offset.end - offset.begin + value.bytesize, buffer)
|
|
436
|
+
x && x.include?(value)
|
|
437
|
+
else
|
|
438
|
+
io.read(offset, buffer)
|
|
439
|
+
io.read(value.bytesize, buffer) == value
|
|
440
|
+
end
|
|
441
|
+
io.rewind
|
|
442
|
+
match && (!children || magic_match_io(io, children, buffer))
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
end
|
data/mimemagic.gemspec
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.dirname(__FILE__) + '/lib/mimemagic/version'
|
|
3
|
+
require 'date'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'mimemagic-dorian'
|
|
7
|
+
s.version = MimeMagic::VERSION
|
|
8
|
+
|
|
9
|
+
s.authors = ['Dorian Taylor', 'Daniel Mendler', 'Jon Wood']
|
|
10
|
+
s.date = Date.today.to_s
|
|
11
|
+
s.email = ['code@doriantaylor.com', 'mail@daniel-mendler.de', 'jon@blankpad.net']
|
|
12
|
+
|
|
13
|
+
s.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(test|script)/}) }
|
|
14
|
+
s.require_paths = %w(lib)
|
|
15
|
+
s.extensions = %w(ext/mimemagic/Rakefile)
|
|
16
|
+
|
|
17
|
+
s.summary = 'Fast mime detection by extension or content (DORIAN PATCH)'
|
|
18
|
+
s.description = <<~EOS
|
|
19
|
+
Fast MIME detection by extension or content (Uses freedesktop.org.xml
|
|
20
|
+
shared-mime-info database). This fork implements PR #175 on the upstream
|
|
21
|
+
gem and will be dissolved if/when that patch is merged.
|
|
22
|
+
EOS
|
|
23
|
+
s.homepage = 'https://github.com/doriantaylor/rb-mimemagic'
|
|
24
|
+
s.license = 'MIT'
|
|
25
|
+
|
|
26
|
+
s.add_dependency('nokogiri', '~> 1')
|
|
27
|
+
s.add_dependency('rake')
|
|
28
|
+
|
|
29
|
+
s.add_development_dependency('minitest', '~> 5.14')
|
|
30
|
+
|
|
31
|
+
if s.respond_to?(:metadata)
|
|
32
|
+
s.metadata['changelog_uri'] = "https://github.com/doriantaylor/rb-mimemagic/blob/fork-gem/CHANGELOG.md"
|
|
33
|
+
s.metadata['source_code_uri'] = "https://github.com/doriantaylor/rb-mimemagic"
|
|
34
|
+
s.metadata['bug_tracker_uri'] = "https://github.com/doriantaylor/rb-mimemagic/issues"
|
|
35
|
+
end
|
|
36
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: mimemagic-dorian
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.5.4
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Dorian Taylor
|
|
8
|
+
- Daniel Mendler
|
|
9
|
+
- Jon Wood
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2026-06-03 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: nokogiri
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
requirements:
|
|
18
|
+
- - "~>"
|
|
19
|
+
- !ruby/object:Gem::Version
|
|
20
|
+
version: '1'
|
|
21
|
+
type: :runtime
|
|
22
|
+
prerelease: false
|
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
24
|
+
requirements:
|
|
25
|
+
- - "~>"
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: '1'
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: rake
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: '0'
|
|
35
|
+
type: :runtime
|
|
36
|
+
prerelease: false
|
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
38
|
+
requirements:
|
|
39
|
+
- - ">="
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '0'
|
|
42
|
+
- !ruby/object:Gem::Dependency
|
|
43
|
+
name: minitest
|
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - "~>"
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '5.14'
|
|
49
|
+
type: :development
|
|
50
|
+
prerelease: false
|
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - "~>"
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '5.14'
|
|
56
|
+
description: |
|
|
57
|
+
Fast MIME detection by extension or content (Uses freedesktop.org.xml
|
|
58
|
+
shared-mime-info database). This fork implements PR #175 on the upstream
|
|
59
|
+
gem and will be dissolved if/when that patch is merged.
|
|
60
|
+
email:
|
|
61
|
+
- code@doriantaylor.com
|
|
62
|
+
- mail@daniel-mendler.de
|
|
63
|
+
- jon@blankpad.net
|
|
64
|
+
executables: []
|
|
65
|
+
extensions:
|
|
66
|
+
- ext/mimemagic/Rakefile
|
|
67
|
+
extra_rdoc_files: []
|
|
68
|
+
files:
|
|
69
|
+
- ".gitignore"
|
|
70
|
+
- ".travis.yml"
|
|
71
|
+
- ".yardopts"
|
|
72
|
+
- CHANGELOG.md
|
|
73
|
+
- Gemfile
|
|
74
|
+
- LICENSE
|
|
75
|
+
- README.md
|
|
76
|
+
- Rakefile
|
|
77
|
+
- ext/mimemagic/Rakefile
|
|
78
|
+
- lib/mimemagic.rb
|
|
79
|
+
- lib/mimemagic/tables.rb
|
|
80
|
+
- lib/mimemagic/version.rb
|
|
81
|
+
- mimemagic.gemspec
|
|
82
|
+
homepage: https://github.com/doriantaylor/rb-mimemagic
|
|
83
|
+
licenses:
|
|
84
|
+
- MIT
|
|
85
|
+
metadata:
|
|
86
|
+
changelog_uri: https://github.com/doriantaylor/rb-mimemagic/blob/fork-gem/CHANGELOG.md
|
|
87
|
+
source_code_uri: https://github.com/doriantaylor/rb-mimemagic
|
|
88
|
+
bug_tracker_uri: https://github.com/doriantaylor/rb-mimemagic/issues
|
|
89
|
+
rdoc_options: []
|
|
90
|
+
require_paths:
|
|
91
|
+
- lib
|
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
99
|
+
- - ">="
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0'
|
|
102
|
+
requirements: []
|
|
103
|
+
rubygems_version: 3.6.7
|
|
104
|
+
specification_version: 4
|
|
105
|
+
summary: Fast mime detection by extension or content (DORIAN PATCH)
|
|
106
|
+
test_files: []
|