afp_mimemagic 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'nokogiri'
4
+
5
+ class String
6
+ alias inspect_old inspect
7
+
8
+ def inspect
9
+ x = b.inspect_old.gsub(/\\x([0-9a-f]{2})/i) do
10
+ '\\%03o' % Regexp.last_match(1).to_i(16)
11
+ end
12
+ x =~ /[\\']/ ? x : x.gsub('"', '\'')
13
+ end
14
+ end
15
+
16
+ def str2int(s)
17
+ return s.to_i(16) if s[0..1].downcase == '0x'
18
+ return s.to_i(8) if s[0..0].downcase == '0'
19
+
20
+ s.to_i(10)
21
+ end
22
+
23
+ def get_matches(parent)
24
+ parent.elements.map do |match|
25
+ if match['mask']
26
+ nil
27
+ else
28
+ type = match['type']
29
+ value = match['value']
30
+ offset = match['offset'].split(':').map { |x| x.to_i }
31
+ offset = offset.size == 2 ? offset[0]..offset[1] : offset[0]
32
+ case type
33
+ when 'string'
34
+ value.gsub!(/\\(x[\dA-Fa-f]{1,2}|0\d{1,3}|\d{1,3}|.)/) { eval("\"\\#{Regexp.last_match(1)}\"") }
35
+ when 'big16'
36
+ value = str2int(value)
37
+ value = ((value >> 8).chr + (value & 0xFF).chr)
38
+ when 'big32'
39
+ value = str2int(value)
40
+ value = (((value >> 24) & 0xFF).chr + ((value >> 16) & 0xFF).chr + ((value >> 8) & 0xFF).chr + (value & 0xFF).chr)
41
+ when 'little16'
42
+ value = str2int(value)
43
+ value = ((value & 0xFF).chr + (value >> 8).chr)
44
+ when 'little32'
45
+ value = str2int(value)
46
+ value = ((value & 0xFF).chr + ((value >> 8) & 0xFF).chr + ((value >> 16) & 0xFF).chr + ((value >> 24) & 0xFF).chr)
47
+ when 'host16' # use little endian
48
+ value = str2int(value)
49
+ value = ((value & 0xFF).chr + (value >> 8).chr)
50
+ when 'host32' # use little endian
51
+ value = str2int(value)
52
+ value = ((value & 0xFF).chr + ((value >> 8) & 0xFF).chr + ((value >> 16) & 0xFF).chr + ((value >> 24) & 0xFF).chr)
53
+ when 'byte'
54
+ value = str2int(value)
55
+ value = value.chr
56
+ end
57
+ children = get_matches(match)
58
+ children.empty? ? [offset, value] : [offset, value, children]
59
+ end
60
+ end.compact
61
+ end
62
+
63
+ if ARGV.size != 1
64
+ puts "Usage: #{$0} <freedesktop.org.xml>"
65
+ exit 1
66
+ end
67
+
68
+ FILE = ARGV[0]
69
+ file = File.new(FILE)
70
+ doc = Nokogiri::XML(file)
71
+ extensions = {}
72
+ types = {}
73
+ magics = []
74
+ (doc / 'mime-info/mime-type').each do |mime|
75
+ comments = Hash[*(mime / 'comment').map { |comment| [comment['xml:lang'], comment.inner_text] }.flatten]
76
+ type = mime['type']
77
+ subclass = (mime / 'sub-class-of').map { |x| x['type'] }
78
+ exts = (mime / 'glob').map { |x| x['pattern'] =~ /^\*\.([^\[\]]+)$/ ? Regexp.last_match(1).downcase : nil }.compact
79
+ (mime / 'magic').each do |magic|
80
+ priority = magic['priority'].to_i
81
+ matches = get_matches(magic)
82
+ magics << [priority, type, matches]
83
+ end
84
+ next if exts.empty?
85
+
86
+ exts.each do |x|
87
+ extensions[x] = type unless extensions.include?(x)
88
+ end
89
+ types[type] = [exts, subclass, comments[nil]]
90
+ end
91
+
92
+ magics = magics.sort { |a, b| [-a[0], a[1]] <=> [-b[0], b[1]] }
93
+
94
+ common_types = [
95
+ 'image/jpeg', # .jpg
96
+ 'image/png', # .png
97
+ 'image/gif', # .gif
98
+ 'image/tiff', # .tiff
99
+ 'image/bmp', # .bmp
100
+ 'image/vnd.adobe.photoshop', # .psd
101
+ 'image/webp', # .webp
102
+ 'image/svg+xml', # .svg
103
+
104
+ 'video/x-msvideo', # .avi
105
+ 'video/x-ms-wmv', # .wmv
106
+ 'video/mp4', # .mp4, .m4v
107
+ 'video/quicktime', # .mov
108
+ 'video/mpeg', # .mpeg
109
+ 'video/ogg', # .ogv
110
+ 'video/webm', # .webm
111
+ 'video/x-matroska', # .mkv
112
+ 'video/x-flv', # .flv
113
+
114
+ 'audio/mpeg', # .mp3
115
+ 'audio/x-wav', # .wav
116
+ 'audio/aac', # .aac
117
+ 'audio/flac', # .flac
118
+ 'audio/mp4', # .m4a
119
+ 'audio/ogg', # .ogg
120
+
121
+ 'application/pdf', # .pdf
122
+ 'application/msword', # .doc
123
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', # .docx
124
+ 'application/vnd.ms-powerpoint', # .pps
125
+ 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', # .ppsx
126
+ 'application/vnd.ms-excel', # .pps
127
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' # .ppsx
128
+ ]
129
+
130
+ common_magics = common_types.map do |common_type|
131
+ magics.find { |_, type, _| type == common_type }
132
+ end
133
+
134
+ magics = (common_magics.compact + magics).uniq
135
+
136
+ puts '# -*- coding: binary -*-'
137
+ puts '# frozen_string_literal: true'
138
+ puts "# Generated from #{FILE}"
139
+ puts 'class MimeMagic'
140
+ puts ' # @private'
141
+ puts ' # :nodoc:'
142
+ puts ' EXTENSIONS = {'
143
+ extensions.keys.sort.each do |key|
144
+ puts " '#{key}' => '#{extensions[key]}',"
145
+ end
146
+ puts ' }'
147
+ puts ' # @private'
148
+ puts ' # :nodoc:'
149
+ puts ' TYPES = {'
150
+ types.keys.sort.each do |key|
151
+ exts = types[key][0].join(' ')
152
+ parents = types[key][1].sort.join(' ')
153
+ comment = types[key][2].inspect
154
+ puts " '#{key}' => [%w(#{exts}), %w(#{parents}), #{comment}],"
155
+ end
156
+ puts ' }'
157
+ puts ' # @private'
158
+ puts ' # :nodoc:'
159
+ puts ' MAGIC = ['
160
+ magics.each do |_priority, type, matches|
161
+ puts " ['#{type}', #{matches.inspect}],"
162
+ end
163
+ puts ' ]'
164
+ puts 'end'
Binary file
Binary file
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/ruby
2
+ print "Hello World"
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,160 @@
1
+ require 'minitest/autorun'
2
+ require 'mimemagic'
3
+ require 'stringio'
4
+ require 'forwardable'
5
+
6
+ class TestMimeMagic < Minitest::Test
7
+ # Do deep copy for constants of initial state.
8
+ INIT_EXTENSIONS = Marshal.load(Marshal.dump(MimeMagic::EXTENSIONS))
9
+ INIT_TYPES = Marshal.load(Marshal.dump(MimeMagic::TYPES))
10
+ INIT_MAGIC = Marshal.load(Marshal.dump(MimeMagic::MAGIC))
11
+
12
+ def setup
13
+ extentions = Marshal.load(Marshal.dump(INIT_EXTENSIONS))
14
+ types = Marshal.load(Marshal.dump(INIT_TYPES))
15
+ magic = Marshal.load(Marshal.dump(INIT_MAGIC))
16
+ MimeMagic.send(:remove_const, :EXTENSIONS) if MimeMagic.const_defined?(:EXTENSIONS)
17
+ MimeMagic.send(:remove_const, :TYPES) if MimeMagic.const_defined?(:TYPES)
18
+ MimeMagic.send(:remove_const, :MAGIC) if MimeMagic.const_defined?(:MAGIC)
19
+ MimeMagic.const_set('EXTENSIONS', extentions)
20
+ MimeMagic.const_set('TYPES', types)
21
+ MimeMagic.const_set('MAGIC', magic)
22
+ end
23
+
24
+ def test_have_type_mediatype_and_subtype
25
+ assert_equal 'text/html', MimeMagic.new('text/html').type
26
+ assert_equal 'text', MimeMagic.new('text/html').mediatype
27
+ assert_equal 'html', MimeMagic.new('text/html').subtype
28
+ end
29
+
30
+ def test_have_mediatype_helpers
31
+ assert MimeMagic.new('text/plain').text?
32
+ assert MimeMagic.new('text/html').text?
33
+ assert MimeMagic.new('application/xhtml+xml').text?
34
+ refute MimeMagic.new('application/octet-stream').text?
35
+ refute MimeMagic.new('image/png').text?
36
+ assert MimeMagic.new('image/png').image?
37
+ assert MimeMagic.new('video/ogg').video?
38
+ assert MimeMagic.new('audio/mpeg').audio?
39
+ end
40
+
41
+ def test_have_hierarchy
42
+ assert MimeMagic.new('text/html').child_of?('text/plain')
43
+ assert MimeMagic.new('text/x-java').child_of?('text/plain')
44
+ end
45
+
46
+ def test_have_extensions
47
+ assert_equal %w[htm html], MimeMagic.new('text/html').extensions
48
+ end
49
+
50
+ def test_have_comment
51
+ assert_equal 'HTML document', MimeMagic.new('text/html').comment
52
+ end
53
+
54
+ def test_recognize_extensions
55
+ assert_equal 'text/html', MimeMagic.by_extension('.html').to_s
56
+ assert_equal 'text/html', MimeMagic.by_extension('html').to_s
57
+ assert_equal 'text/html', MimeMagic.by_extension(:html).to_s
58
+ assert_equal 'application/x-ruby', MimeMagic.by_extension('rb').to_s
59
+ assert_nil MimeMagic.by_extension('crazy')
60
+ assert_nil MimeMagic.by_extension('')
61
+ end
62
+
63
+ def test_recognize_by_a_path
64
+ assert_equal 'text/html', MimeMagic.by_path('/adsjkfa/kajsdfkadsf/kajsdfjasdf.html').to_s
65
+ assert_equal 'text/html', MimeMagic.by_path('something.html').to_s
66
+ assert_equal 'application/x-ruby', MimeMagic.by_path('wtf.rb').to_s
67
+ assert_nil MimeMagic.by_path('where/am.html/crazy')
68
+ assert_nil MimeMagic.by_path('')
69
+ end
70
+
71
+ def test_recognize_xlsx_as_zip_without_magic
72
+ file = 'test/files/application.vnd.openxmlformats-officedocument.spreadsheetml.sheet'
73
+ %w[msoffice rubyxl gdocs].each do |variant|
74
+ file = "test/files/application.vnd.openxmlformats-officedocument.spreadsheetml{#{variant}}.sheet"
75
+ assert_equal 'application/zip', MimeMagic.by_magic(File.read(file)).to_s
76
+ assert_equal 'application/zip', MimeMagic.by_magic(File.open(file, 'rb')).to_s
77
+ end
78
+ end
79
+
80
+ def test_recognize_by_magic
81
+ load 'mimemagic/overlay.rb'
82
+ Dir['test/files/*'].each do |file|
83
+ mime = file[11..-1].sub('.', '/').sub(/\{\w+\}/, '')
84
+ assert_equal mime, MimeMagic.by_magic(File.read(file)).to_s
85
+ assert_equal mime, MimeMagic.by_magic(File.open(file, 'rb')).to_s
86
+ end
87
+ end
88
+
89
+ def test_recognize_all_by_magic
90
+ load 'mimemagic/overlay.rb'
91
+ %w[msoffice rubyxl gdocs].each do |variant|
92
+ file = "test/files/application.vnd.openxmlformats-officedocument.spreadsheetml{#{variant}}.sheet"
93
+ mimes = %w[application/vnd.openxmlformats-officedocument.spreadsheetml.sheet application/zip]
94
+ assert_equal mimes, MimeMagic.all_by_magic(File.read(file)).map(&:type)
95
+ end
96
+ end
97
+
98
+ def test_have_add
99
+ MimeMagic.add('application/mimemagic-test',
100
+ extensions: %w[ext1 ext2],
101
+ parents: 'application/xml',
102
+ comment: 'Comment')
103
+ assert_equal 'application/mimemagic-test', MimeMagic.by_extension('ext1').to_s
104
+ assert_equal 'application/mimemagic-test', MimeMagic.by_extension('ext2').to_s
105
+ assert_equal 'Comment', MimeMagic.by_extension('ext2').comment
106
+ assert_equal %w[ext1 ext2], MimeMagic.new('application/mimemagic-test').extensions
107
+ assert MimeMagic.new('application/mimemagic-test').child_of?('text/plain')
108
+ end
109
+
110
+ def test_process_magic
111
+ MimeMagic.add('application/mimemagic-test',
112
+ magic: [[0, 'MAGICTEST'], # MAGICTEST at position 0
113
+ [1, 'MAGICTEST'], # MAGICTEST at position 1
114
+ [9..12, 'MAGICTEST'], # MAGICTEST starting at position 9 to 12
115
+ [2, 'MAGICTEST', [[0, 'X'], [0, 'Y']]]]) # MAGICTEST at position 2 and (X at 0 or Y at 0)
116
+
117
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic('MAGICTEST').to_s
118
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic('XMAGICTEST').to_s
119
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(' MAGICTEST').to_s
120
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic('123456789MAGICTEST').to_s
121
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic('123456789ABMAGICTEST').to_s
122
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic('123456789ABCMAGICTEST').to_s
123
+ assert_nil MimeMagic.by_magic('123456789ABCDMAGICTEST')
124
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic('X MAGICTEST').to_s
125
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic('Y MAGICTEST').to_s
126
+ assert_nil MimeMagic.by_magic('Z MAGICTEST')
127
+
128
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(StringIO.new('MAGICTEST')).to_s
129
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(StringIO.new('XMAGICTEST')).to_s
130
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(StringIO.new(' MAGICTEST')).to_s
131
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(StringIO.new('123456789MAGICTEST')).to_s
132
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(StringIO.new('123456789ABMAGICTEST')).to_s
133
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(StringIO.new('123456789ABCMAGICTEST')).to_s
134
+ assert_nil MimeMagic.by_magic(StringIO.new('123456789ABCDMAGICTEST'))
135
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(StringIO.new('X MAGICTEST')).to_s
136
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(StringIO.new('Y MAGICTEST')).to_s
137
+ assert_nil MimeMagic.by_magic(StringIO.new('Z MAGICTEST'))
138
+ end
139
+
140
+ class IOObject
141
+ def initialize
142
+ @io = StringIO.new('MAGICTEST')
143
+ end
144
+
145
+ extend Forwardable
146
+ delegate %i[read size rewind eof? close] => :@io
147
+ end
148
+
149
+ class StringableObject
150
+ def to_s
151
+ 'MAGICTEST'
152
+ end
153
+ end
154
+
155
+ def test_handle_different_file_objects
156
+ MimeMagic.add('application/mimemagic-test', magic: [[0, 'MAGICTEST']])
157
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(IOObject.new).to_s
158
+ assert_equal 'application/mimemagic-test', MimeMagic.by_magic(StringableObject.new).to_s
159
+ end
160
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: afp_mimemagic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.6
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Mendler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-12-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Fast mime detection by extension or content in pure ruby (Uses freedesktop.org.xml
42
+ shared-mime-info database)
43
+ email:
44
+ - mail@daniel-mendler.de
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - ".travis.yml"
51
+ - ".yardopts"
52
+ - CHANGELOG.md
53
+ - Gemfile
54
+ - LICENSE
55
+ - README.md
56
+ - Rakefile
57
+ - lib/mimemagic.rb
58
+ - lib/mimemagic/overlay.rb
59
+ - lib/mimemagic/tables.rb
60
+ - lib/mimemagic/version.rb
61
+ - mimemagic.gemspec
62
+ - script/freedesktop.org.xml
63
+ - script/generate-mime.rb
64
+ - test/files/application.gzip
65
+ - test/files/application.vnd.openxmlformats-officedocument.spreadsheetml{gdocs}.sheet
66
+ - test/files/application.vnd.openxmlformats-officedocument.spreadsheetml{msoffice}.sheet
67
+ - test/files/application.vnd.openxmlformats-officedocument.spreadsheetml{rubyxl}.sheet
68
+ - test/files/application.x-bzip
69
+ - test/files/application.x-ruby
70
+ - test/files/application.x-tar
71
+ - test/files/application.zip
72
+ - test/files/image.jpeg
73
+ - test/files/image.png
74
+ - test/mimemagic_test.rb
75
+ homepage: https://github.com/minad/mimemagic
76
+ licenses:
77
+ - GPL-2.0
78
+ metadata:
79
+ changelog_uri: https://github.com/minad/mimemagic/blob/master/CHANGELOG.md
80
+ source_code_uri: https://github.com/minad/mimemagic
81
+ bug_tracker_uri: https://github.com/minad/mimemagic/issues
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubygems_version: 3.0.8
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Fast mime detection by extension or content
101
+ test_files: []