ruby-filemagic 0.2.1

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,28 @@
1
+ --------------------------------------------------------------------------------
2
+ 7/28/2003 version 0.1.0
3
+
4
+ o Initial release.
5
+
6
+ --------------------------------------------------------------------------------
7
+ 7/30/2003 version 0.1.1
8
+
9
+ o Added manual close method
10
+ o Added unit test suite
11
+
12
+ --------------------------------------------------------------------------------
13
+ 9/12/2008 version 0.2.0
14
+
15
+ o Modified C API
16
+ o Uniform C function prefix rb_magic_ (instead of magick_)
17
+ o Uniform Ruby method prefix fm_ (instead of none)
18
+ o More magic(4) constants (if available)
19
+ o Added Ruby wrapper for more rubyish interface
20
+ o Added extensions for File and String core classes
21
+ o Added/updated project files
22
+ o Now available as a Rubygem!
23
+
24
+ --------------------------------------------------------------------------------
25
+ 9/18/2008 version 0.2.1
26
+
27
+ o Added mahoro source file and tests for reference and inspiration
28
+ o We have a Rubyforge project now! :-)
data/README ADDED
@@ -0,0 +1,69 @@
1
+ = FileMagic Library Binding
2
+
3
+ == VERSION
4
+
5
+ This documentation refers to filemagic version 0.2.1
6
+
7
+
8
+ == DESCRIPTION
9
+
10
+ === Revised version
11
+
12
+ September 12, 2008 Jens Wille <jens.wille@uni-koeln.de>
13
+
14
+ Similar to Ricardo[http://github.com/ricardochimal/ruby-filemagic]
15
+ I wanted this project to make some progress. My needs went a bit
16
+ farther than his, though ;-) Enjoy anyway!
17
+
18
+ Install the gem from github[http://github.com]:
19
+
20
+ sudo gem install blackwinter-ruby-filemagic --source http://gems.github.com
21
+
22
+ === Original package
23
+
24
+ July 28, 2003 Travis Whitton <tinymountain@gmail.com>
25
+
26
+ This is one of my first ruby bindings, so suggestions are welcome. See
27
+ filemagic.rd and test.rb for usage.
28
+
29
+ to install, run these commands:
30
+
31
+ ruby extconf.rb
32
+ make
33
+ su
34
+ make install
35
+
36
+ the file(1) library and headers are required.
37
+ I have file 0.4.3.
38
+
39
+ Enjoy!
40
+ Travis
41
+
42
+
43
+ == LINKS
44
+
45
+ * <http://grub.ath.cx/filemagic/>
46
+ * <http://github.com/blackwinter/ruby-filemagic>
47
+ * <http://ruby-filemagic.rubyforge.org/>
48
+ * <http://rubyforge.org/projects/ruby-filemagic>
49
+
50
+
51
+ == AUTHORS
52
+
53
+ * Travis Whitton <mailto:tinymountain@gmail.com> (Original author)
54
+ * Jens Wille <mailto:jens.wille@uni-koeln.de>
55
+
56
+
57
+ == COPYING
58
+
59
+ The filemagic extension library is copywrited free software by Travis Whitton
60
+ <tinymountain@gmail.com>. You can redistribute it under the terms specified in
61
+ the COPYING file of the Ruby distribution.
62
+
63
+
64
+ == WARRANTY
65
+
66
+ THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
67
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
68
+ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
69
+ PURPOSE.
@@ -0,0 +1,26 @@
1
+ require %q{lib/filemagic/version}
2
+
3
+ begin
4
+ require 'hen'
5
+
6
+ Hen.lay! {{
7
+ :rubyforge => {
8
+ :package => 'ruby-filemagic',
9
+ :project => 'ruby-filemagic',
10
+ :rdoc_dir => nil
11
+ },
12
+
13
+ :gem => {
14
+ :version => FileMagic::VERSION,
15
+ :summary => 'Ruby bindings to the magic(4) library',
16
+ :authors => ['Travis Whitton', 'Jens Wille'],
17
+ :email => ['tinymountain@gmail.com', 'jens.wille@uni-koeln.de'],
18
+ :homepage => 'http://ruby-filemagic.rubyforge.org/',
19
+ :files => FileList['lib/**/*.rb', 'ext/**/*.c', 'test/*'].to_a,
20
+ :extensions => FileList['ext/**/extconf.rb'].to_a,
21
+ :extra_files => FileList['[A-Z]*', 'info/*'].to_a
22
+ }
23
+ }}
24
+ rescue LoadError
25
+ abort "Please install the 'hen' gem first."
26
+ end
data/TODO ADDED
@@ -0,0 +1,9 @@
1
+ o Find a better way to handle magic_load than just defaulting to NULL
2
+ o Find a way to make magic_check work on NULL
3
+ o [DONE] Find a way to make magic_setflags work
4
+ o Refactor code into initialize instead of new
5
+ o [DONE?] Enable blocks for automatic cleanup:
6
+
7
+ FileMagic.open("somefile.txt") do |file|
8
+ # close is called at the end of this block
9
+ end
@@ -0,0 +1,8 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("magic")
4
+ if have_library("magic", "magic_open") and have_header("magic.h")
5
+ create_makefile("filemagic")
6
+ else
7
+ print "*** ERROR: missing required library to compile this module\n"
8
+ end
@@ -0,0 +1,213 @@
1
+ /*********************************************************
2
+
3
+ filemagic.c
4
+
5
+ a Ruby extension to bind Ruby to the libmagic library
6
+ (ftp://ftp.astron.com/pub/file/)
7
+
8
+ patterned very closely off of audiofile.c by jaredj which
9
+ is patterned very very closely off of gdbm.c by matz ;-)
10
+
11
+ $Author: twhitton $
12
+ $Date: 2003/07/30 13:25:10 $
13
+
14
+ *********************************************************/
15
+
16
+ #include "ruby.h"
17
+ #include <magic.h>
18
+
19
+ static VALUE cFileMagic, rb_FileMagicError;
20
+
21
+ #define GetMagicCookie(obj, cookie) {\
22
+ if (rb_funcall(obj, rb_intern("closed?"), 0))\
23
+ rb_raise(rb_eRuntimeError, "closed stream");\
24
+ Data_Get_Struct(obj, struct magic_set, cookie);\
25
+ }
26
+
27
+ /*
28
+ GC never seems to happen until the program terminates, but this is called
29
+ on any unclosed objects
30
+ */
31
+ static void rb_magic_free(magic_t cookie) {
32
+ magic_close(cookie);
33
+ }
34
+
35
+ static VALUE rb_magic_init(VALUE self, VALUE flags) {
36
+ }
37
+
38
+ /* Frees resources allocated */
39
+ static VALUE rb_magic_close(VALUE self) {
40
+ magic_t cookie;
41
+
42
+ GetMagicCookie(self, cookie);
43
+ magic_close(cookie);
44
+
45
+ /* This keeps rb_magic_free from trying to free closed objects */
46
+ RDATA(self)->data = NULL;
47
+
48
+ return Qnil;
49
+ }
50
+
51
+ /* FileMagic.new */
52
+ static VALUE rb_magic_new(VALUE class, VALUE flags) {
53
+ VALUE obj;
54
+ magic_t cookie;
55
+
56
+ cookie = magic_open(NUM2INT(flags));
57
+ if (cookie == NULL)
58
+ rb_fatal("out of memory");
59
+ if (magic_load(cookie, NULL) == -1)
60
+ rb_fatal("%s", magic_error(cookie));
61
+
62
+ obj = Data_Wrap_Struct(class, 0, rb_magic_free, cookie);
63
+ rb_obj_call_init(obj, 1, &flags);
64
+
65
+ return obj;
66
+ }
67
+
68
+ /* Return a string describing file */
69
+ static VALUE rb_magic_file(VALUE self, VALUE file) {
70
+ const char *m;
71
+ magic_t cookie;
72
+
73
+ m = STR2CSTR(file);
74
+ GetMagicCookie(self, cookie);
75
+ if ((m = magic_file(cookie, m)) == NULL)
76
+ rb_raise(rb_FileMagicError, magic_error(cookie));
77
+
78
+ return rb_str_new2(m);
79
+ }
80
+
81
+ /* Return a string describing the string buffer */
82
+ static VALUE rb_magic_buffer(VALUE self, VALUE buffer) {
83
+ int i = RSTRING(buffer)->len;
84
+ const char *m;
85
+ magic_t cookie;
86
+
87
+ m = STR2CSTR(buffer);
88
+ GetMagicCookie(self, cookie);
89
+ if ((m = magic_buffer(cookie, m, i)) == NULL)
90
+ rb_raise(rb_FileMagicError, magic_error(cookie));
91
+
92
+ return rb_str_new2(m);
93
+ }
94
+
95
+ /* Set flags on the cookie object */
96
+ static VALUE rb_magic_setflags(VALUE self, VALUE flags) {
97
+ int retval;
98
+ magic_t cookie;
99
+
100
+ GetMagicCookie(self, cookie);
101
+ retval = magic_setflags(cookie, NUM2INT(flags));
102
+
103
+ return INT2FIX(retval);
104
+ }
105
+
106
+ /* Checks validity of a magic database file */
107
+ static VALUE rb_magic_check(VALUE self, VALUE file) {
108
+ int retval;
109
+ const char *m;
110
+ magic_t cookie;
111
+
112
+ GetMagicCookie(self, cookie);
113
+ m = STR2CSTR(file);
114
+ retval = magic_check(cookie, m);
115
+
116
+ return INT2FIX(retval);
117
+ }
118
+
119
+ /* Compiles a magic database file */
120
+ static VALUE rb_magic_compile(VALUE self, VALUE file) {
121
+ int retval;
122
+ const char *m;
123
+ magic_t cookie;
124
+
125
+ GetMagicCookie(self, cookie);
126
+ m = STR2CSTR(file);
127
+ retval = magic_compile(cookie, m);
128
+
129
+ return INT2FIX(retval);
130
+ }
131
+
132
+ void Init_filemagic() {
133
+ cFileMagic = rb_define_class("FileMagic", rb_cObject);
134
+
135
+ rb_define_singleton_method(cFileMagic, "fm_new", rb_magic_new, 1);
136
+
137
+ rb_define_method(cFileMagic, "fm_initialize", rb_magic_init, 1);
138
+ rb_define_method(cFileMagic, "fm_close", rb_magic_close, 0);
139
+ rb_define_method(cFileMagic, "fm_file", rb_magic_file, 1);
140
+ rb_define_method(cFileMagic, "fm_buffer", rb_magic_buffer, 1);
141
+ rb_define_method(cFileMagic, "fm_setflags", rb_magic_setflags, 1);
142
+ rb_define_method(cFileMagic, "fm_check", rb_magic_check, 1);
143
+ rb_define_method(cFileMagic, "fm_compile", rb_magic_compile, 1);
144
+
145
+ rb_FileMagicError = rb_define_class_under(cFileMagic, "FileMagicError", rb_eStandardError);
146
+
147
+ #ifdef MAGIC_NONE
148
+ rb_define_const(cFileMagic, "MAGIC_NONE", INT2FIX(MAGIC_NONE));
149
+ #endif
150
+ #ifdef MAGIC_DEBUG
151
+ rb_define_const(cFileMagic, "MAGIC_DEBUG", INT2FIX(MAGIC_DEBUG));
152
+ #endif
153
+ #ifdef MAGIC_SYMLINK
154
+ rb_define_const(cFileMagic, "MAGIC_SYMLINK", INT2FIX(MAGIC_SYMLINK));
155
+ #endif
156
+ #ifdef MAGIC_COMPRESS
157
+ rb_define_const(cFileMagic, "MAGIC_COMPRESS", INT2FIX(MAGIC_COMPRESS));
158
+ #endif
159
+ #ifdef MAGIC_DEVICES
160
+ rb_define_const(cFileMagic, "MAGIC_DEVICES", INT2FIX(MAGIC_DEVICES));
161
+ #endif
162
+ #ifdef MAGIC_MIME_TYPE
163
+ rb_define_const(cFileMagic, "MAGIC_MIME_TYPE", INT2FIX(MAGIC_MIME_TYPE));
164
+ #endif
165
+ #ifdef MAGIC_CONTINUE
166
+ rb_define_const(cFileMagic, "MAGIC_CONTINUE", INT2FIX(MAGIC_CONTINUE));
167
+ #endif
168
+ #ifdef MAGIC_CHECK
169
+ rb_define_const(cFileMagic, "MAGIC_CHECK", INT2FIX(MAGIC_CHECK));
170
+ #endif
171
+ #ifdef MAGIC_PRESERVE_ATIME
172
+ rb_define_const(cFileMagic, "MAGIC_PRESERVE_ATIME", INT2FIX(MAGIC_PRESERVE_ATIME));
173
+ #endif
174
+ #ifdef MAGIC_RAW
175
+ rb_define_const(cFileMagic, "MAGIC_RAW", INT2FIX(MAGIC_RAW));
176
+ #endif
177
+ #ifdef MAGIC_ERROR
178
+ rb_define_const(cFileMagic, "MAGIC_ERROR", INT2FIX(MAGIC_ERROR));
179
+ #endif
180
+ #ifdef MAGIC_MIME_ENCODING
181
+ rb_define_const(cFileMagic, "MAGIC_MIME_ENCODING", INT2FIX(MAGIC_MIME_ENCODING));
182
+ #endif
183
+ #ifdef MAGIC_MIME
184
+ rb_define_const(cFileMagic, "MAGIC_MIME", INT2FIX(MAGIC_MIME));
185
+ #endif
186
+ #ifdef MAGIC_NO_CHECK_COMPRESS
187
+ rb_define_const(cFileMagic, "MAGIC_NO_CHECK_COMPRESS", INT2FIX(MAGIC_NO_CHECK_COMPRESS));
188
+ #endif
189
+ #ifdef MAGIC_NO_CHECK_TAR
190
+ rb_define_const(cFileMagic, "MAGIC_NO_CHECK_TAR", INT2FIX(MAGIC_NO_CHECK_TAR));
191
+ #endif
192
+ #ifdef MAGIC_NO_CHECK_SOFT
193
+ rb_define_const(cFileMagic, "MAGIC_NO_CHECK_SOFT", INT2FIX(MAGIC_NO_CHECK_SOFT));
194
+ #endif
195
+ #ifdef MAGIC_NO_CHECK_APPTYPE
196
+ rb_define_const(cFileMagic, "MAGIC_NO_CHECK_APPTYPE", INT2FIX(MAGIC_NO_CHECK_APPTYPE));
197
+ #endif
198
+ #ifdef MAGIC_NO_CHECK_ELF
199
+ rb_define_const(cFileMagic, "MAGIC_NO_CHECK_ELF", INT2FIX(MAGIC_NO_CHECK_ELF));
200
+ #endif
201
+ #ifdef MAGIC_NO_CHECK_ASCII
202
+ rb_define_const(cFileMagic, "MAGIC_NO_CHECK_ASCII", INT2FIX(MAGIC_NO_CHECK_ASCII));
203
+ #endif
204
+ #ifdef MAGIC_NO_CHECK_TROFF
205
+ rb_define_const(cFileMagic, "MAGIC_NO_CHECK_TROFF", INT2FIX(MAGIC_NO_CHECK_TROFF));
206
+ #endif
207
+ #ifdef MAGIC_NO_CHECK_TOKENS
208
+ rb_define_const(cFileMagic, "MAGIC_NO_CHECK_TOKENS", INT2FIX(MAGIC_NO_CHECK_TOKENS));
209
+ #endif
210
+ #ifdef MAGIC_NO_CHECK_FORTRAN
211
+ rb_define_const(cFileMagic, "MAGIC_NO_CHECK_FORTRAN", INT2FIX(MAGIC_NO_CHECK_FORTRAN));
212
+ #endif
213
+ }
@@ -0,0 +1,28 @@
1
+ #! /usr/bin/ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require 'filemagic'
5
+
6
+ puts FileMagic.new.flags
7
+
8
+ FileMagic.open(:mime) { |fm|
9
+ puts fm.flags
10
+ puts fm.file(__FILE__)
11
+
12
+ fm.setflags(:raw, :continue)
13
+ puts fm.flags
14
+ }
15
+
16
+ fm = FileMagic.new
17
+ puts fm.flags
18
+
19
+ mime = FileMagic.mime
20
+ puts mime.flags
21
+
22
+ ARGV.each { |file|
23
+ puts fm.file(file)
24
+ puts fm.file(file, true)
25
+
26
+ puts mime.file(file)
27
+ puts mime.file(file, true)
28
+ }
@@ -0,0 +1,36 @@
1
+ =begin
2
+
3
+ = FileMagic extension module SEE ALSO libmagic(3), file(1) and magic(4)
4
+ == FileMagic
5
+ === Constants
6
+ : MAGIC_NONE
7
+ No flags
8
+ : MAGIC_DEBUG
9
+ Turn on debuggin
10
+ : MAGIC_SYMLINK
11
+ Follow symlinks
12
+ : MAGIC_COMPRESS
13
+ Check inside compressed files
14
+ : MAGIC_DEVICES
15
+ Look at the contents of devices
16
+ : MAGIC_MIME
17
+ Return a mime string
18
+ : MAGIC_CONTINUE
19
+ Return all matches, not just the first
20
+ : MAGIC_CHECK
21
+ Print warnings to stderr
22
+
23
+ === Methods
24
+ : file(filename)
25
+ returns a textual description of the contents of the filename argument
26
+ : buffer(string)
27
+ returns a textual description of the contents of the string argument
28
+ : check(filename)
29
+ checks the validity of entries in the colon separated database files
30
+ passed in as filename
31
+ : compile(filename)
32
+ compile the the colon separated list of database files passed in as
33
+ filename
34
+ : close()
35
+ closes the magic database and frees any memory allocated. if memory
36
+ is a concern, use this.
@@ -0,0 +1,177 @@
1
+ require 'filemagic.so'
2
+
3
+ class FileMagic
4
+
5
+ # Map abbreviated flag names to their values (:name => Constant).
6
+ MAGIC_FLAGS = [
7
+ :none, # No flags
8
+ :debug, # Turn on debugging
9
+ :symlink, # Follow symlinks
10
+ :compress, # Check inside compressed files
11
+ :devices, # Look at the contents of devices
12
+ :mime_type, # Return only the MIME type
13
+ :continue, # Return all matches
14
+ :check, # Print warnings to stderr
15
+ :preserve_atime, # Restore access time on exit
16
+ :raw, # Don't translate unprint chars
17
+ :error, # Handle ENOENT etc as real errors
18
+ :mime_encoding, # Return only the MIME encoding
19
+ :mime, # MAGIC_MIME_TYPE | MAGIC_MIME_ENCODING
20
+ :no_check_compress, # Don't check for compressed files
21
+ :no_check_tar, # Don't check for tar files
22
+ :no_check_soft, # Don't check magic entries
23
+ :no_check_apptype, # Don't check application type
24
+ :no_check_elf, # Don't check for elf details
25
+ :no_check_ascii, # Don't check for ascii files
26
+ :no_check_troff, # Don't check ascii/troff
27
+ :no_check_tokens, # Don't check ascii/tokens
28
+ :no_check_fortran # Don't check ascii/fortran
29
+ ].inject({}) { |flags, flag|
30
+ const = "MAGIC_#{flag.to_s.upcase}"
31
+ flags.update(flag => const_defined?(const) && const_get(const))
32
+ }
33
+
34
+ attr_reader :flags
35
+ attr_writer :simplified
36
+
37
+ @fm = Hash.new { |fm, flags|
38
+ fm.has_key?(key = flags.to_s) ? fm[key] : fm[key] = new(*flags)
39
+ }
40
+
41
+ class << self
42
+
43
+ # Provide a "magic singleton" ;-)
44
+ def fm(*flags)
45
+ @fm.delete(flags.to_s) if @fm[flags].closed?
46
+ @fm[flags]
47
+ end
48
+
49
+ # Clear our instance cache.
50
+ def clear!
51
+ @fm.each_value { |fm| fm.close }
52
+ @fm.clear
53
+ end
54
+
55
+ # Allow shorter names for flags; now also takes options.
56
+ def new(*flags)
57
+ warn "warning: FileMagic::new() does not take block; use FileMagic::open() instead" if block_given?
58
+
59
+ options = flags.last.is_a?(Hash) ? flags.pop : {}
60
+
61
+ fm = fm_new(build_flags(*flags))
62
+
63
+ options.each { |option, value|
64
+ if fm.respond_to?(method = "#{option}=")
65
+ fm.send(method, value)
66
+ else
67
+ raise ArgumentError, "illegal option: #{option.inspect}"
68
+ end
69
+ }
70
+
71
+ fm
72
+ end
73
+
74
+ # Just like #new, but takes an optional block, in which case #close is called at the end.
75
+ def open(*flags)
76
+ fm = new(*flags)
77
+
78
+ if block_given?
79
+ begin
80
+ yield fm
81
+ ensure
82
+ fm.close
83
+ end
84
+ end
85
+
86
+ fm
87
+ end
88
+
89
+ # Just a short-cut ;-)
90
+ def mime(*flags, &block)
91
+ open(:mime, *flags, &block)
92
+ end
93
+
94
+ # Build the actual flags from the named flags passed as arguments.
95
+ def build_flags(*flags)
96
+ _flags = *flags
97
+
98
+ unless _flags.is_a?(Integer)
99
+ _flags = MAGIC_NONE
100
+
101
+ flags.flatten.each { |flag|
102
+ if value = flag.is_a?(Integer) ? flag : MAGIC_FLAGS[flag.to_sym]
103
+ _flags |= value
104
+ else
105
+ raise ArgumentError, "#{value.nil? ? 'no such flag' : 'flag not available'}: #{flag}"
106
+ end
107
+ }
108
+ end
109
+
110
+ _flags
111
+ end
112
+
113
+ end
114
+
115
+ # The actual processing happens in #new.
116
+ def initialize(*flags)
117
+ fm_initialize(*flags)
118
+
119
+ @flags = *flags
120
+ @closed = false
121
+ end
122
+
123
+ def close
124
+ return if closed?
125
+
126
+ fm_close
127
+ @closed = true
128
+ end
129
+
130
+ # Optionally cut off additional information after mime-type.
131
+ def file(file, simplified = simplified?)
132
+ simplify_mime(fm_file(file), simplified)
133
+ end
134
+
135
+ # Optionally cut off additional information after mime-type.
136
+ def buffer(buffer, simplified = simplified?)
137
+ simplify_mime(fm_buffer(buffer), simplified)
138
+ end
139
+
140
+ def setflags(*flags)
141
+ previous_flags, @flags = @flags, self.class.build_flags(*flags)
142
+ fm_setflags(@flags)
143
+
144
+ previous_flags
145
+ end
146
+ alias_method :flags=, :setflags
147
+
148
+ def check(file = "\0")
149
+ fm_check(file)
150
+ end
151
+ alias_method :valid?, :check
152
+
153
+ def compile(file)
154
+ fm_compile(file)
155
+ end
156
+
157
+ def simplified?
158
+ @simplified
159
+ end
160
+
161
+ def closed?
162
+ @closed
163
+ end
164
+
165
+ def inspect
166
+ str = super
167
+ str.insert(-2, ' (closed)') if closed?
168
+ str
169
+ end
170
+
171
+ private
172
+
173
+ def simplify_mime(mime, simplified = true)
174
+ simplified ? mime[/([\w\/-]+)/, 1].downcase : mime
175
+ end
176
+
177
+ end
@@ -0,0 +1,95 @@
1
+ require 'filemagic'
2
+
3
+ module FileMagic::Ext
4
+
5
+ module ClassMethods
6
+
7
+ def file_type(file, *flags)
8
+ raise NotImplementedError, 'must be implemented by including class'
9
+ end
10
+
11
+ def file(file, *flags)
12
+ file_type(file, *flags)
13
+ end
14
+
15
+ def mime_type(file, *flags)
16
+ flags.unshift :mime
17
+ file_type(file, *flags)
18
+ end
19
+ alias_method :mime, :mime_type
20
+
21
+ def content_type(file, *flags)
22
+ flags << { :simplified => true }
23
+ mime_type(file, *flags)
24
+ end
25
+
26
+ end
27
+
28
+ module InstanceMethods
29
+
30
+ def file_type(*flags)
31
+ self.class.file_type(self, *flags)
32
+ end
33
+ alias_method :file, :file_type
34
+
35
+ def mime_type(*flags)
36
+ self.class.mime_type(self, *flags)
37
+ end
38
+ alias_method :mime, :mime_type
39
+
40
+ def content_type(*flags)
41
+ self.class.content_type(self, *flags)
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+
48
+ class File
49
+
50
+ include FileMagic::Ext::InstanceMethods
51
+ extend FileMagic::Ext::ClassMethods
52
+
53
+ def self.file_type(file, *flags)
54
+ FileMagic.fm(*flags).file(file.respond_to?(:path) ? file.path : file)
55
+ rescue FileMagic::FileMagicError
56
+ nil
57
+ end
58
+
59
+ end
60
+
61
+ class String
62
+
63
+ include FileMagic::Ext::InstanceMethods
64
+ extend FileMagic::Ext::ClassMethods
65
+
66
+ def self.file_type(string, *flags)
67
+ FileMagic.fm(*flags).buffer(string)
68
+ rescue FileMagic::FileMagicError
69
+ nil
70
+ end
71
+
72
+ end
73
+
74
+ if $0 == __FILE__
75
+ f = __FILE__
76
+ p f
77
+
78
+ p File.file_type(f)
79
+ p File.mime_type(f)
80
+ p File.content_type(f)
81
+
82
+ f = File.new(f)
83
+ p f
84
+
85
+ p f.file_type
86
+ p f.mime_type
87
+ p f.content_type
88
+
89
+ s = '#! /usr/bin/ruby'
90
+ p s
91
+
92
+ p s.file_type
93
+ p s.mime_type
94
+ p s.content_type
95
+ end
@@ -0,0 +1,27 @@
1
+ class FileMagic
2
+
3
+ module Version
4
+
5
+ MAJOR = 0
6
+ MINOR = 2
7
+ TINY = 1
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,124 @@
1
+ require 'test/unit'
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ require 'filemagic'
5
+
6
+ class TestFileMagic < Test::Unit::TestCase
7
+
8
+ def test_file
9
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
10
+
11
+ res = fm.file(path_to('pyfile'))
12
+ assert_equal('a python script text executable', res)
13
+
14
+ if File.symlink?(path_to('pylink'))
15
+ res = fm.file(path_to('pylink'))
16
+ assert_equal("symbolic link to `pyfile'", res)
17
+ end
18
+
19
+ fm.close
20
+ fm = FileMagic.new(FileMagic::MAGIC_SYMLINK)
21
+
22
+ res = fm.file(path_to('pylink'))
23
+ assert_equal('a python script text executable', res)
24
+
25
+ fm.close
26
+ fm = FileMagic.new(FileMagic::MAGIC_SYMLINK | FileMagic::MAGIC_MIME)
27
+
28
+ res = fm.file(path_to('pylink'))
29
+ assert_equal('text/plain; charset=us-ascii', res)
30
+
31
+ fm.close
32
+ fm = FileMagic.new(FileMagic::MAGIC_COMPRESS)
33
+
34
+ res = fm.file(path_to('pyfile-compressed.gz'))
35
+ assert_match(/^a python script text executable \(gzip compressed data, was "pyfile-compressed", from Unix/, res)
36
+
37
+ fm.close
38
+ end
39
+
40
+ def test_buffer
41
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
42
+ res = fm.buffer("#!/bin/sh\n")
43
+ fm.close
44
+ assert_match(/shell script text executable$/, res)
45
+ end
46
+
47
+ def test_check
48
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
49
+ res = fm.check(path_to('perl'))
50
+ fm.close
51
+ assert_equal(0, res)
52
+ end
53
+
54
+ def test_compile
55
+ assert(File.writable?('.'), "can't write to current directory")
56
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
57
+ res = fm.compile(path_to('perl'))
58
+ fm.close
59
+ assert_equal(0, res)
60
+ File.unlink(path_to('perl.mgc', '.'))
61
+ end
62
+
63
+ def test_block
64
+ block_fm = FileMagic.open(FileMagic::MAGIC_NONE) { |fm|
65
+ res = fm.file(path_to('pyfile'))
66
+ assert_equal('a python script text executable', res)
67
+ }
68
+ assert block_fm.closed?
69
+ end
70
+
71
+ def test_setflags
72
+ fm = FileMagic.new(FileMagic::MAGIC_NONE)
73
+ assert_equal(FileMagic::MAGIC_NONE, fm.flags)
74
+ fm.setflags(FileMagic::MAGIC_SYMLINK)
75
+ assert_equal(FileMagic::MAGIC_SYMLINK, fm.flags)
76
+ fm.close
77
+ end
78
+
79
+ def test_abbr
80
+ fm = FileMagic.new(:mime, :continue)
81
+ assert_equal(FileMagic::MAGIC_MIME | FileMagic::MAGIC_CONTINUE, fm.flags)
82
+ fm.setflags(:symlink)
83
+ assert_equal(FileMagic::MAGIC_SYMLINK, fm.flags)
84
+ fm.close
85
+ end
86
+
87
+ # tests adapted from mahoro:
88
+
89
+ def test_mahoro_file
90
+ fm = FileMagic.new
91
+ fm.flags = FileMagic::MAGIC_NONE
92
+ assert_equal('ASCII C program text', fm.file(path_to('mahoro.c')))
93
+ end
94
+
95
+ def test_mahoro_mime_file
96
+ fm = FileMagic.new
97
+ fm.flags = FileMagic::MAGIC_MIME
98
+ assert_equal('text/x-c; charset=us-ascii', fm.file(path_to('mahoro.c')))
99
+ end
100
+
101
+ def test_mahoro_buffer
102
+ fm = FileMagic.new
103
+ fm.flags = FileMagic::MAGIC_NONE
104
+ assert_equal('ASCII C program text', fm.buffer(File.read(path_to('mahoro.c'))))
105
+ end
106
+
107
+ def test_mahoro_mime_buffer
108
+ fm = FileMagic.new
109
+ fm.flags = FileMagic::MAGIC_MIME
110
+ assert_equal('text/x-c; charset=us-ascii', fm.buffer(File.read(path_to('mahoro.c'))))
111
+ end
112
+
113
+ def test_mahoro_valid
114
+ fm = FileMagic.new
115
+ assert(fm.valid?, 'Default database was not valid.')
116
+ end
117
+
118
+ # utility methods:
119
+
120
+ def path_to(file, dir = File.dirname(__FILE__))
121
+ File.join(dir, file)
122
+ end
123
+
124
+ end
@@ -0,0 +1,16 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require 'filemagic'
3
+
4
+ warn "watch -n 1 'ps aux | grep [l]eaktest'"
5
+
6
+ def do_file(filename)
7
+ fm = FileMagic.new(0)
8
+ file = fm.file(filename)
9
+ fm.close
10
+ return file
11
+ end
12
+
13
+ loop do
14
+ puts do_file($0)
15
+ sleep 1
16
+ end
@@ -0,0 +1,187 @@
1
+ /*
2
+ * This file is Public Domain.
3
+ */
4
+
5
+ #include <ruby.h>
6
+ #include <magic.h>
7
+
8
+ struct MagicCookie
9
+ {
10
+ magic_t cookie;
11
+ };
12
+
13
+ static VALUE cMahoro;
14
+ static VALUE eMahoroError;
15
+
16
+ static void
17
+ mahoro_free(ptr)
18
+ struct MagicCookie *ptr;
19
+ {
20
+ magic_close(ptr->cookie);
21
+ free(ptr);
22
+ }
23
+
24
+ static VALUE
25
+ mahoro_allocate(klass)
26
+ VALUE klass;
27
+ {
28
+ return Data_Wrap_Struct(klass, 0, mahoro_free, 0);
29
+ }
30
+
31
+ static VALUE
32
+ mahoro_initialize(argc, argv, self)
33
+ int argc;
34
+ VALUE *argv, self;
35
+ {
36
+ int flags = MAGIC_NONE;
37
+ char *path = 0;
38
+ struct MagicCookie *ptr;
39
+ magic_t cookie;
40
+ VALUE vpath, vflags;
41
+
42
+ switch(rb_scan_args(argc, argv, "02", &vflags, &vpath)) {
43
+ case 2:
44
+ if(!NIL_P(vpath)) {
45
+ path = StringValuePtr(vpath);
46
+ }
47
+ /* fallthrough */
48
+ case 1:
49
+ flags = FIX2INT(vflags);
50
+ break;
51
+ }
52
+
53
+ if(!(cookie = magic_open(flags))) {
54
+ rb_raise(eMahoroError, "failed to initialize magic cookie");
55
+ }
56
+
57
+ if(magic_load(cookie, path)) {
58
+ rb_raise(eMahoroError, "failed to load database: %s",
59
+ magic_error(cookie));
60
+ }
61
+
62
+ ptr = ALLOC(struct MagicCookie);
63
+ ptr->cookie = cookie;
64
+ DATA_PTR(self) = ptr;
65
+
66
+ return self;
67
+ }
68
+
69
+ static VALUE
70
+ mahoro_file(self, path)
71
+ VALUE self, path;
72
+ {
73
+ const char *msg;
74
+ magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
75
+
76
+ if(!(msg = magic_file(cookie, StringValuePtr(path)))) {
77
+ rb_raise(eMahoroError, "failed lookup: %s", magic_error(cookie));
78
+ }
79
+
80
+ return rb_str_new2(msg);
81
+ }
82
+
83
+ static VALUE
84
+ mahoro_buffer(self, input)
85
+ VALUE self, input;
86
+ {
87
+ const char *msg;
88
+ magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
89
+
90
+ if(!(msg = magic_buffer(cookie, StringValuePtr(input),
91
+ RSTRING(StringValue(input))->len))) {
92
+ rb_raise(eMahoroError, "failed lookup: %s", magic_error(cookie));
93
+ }
94
+
95
+ return rb_str_new2(msg);
96
+ }
97
+
98
+ static VALUE
99
+ mahoro_set_flags(self, flags)
100
+ VALUE self, flags;
101
+ {
102
+ magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
103
+
104
+ return INT2FIX(magic_setflags(cookie, FIX2INT(flags)));
105
+ }
106
+
107
+ static VALUE
108
+ mahoro_check(argc, argv, self)
109
+ int argc;
110
+ VALUE *argv, self;
111
+ {
112
+ char *path = 0;
113
+ VALUE vpath;
114
+ magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
115
+
116
+ switch(rb_scan_args(argc, argv, "01", &vpath)) {
117
+ case 1:
118
+ if(!NIL_P(vpath)) {
119
+ path = StringValuePtr(vpath);
120
+ }
121
+ break;
122
+ }
123
+
124
+ if(!magic_check(cookie, path)) {
125
+ return Qtrue;
126
+ } else {
127
+ return Qfalse;
128
+ }
129
+ }
130
+
131
+ static VALUE
132
+ mahoro_compile(klass, path)
133
+ VALUE klass, path;
134
+ {
135
+ magic_t cookie = magic_open(MAGIC_NONE);
136
+
137
+ if(magic_compile(cookie, StringValuePtr(path))) {
138
+ rb_raise(eMahoroError, "failed compile: %s", magic_error(cookie));
139
+ }
140
+
141
+ magic_close(cookie);
142
+
143
+ return Qtrue;
144
+ }
145
+
146
+ static VALUE
147
+ mahoro_load(self, path)
148
+ VALUE self, path;
149
+ {
150
+ magic_t cookie = ((struct MagicCookie *) DATA_PTR(self))->cookie;
151
+
152
+ if(magic_load(cookie, StringValuePtr(path))) {
153
+ rb_raise(eMahoroError, "failed load: %s", magic_error(cookie));
154
+ }
155
+
156
+ return self;
157
+ }
158
+
159
+ void Init_mahoro(void)
160
+ {
161
+ cMahoro = rb_define_class("Mahoro", rb_cObject);
162
+ eMahoroError = rb_define_class_under(cMahoro, "Error", rb_eStandardError);
163
+
164
+ rb_const_set(cMahoro, rb_intern("NONE"), INT2FIX(MAGIC_NONE));
165
+ rb_const_set(cMahoro, rb_intern("DEBUG"), INT2FIX(MAGIC_DEBUG));
166
+ rb_const_set(cMahoro, rb_intern("SYMLINK"), INT2FIX(MAGIC_SYMLINK));
167
+ rb_const_set(cMahoro, rb_intern("COMPRESS"), INT2FIX(MAGIC_COMPRESS));
168
+ rb_const_set(cMahoro, rb_intern("DEVICES"), INT2FIX(MAGIC_DEVICES));
169
+ rb_const_set(cMahoro, rb_intern("MIME"), INT2FIX(MAGIC_MIME));
170
+ rb_const_set(cMahoro, rb_intern("CONTINUE"), INT2FIX(MAGIC_CONTINUE));
171
+ rb_const_set(cMahoro, rb_intern("CHECK"), INT2FIX(MAGIC_CHECK));
172
+ rb_const_set(cMahoro, rb_intern("PRESERVE_ATIME"),
173
+ INT2FIX(MAGIC_PRESERVE_ATIME));
174
+ rb_const_set(cMahoro, rb_intern("RAW"), INT2FIX(MAGIC_RAW));
175
+ rb_const_set(cMahoro, rb_intern("ERROR"), INT2FIX(MAGIC_ERROR));
176
+
177
+ rb_define_alloc_func(cMahoro, mahoro_allocate);
178
+ rb_define_method(cMahoro, "initialize", mahoro_initialize, -1);
179
+ rb_define_method(cMahoro, "file", mahoro_file, 1);
180
+ rb_define_method(cMahoro, "buffer", mahoro_buffer, 1);
181
+ rb_define_method(cMahoro, "flags=", mahoro_set_flags, 1);
182
+ rb_define_method(cMahoro, "valid?", mahoro_check, -1);
183
+ rb_define_singleton_method(cMahoro, "compile", mahoro_compile, 1);
184
+ rb_define_method(cMahoro, "load", mahoro_load, 1);
185
+ }
186
+
187
+ /* arch-tag: mahoro */
@@ -0,0 +1,19 @@
1
+
2
+ #------------------------------------------------------------------------------
3
+ # perl: file(1) magic for Larry Wall's perl language.
4
+ #
5
+ # The ``eval'' line recognizes an outrageously clever hack for USG systems.
6
+ # Keith Waclena <keith@cerberus.uchicago.edu>
7
+ # Send additions to <perl5-porters@perl.org>
8
+ 0 string/b #!\ /bin/perl perl script text executable
9
+ 0 string eval\ "exec\ /bin/perl perl script text
10
+ 0 string/b #!\ /usr/bin/perl perl script text executable
11
+ 0 string eval\ "exec\ /usr/bin/perl perl script text
12
+ 0 string/b #!\ /usr/local/bin/perl perl script text
13
+ 0 string eval\ "exec\ /usr/local/bin/perl perl script text executable
14
+ 0 string eval\ '(exit\ $?0)'\ &&\ eval\ 'exec perl script text
15
+
16
+ # a couple more, by me
17
+ # XXX: christos matches
18
+ #0 regex package Perl5 module source text (via regex)
19
+ 0 string package Perl5 module source text
@@ -0,0 +1 @@
1
+ """
Binary file
@@ -0,0 +1 @@
1
+ """
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-filemagic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Travis Whitton
8
+ - Jens Wille
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2008-09-18 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Ruby bindings to the magic(4) library
18
+ email:
19
+ - tinymountain@gmail.com
20
+ - jens.wille@uni-koeln.de
21
+ executables: []
22
+
23
+ extensions:
24
+ - ext/extconf.rb
25
+ extra_rdoc_files:
26
+ - README
27
+ files:
28
+ - lib/filemagic/ext.rb
29
+ - lib/filemagic/version.rb
30
+ - lib/filemagic.rb
31
+ - ext/filemagic.c
32
+ - test/pyfile
33
+ - test/pyfile-compressed.gz
34
+ - test/perl
35
+ - test/leaktest.rb
36
+ - test/mahoro.c
37
+ - test/filemagic_test.rb
38
+ - test/pylink
39
+ - README
40
+ - CHANGELOG
41
+ - TODO
42
+ - Rakefile
43
+ - info/filemagic.rd
44
+ - info/example.rb
45
+ has_rdoc: true
46
+ homepage: http://ruby-filemagic.rubyforge.org/
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --line-numbers
50
+ - --main
51
+ - README
52
+ - --all
53
+ - --inline-source
54
+ - --title
55
+ - ruby-filemagic Application documentation
56
+ - --charset
57
+ - UTF-8
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project: ruby-filemagic
75
+ rubygems_version: 1.2.0
76
+ signing_key:
77
+ specification_version: 2
78
+ summary: Ruby bindings to the magic(4) library
79
+ test_files: []
80
+