ruby-filemagic 0.6.2-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,98 @@
1
+ #ifndef FILEMAGIC_H
2
+ #define FILEMAGIC_H
3
+
4
+ #include "ruby.h"
5
+ #include <math.h>
6
+ #include <errno.h>
7
+ #include <magic.h>
8
+ #ifdef HAVE_FILE_PATCHLEVEL_H
9
+ #include <file/patchlevel.h>
10
+ #endif
11
+
12
+ #define GetMagicSet(obj, ms) {\
13
+ if (RTEST(rb_magic_closed_p(obj))) {\
14
+ rb_raise(rb_eRuntimeError, "closed stream");\
15
+ }\
16
+ else {\
17
+ Data_Get_Struct((obj), struct magic_set, (ms));\
18
+ }\
19
+ }
20
+
21
+ #define RB_MAGIC_TYPE_FILE magic_file(ms, str)
22
+ #define RB_MAGIC_TYPE_BUFFER magic_buffer(ms, str, RSTRING_LEN(arg))
23
+
24
+ #define RB_MAGIC_TYPE(what, WHAT) \
25
+ static VALUE \
26
+ rb_magic_##what(int argc, VALUE *argv, VALUE self) {\
27
+ VALUE arg, simple, res;\
28
+ const char *str, *type;\
29
+ magic_t ms;\
30
+ \
31
+ rb_scan_args(argc, argv, "11", &arg, &simple);\
32
+ \
33
+ str = StringValuePtr(arg);\
34
+ GetMagicSet(self, ms);\
35
+ \
36
+ if ((type = RB_MAGIC_TYPE_##WHAT) == NULL) {\
37
+ rb_raise(rb_FileMagicError, "failed lookup: %s", magic_error(ms));\
38
+ }\
39
+ \
40
+ res = rb_str_new2(type);\
41
+ \
42
+ if (NIL_P(simple)) {\
43
+ simple = rb_attr_get(self, rb_intern("@simplified"));\
44
+ }\
45
+ \
46
+ if (RTEST(simple)) {\
47
+ rb_funcall(res, rb_intern("downcase!"), 0);\
48
+ \
49
+ return rb_funcall(res, rb_intern("slice"), 2,\
50
+ rb_const_get(cFileMagic, rb_intern("SIMPLE_RE")), INT2FIX(1));\
51
+ }\
52
+ else {\
53
+ return res;\
54
+ }\
55
+ }
56
+
57
+ #define RB_MAGIC_APPRENTICE(what) \
58
+ static VALUE \
59
+ rb_magic_##what(int argc, VALUE *argv, VALUE self) {\
60
+ VALUE str;\
61
+ const char *file;\
62
+ magic_t ms;\
63
+ \
64
+ file = rb_scan_args(argc, argv, "01", &str) == 1 ? StringValuePtr(str) : NULL;\
65
+ \
66
+ GetMagicSet(self, ms);\
67
+ \
68
+ return magic_##what(ms, file) ? Qfalse : Qtrue;\
69
+ }
70
+
71
+ #define RB_MAGIC_SET_VERSION(m, p) sprintf(version, "%d.%02d", m, p);
72
+
73
+ static VALUE cFileMagic, rb_FileMagicError;
74
+
75
+ static VALUE rb_magic_getpath(VALUE);
76
+ static VALUE rb_magic_flags(VALUE, VALUE);
77
+
78
+ static VALUE rb_magic_new(int, VALUE*, VALUE);
79
+ static void rb_magic_free(magic_t);
80
+ static VALUE rb_magic_init(int, VALUE*, VALUE);
81
+
82
+ static VALUE rb_magic_close(VALUE);
83
+ static VALUE rb_magic_closed_p(VALUE);
84
+
85
+ static VALUE rb_magic_file(int, VALUE*, VALUE);
86
+ static VALUE rb_magic_buffer(int, VALUE*, VALUE);
87
+
88
+ static VALUE rb_magic_getflags(VALUE);
89
+ static VALUE rb_magic_setflags(VALUE, VALUE);
90
+
91
+ static VALUE rb_magic_list(int, VALUE*, VALUE);
92
+ static VALUE rb_magic_load(int, VALUE*, VALUE);
93
+ static VALUE rb_magic_check(int, VALUE*, VALUE);
94
+ static VALUE rb_magic_compile(int, VALUE*, VALUE);
95
+
96
+ void Init_ruby_filemagic(void);
97
+
98
+ #endif /* FILEMAGIC_H */
data/lib/filemagic.rb ADDED
@@ -0,0 +1,142 @@
1
+ begin
2
+ require "filemagic/#{RUBY_VERSION[/\d+.\d+/]}/ruby_filemagic"
3
+ rescue LoadError => err
4
+ raise if err.respond_to?(:path) && !err.path
5
+ require 'filemagic/ruby_filemagic'
6
+ end
7
+
8
+ require 'filemagic/version'
9
+
10
+ class FileMagic
11
+
12
+ DEFAULT_MAGIC = __FILE__.sub(/\.rb\z/, '/magic.mgc')
13
+
14
+ ENV['MAGIC'] ||= DEFAULT_MAGIC unless path
15
+
16
+ # Map flag names to their values (:name => Integer).
17
+ FLAGS_BY_SYM = [
18
+ :none, # No flags
19
+ :debug, # Turn on debugging
20
+ :symlink, # Follow symlinks
21
+ :compress, # Check inside compressed files
22
+ :devices, # Look at the contents of devices
23
+ :mime_type, # Return only the MIME type
24
+ :continue, # Return all matches
25
+ :check, # Print warnings to stderr
26
+ :preserve_atime, # Restore access time on exit
27
+ :raw, # Don't translate unprint chars
28
+ :error, # Handle ENOENT etc as real errors
29
+ :mime_encoding, # Return only the MIME encoding
30
+ :mime, # MAGIC_MIME_TYPE | MAGIC_MIME_ENCODING
31
+ :apple, # Return the Apple creator and type
32
+ :no_check_compress, # Don't check for compressed files
33
+ :no_check_tar, # Don't check for tar files
34
+ :no_check_soft, # Don't check magic entries
35
+ :no_check_apptype, # Don't check application type
36
+ :no_check_elf, # Don't check for elf details
37
+ :no_check_text, # Don't check for text files
38
+ :no_check_cdf, # Don't check for cdf files
39
+ :no_check_tokens, # Don't check ascii/tokens
40
+ :no_check_encoding, # Don't check text encodings
41
+ :no_check_builtin, # No built-in tests; only consult the magic file
42
+
43
+ # Defined for backwards compatibility (renamed)
44
+ :no_check_ascii, # MAGIC_NO_CHECK_TEXT
45
+
46
+ # Defined for backwards compatibility; do nothing
47
+ :no_check_fortran, # Don't check ascii/fortran
48
+ :no_check_troff # Don't check ascii/troff
49
+ ].inject({}) { |flags, flag|
50
+ const = "MAGIC_#{flag.to_s.upcase}"
51
+ flags.update(flag => const_defined?(const) && const_get(const))
52
+ }
53
+
54
+ # Map flag values to their names (Integer => :name).
55
+ FLAGS_BY_INT = FLAGS_BY_SYM.invert.update(0 => :none)
56
+
57
+ # Extract "simple" MIME type.
58
+ SIMPLE_RE = %r{([.\w\/-]+)}
59
+
60
+ @fm = {}
61
+
62
+ class << self
63
+
64
+ # Provide a "magic singleton".
65
+ def fm(*flags)
66
+ options = flags.last.is_a?(Hash) ? flags.pop : {}
67
+
68
+ if fm = @fm[key = [flags = flags(flags), options]]
69
+ return fm unless fm.closed?
70
+ end
71
+
72
+ @fm[key] = new(flags, options)
73
+ end
74
+
75
+ # Clear our instance cache.
76
+ def clear!
77
+ @fm.each_value(&:close).clear
78
+ end
79
+
80
+ # Just like #new, but takes an optional block, in which case #close
81
+ # is called at the end and the value of the block is returned.
82
+ def open(*flags)
83
+ fm = new(*flags)
84
+
85
+ if block_given?
86
+ begin
87
+ yield fm
88
+ ensure
89
+ fm.close
90
+ end
91
+ else
92
+ fm
93
+ end
94
+ end
95
+
96
+ # Just a short-cut to #open with the +mime+ flag set.
97
+ def mime(*flags, &block)
98
+ open(:mime, *flags, &block)
99
+ end
100
+
101
+ def magic_version(default = MAGIC_VERSION)
102
+ default != '0' ? default :
103
+ user_magic_version ||
104
+ auto_magic_version ||
105
+ [default, 'unknown']
106
+ end
107
+
108
+ private
109
+
110
+ def user_magic_version(key = 'MAGIC_VERSION')
111
+ [ENV[key], 'user-specified'] if ENV[key]
112
+ end
113
+
114
+ def auto_magic_version
115
+ require 'nuggets/file/which'
116
+
117
+ if cmd = File.which_command([
118
+ 'dpkg-query -f \'${Version}\' -W libmagic-dev',
119
+ 'file -v'
120
+ ])
121
+ [%x{#{cmd}}[/\d+\.\d+/], 'auto-detected']
122
+ end
123
+ rescue LoadError
124
+ end
125
+
126
+ end
127
+
128
+ attr_writer :simplified
129
+
130
+ def simplified?
131
+ @simplified
132
+ end
133
+
134
+ def io(io, length = 8)
135
+ buffer(io.read(length))
136
+ end
137
+
138
+ def inspect
139
+ super.insert(-2, closed? ? ' (closed)' : '')
140
+ end
141
+
142
+ end
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,99 @@
1
+ require 'filemagic'
2
+
3
+ module FileMagic::Ext
4
+
5
+ def self.included(base)
6
+ base.class_eval {
7
+ extend ClassMethods
8
+ include InstanceMethods
9
+ }
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ def file_type(file, *flags)
15
+ raise NotImplementedError, 'must be implemented by including class'
16
+ end
17
+
18
+ def file(file, *flags)
19
+ file_type(file, *flags)
20
+ end
21
+
22
+ def mime_type(file, *flags)
23
+ file_type(file, *flags.unshift(:mime))
24
+ end
25
+
26
+ alias_method :mime, :mime_type
27
+
28
+ def content_type(file, *flags)
29
+ mime_type(file, *flags << { simplified: true })
30
+ end
31
+
32
+ end
33
+
34
+ module InstanceMethods
35
+
36
+ def file_type(*flags)
37
+ self.class.file_type(self, *flags)
38
+ end
39
+
40
+ alias_method :file, :file_type
41
+
42
+ def mime_type(*flags)
43
+ self.class.mime_type(self, *flags)
44
+ end
45
+
46
+ alias_method :mime, :mime_type
47
+
48
+ def content_type(*flags)
49
+ self.class.content_type(self, *flags)
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+
56
+ class File
57
+
58
+ include FileMagic::Ext
59
+
60
+ def self.file_type(file, *flags)
61
+ FileMagic.fm(*flags).file(file.respond_to?(:path) ? file.path : file)
62
+ rescue FileMagic::FileMagicError
63
+ end
64
+
65
+ end
66
+
67
+ class String
68
+
69
+ include FileMagic::Ext
70
+
71
+ def self.file_type(string, *flags)
72
+ FileMagic.fm(*flags).buffer(string)
73
+ rescue FileMagic::FileMagicError
74
+ end
75
+
76
+ end
77
+
78
+ if $0 == __FILE__
79
+ f = __FILE__
80
+ p f
81
+
82
+ p File.file_type(f)
83
+ p File.mime_type(f)
84
+ p File.content_type(f)
85
+
86
+ f = File.new(f)
87
+ p f
88
+
89
+ p f.file_type
90
+ p f.mime_type
91
+ p f.content_type
92
+
93
+ s = '#! /usr/bin/ruby'
94
+ p s
95
+
96
+ p s.file_type
97
+ p s.mime_type
98
+ p s.content_type
99
+ end
Binary file
@@ -0,0 +1,27 @@
1
+ class FileMagic
2
+
3
+ module Version
4
+
5
+ MAJOR = 0
6
+ MINOR = 6
7
+ TINY = 2
8
+
9
+ class << self
10
+
11
+ # Returns array representation.
12
+ def to_a
13
+ [MAJOR, MINOR, TINY]
14
+ end
15
+
16
+ # Short-cut for version string.
17
+ def to_s
18
+ to_a.join('.')
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ VERSION = Version.to_s
26
+
27
+ end
@@ -0,0 +1 @@
1
+ require 'filemagic'
Binary file
@@ -0,0 +1,227 @@
1
+ require 'test/unit'
2
+ require 'filemagic'
3
+
4
+ class TestFileMagic < Test::Unit::TestCase
5
+
6
+ magic_version, origin = FileMagic.magic_version
7
+ MAGIC_VERSION = magic_version.to_f
8
+
9
+ warn <<-EOT
10
+
11
+ libmagic version: #{MAGIC_VERSION}#{" (#{origin})" if origin}
12
+ magic file from #{FileMagic.path}
13
+
14
+ EOT
15
+
16
+ def test_file
17
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
18
+
19
+ python_script = match_version(
20
+ 0 => 'a python script, ASCII text executable',
21
+ 5.11 => 'Python script, ASCII text executable'
22
+ )
23
+
24
+ res = fm.file(path_to('pyfile'))
25
+ assert_equal(python_script, res)
26
+
27
+ if File.symlink?(path_to('pylink'))
28
+ res = fm.file(path_to('pylink'))
29
+ assert_equal("symbolic link to `pyfile'", res.strip)
30
+ end
31
+
32
+ fm.close
33
+ fm = FileMagic.new(FileMagic::MAGIC_SYMLINK)
34
+
35
+ res = fm.file(path_to('pylink'))
36
+ assert_equal(python_script, res)
37
+
38
+ fm.close
39
+ fm = FileMagic.new(FileMagic::MAGIC_SYMLINK | FileMagic::MAGIC_MIME)
40
+
41
+ res = fm.file(path_to('pylink'))
42
+ assert_equal('text/plain; charset=us-ascii', res)
43
+
44
+ fm.close
45
+ fm = FileMagic.new(FileMagic::MAGIC_COMPRESS)
46
+
47
+ res = fm.file(path_to('pyfile-compressed.gz'))
48
+ gzip_compressed = 'gzip compressed data, was "pyfile-compressed"'
49
+ assert_match(Gem.win_platform? ? /^#{gzip_compressed}/ :
50
+ /^#{python_script} \(#{gzip_compressed}/, res)
51
+
52
+ fm.close
53
+ end
54
+
55
+ def test_buffer
56
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
57
+ res = fm.buffer("#!/bin/sh\n")
58
+ fm.close
59
+ assert_equal('POSIX shell script, ASCII text executable', res)
60
+ end
61
+
62
+ def test_check
63
+ return if Gem.win_platform?
64
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
65
+ res = silence_stderr { fm.check(path_to('perl')) }
66
+ fm.close
67
+ assert(res)
68
+ end
69
+
70
+ def test_check_compiled
71
+ return if MAGIC_VERSION <= 5.09
72
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
73
+ res = silence_stderr { fm.check(path_to('perl.mgc')) }
74
+ fm.close
75
+ assert(res)
76
+ end
77
+
78
+ def test_compile
79
+ assert(File.writable?('.'), "can't write to current directory")
80
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
81
+ res = fm.compile(path_to('perl'))
82
+ fm.close
83
+ assert(res)
84
+ File.unlink(path_to('perl.mgc', '.'))
85
+ end
86
+
87
+ def test_block
88
+ block_fm = nil
89
+ res = FileMagic.open(FileMagic::MAGIC_NONE) { |fm|
90
+ block_fm = fm
91
+ fm.file(path_to('pyfile'))
92
+ }
93
+ assert_equal(match_version(
94
+ 0 => 'a python script, ASCII text executable',
95
+ 5.11 => 'Python script, ASCII text executable'
96
+ ), res)
97
+ assert block_fm.closed?
98
+ end
99
+
100
+ def test_flags_to_int
101
+ assert_raise(TypeError) { FileMagic.flags(0) }
102
+ assert_equal(0, FileMagic.flags([FileMagic::MAGIC_NONE]))
103
+ assert_equal(0, FileMagic.flags([:none]))
104
+ assert_equal(0, FileMagic.flags([]))
105
+ assert_equal(1072, FileMagic.flags([:mime, :continue]))
106
+ end
107
+
108
+ def test_setflags
109
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
110
+ assert_equal([], fm.flags)
111
+ fm.flags = FileMagic::MAGIC_SYMLINK
112
+ assert_equal([:symlink], fm.flags)
113
+ fm.close
114
+ end
115
+
116
+ def test_abbr
117
+ fm = FileMagic.new(:mime, :continue)
118
+ assert_equal([:mime_type, :continue, :mime_encoding], fm.flags)
119
+ fm.flags = :symlink
120
+ assert_equal([:symlink], fm.flags)
121
+ fm.close
122
+ end
123
+
124
+ def test_close
125
+ fm = FileMagic.new
126
+ fm.close
127
+ assert fm.closed?
128
+ fm.close
129
+ assert fm.closed?
130
+ end
131
+
132
+ # tests adapted from mahoro:
133
+
134
+ def test_mahoro_file
135
+ fm = FileMagic.new
136
+ fm.flags = FileMagic::MAGIC_NONE
137
+ assert_equal(match_version(
138
+ 0 => 'ASCII C program text',
139
+ 5.11 => 'C source, ASCII text'
140
+ ), fm.file(path_to('mahoro.c')))
141
+ end
142
+
143
+ def test_mahoro_mime_file
144
+ fm = FileMagic.new
145
+ fm.flags = FileMagic::MAGIC_MIME
146
+ assert_equal('text/x-c; charset=us-ascii', fm.file(path_to('mahoro.c')))
147
+ end
148
+
149
+ def test_mahoro_buffer
150
+ fm = FileMagic.new
151
+ fm.flags = FileMagic::MAGIC_NONE
152
+ assert_equal(match_version(
153
+ 0 => 'ASCII C program text',
154
+ 5.11 => 'C source, ASCII text'
155
+ ), fm.buffer(File.read(path_to('mahoro.c'))))
156
+ end
157
+
158
+ def test_mahoro_mime_buffer
159
+ fm = FileMagic.new
160
+ fm.flags = FileMagic::MAGIC_MIME
161
+ assert_equal('text/x-c; charset=us-ascii', fm.buffer(File.read(path_to('mahoro.c'))))
162
+ end
163
+
164
+ def test_mahoro_valid
165
+ fm = FileMagic.new
166
+ assert(silence_stderr { fm.valid? }, 'Default database was not valid.')
167
+ end
168
+
169
+ # test abbreviating mime types
170
+
171
+ def test_abbrev_mime_type
172
+ fm = FileMagic.mime
173
+
174
+ refute fm.simplified?
175
+ assert_equal('text/plain; charset=us-ascii', fm.file(path_to('perl')))
176
+
177
+ fm.simplified = true
178
+ assert fm.simplified?
179
+ assert_equal('text/plain', fm.file(path_to('perl')))
180
+ assert_equal(match_version(
181
+ 0 => 'application/vnd.ms-office',
182
+ 5.11 => 'application/msword',
183
+ 5.14 => 'application/vnd.ms-office'
184
+ ), fm.file(path_to('excel-example.xls')))
185
+ end
186
+
187
+ def test_singleton
188
+ fm1 = FileMagic.fm
189
+ assert_equal(fm1, FileMagic.fm)
190
+
191
+ refute fm1.simplified?
192
+ assert_equal('ASCII text', fm1.file(path_to('perl')))
193
+
194
+ fm2 = FileMagic.fm(:mime)
195
+ assert_equal(fm2, FileMagic.fm(:mime))
196
+ refute_equal(fm2, fm1)
197
+
198
+ refute fm2.simplified?
199
+ assert_equal('text/plain; charset=us-ascii', fm2.file(path_to('perl')))
200
+
201
+ fm3 = FileMagic.fm(:mime, simplified: true)
202
+ assert_equal(fm3, FileMagic.fm(:mime, simplified: true))
203
+ refute_equal(fm3, fm2)
204
+ refute_equal(fm3, fm1)
205
+
206
+ assert fm3.simplified?
207
+ assert_equal('text/plain', fm3.file(path_to('perl')))
208
+ end
209
+
210
+ # utility methods:
211
+
212
+ def path_to(file, dir = File.dirname(__FILE__))
213
+ File.join(dir, file)
214
+ end
215
+
216
+ def silence_stderr
217
+ require 'nuggets/io/redirect'
218
+ $stderr.redirect { yield }
219
+ rescue LoadError
220
+ yield
221
+ end
222
+
223
+ def match_version(versions)
224
+ versions.sort_by { |k,| -k }.find { |k,| k <= MAGIC_VERSION }.last
225
+ end
226
+
227
+ end