afp_mimemagic 0.3.6

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.
@@ -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: []