ruby-filemagic 0.3.0 → 0.4.0
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.
- data/CHANGELOG +34 -13
- data/README +2 -6
- data/Rakefile +1 -1
- data/TODO +7 -8
- data/ext/extconf.rb +4 -3
- data/ext/filemagic.c +255 -101
- data/ext/filemagic.h +48 -0
- data/lib/filemagic.rb +17 -119
- data/lib/filemagic/ext.rb +3 -0
- data/lib/filemagic/version.rb +1 -1
- data/test/filemagic_test.rb +23 -6
- metadata +5 -4
data/CHANGELOG
CHANGED
@@ -1,28 +1,49 @@
|
|
1
1
|
--------------------------------------------------------------------------------
|
2
2
|
7/28/2003 version 0.1.0
|
3
3
|
|
4
|
-
|
4
|
+
* Initial release.
|
5
5
|
|
6
6
|
--------------------------------------------------------------------------------
|
7
7
|
7/30/2003 version 0.1.1
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
* Added manual close method
|
10
|
+
* Added unit test suite
|
11
11
|
|
12
12
|
--------------------------------------------------------------------------------
|
13
13
|
9/12/2008 version 0.2.0
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
* Modified C API
|
16
|
+
* Uniform C function prefix rb_magic_ (instead of magick_)
|
17
|
+
* Uniform Ruby method prefix fm_ (instead of none)
|
18
|
+
* More magic(4) constants (if available)
|
19
|
+
* Added Ruby wrapper for more rubyish interface
|
20
|
+
* Added extensions for File and String core classes
|
21
|
+
* Added/updated project files
|
22
|
+
* Now available as a Rubygem!
|
23
23
|
|
24
24
|
--------------------------------------------------------------------------------
|
25
25
|
9/18/2008 version 0.2.1
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
* Added mahoro source file and tests for reference and inspiration
|
28
|
+
* We have a Rubyforge project now! :-)
|
29
|
+
|
30
|
+
--------------------------------------------------------------------------------
|
31
|
+
3/2/2010 version 0.2.2
|
32
|
+
|
33
|
+
* Allow '.' when abbreviating mime types (Eric Schwartz)
|
34
|
+
* Cleanup and project file fixes
|
35
|
+
|
36
|
+
--------------------------------------------------------------------------------
|
37
|
+
9/10/2010 version 0.3.0
|
38
|
+
|
39
|
+
* Ruby 1.9.2 compatibility (Martin Carpenter)
|
40
|
+
* Exposed flags as symbols (Martin Carpenter)
|
41
|
+
|
42
|
+
--------------------------------------------------------------------------------
|
43
|
+
9/14/2010 version 0.4.0
|
44
|
+
|
45
|
+
* Brushed up C layer
|
46
|
+
* Moved most of the Ruby stuff to C
|
47
|
+
* No longer expose internal state (@closed, @flags)
|
48
|
+
* No longer expose internal C methods (fm_*)
|
49
|
+
* Updated for magic(4) version 5.04
|
data/README
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
== VERSION
|
4
4
|
|
5
|
-
This documentation refers to filemagic version 0.
|
5
|
+
This documentation refers to filemagic version 0.4.0
|
6
6
|
|
7
7
|
|
8
8
|
== DESCRIPTION
|
@@ -15,14 +15,10 @@ Similar to Ricardo[http://github.com/ricardochimal/ruby-filemagic]
|
|
15
15
|
I wanted this project to make some progress. My needs went a bit
|
16
16
|
farther than his, though ;-) Enjoy anyway!
|
17
17
|
|
18
|
-
Install the gem
|
18
|
+
Install the gem:
|
19
19
|
|
20
20
|
sudo gem install ruby-filemagic
|
21
21
|
|
22
|
-
or from Github[http://github.com]:
|
23
|
-
|
24
|
-
sudo gem install blackwinter-ruby-filemagic --source http://gems.github.com
|
25
|
-
|
26
22
|
=== Original package
|
27
23
|
|
28
24
|
July 28, 2003 Travis Whitton <tinymountain@gmail.com>
|
data/Rakefile
CHANGED
@@ -16,7 +16,7 @@ begin
|
|
16
16
|
:authors => ['Travis Whitton', 'Jens Wille'],
|
17
17
|
:email => ['tinymountain@gmail.com', 'jens.wille@uni-koeln.de'],
|
18
18
|
:homepage => 'http://ruby-filemagic.rubyforge.org/',
|
19
|
-
:files => FileList['lib/**/*.rb', 'ext/**/*.
|
19
|
+
:files => FileList['lib/**/*.rb', 'ext/**/*.[ch]', 'test/*'].to_a,
|
20
20
|
:extensions => FileList['ext/**/extconf.rb'].to_a,
|
21
21
|
:extra_files => FileList['[A-Z]*', 'info/*'].to_a
|
22
22
|
}
|
data/TODO
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
o Refactor code into initialize instead of new
|
5
|
-
o [DONE?] Enable blocks for automatic cleanup:
|
1
|
+
* Find a better way to handle magic_load than just defaulting to NULL
|
2
|
+
* Find a way to make magic_check work on NULL
|
3
|
+
* Refactor code into initialize instead of new
|
6
4
|
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
* Expose magic(4) version (how?)
|
6
|
+
* Properly document C methods
|
7
|
+
* Convert tests to RSpec
|
8
|
+
* Add Rake tasks
|
data/ext/extconf.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
|
-
dir_config(
|
4
|
-
|
5
|
-
|
3
|
+
dir_config('magic')
|
4
|
+
|
5
|
+
if have_library('magic', 'magic_open') and have_header('magic.h')
|
6
|
+
create_makefile('filemagic')
|
6
7
|
else
|
7
8
|
print "*** ERROR: missing required library to compile this module\n"
|
8
9
|
end
|
data/ext/filemagic.c
CHANGED
@@ -13,91 +13,161 @@
|
|
13
13
|
|
14
14
|
*********************************************************/
|
15
15
|
|
16
|
-
#include "
|
17
|
-
#include <magic.h>
|
16
|
+
#include "filemagic.h"
|
18
17
|
|
19
|
-
|
18
|
+
/* FileMagic.new */
|
19
|
+
static VALUE
|
20
|
+
rb_magic_new(int argc, VALUE *argv, VALUE class) {
|
21
|
+
VALUE obj, args[2];
|
22
|
+
magic_t cookie;
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
Data_Get_Struct(obj, struct magic_set, cookie);\
|
25
|
-
}
|
24
|
+
if (rb_block_given_p()) {
|
25
|
+
rb_warn("FileMagic::new() does not take block; use FileMagic::open() instead");
|
26
|
+
}
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
if (argc > 0 && TYPE(args[1] = argv[argc - 1]) == T_HASH) {
|
29
|
+
argc--;
|
30
|
+
}
|
31
|
+
else {
|
32
|
+
args[1] = rb_hash_new();
|
33
|
+
}
|
34
|
+
|
35
|
+
args[0] = rb_magic_flags_to_int(argc, argv);
|
36
|
+
if ((cookie = magic_open(NUM2INT(args[0]))) == NULL) {
|
37
|
+
rb_fatal("out of memory");
|
38
|
+
}
|
39
|
+
|
40
|
+
if (magic_load(cookie, NULL) == -1) {
|
41
|
+
rb_fatal("%s", magic_error(cookie));
|
42
|
+
}
|
43
|
+
|
44
|
+
obj = Data_Wrap_Struct(class, 0, rb_magic_free, cookie);
|
45
|
+
rb_obj_call_init(obj, 2, args);
|
46
|
+
|
47
|
+
return obj;
|
33
48
|
}
|
34
49
|
|
35
|
-
static VALUE
|
50
|
+
static VALUE
|
51
|
+
rb_magic_init(int argc, VALUE *argv, VALUE self) {
|
52
|
+
VALUE flags, options, keys, k, m;
|
53
|
+
ID mid;
|
54
|
+
int i;
|
55
|
+
|
56
|
+
if (rb_scan_args(argc, argv, "11", &flags, &options) == 1) {
|
57
|
+
options = rb_hash_new();
|
58
|
+
}
|
59
|
+
|
60
|
+
rb_iv_set(self, "_flags", flags);
|
61
|
+
rb_iv_set(self, "closed", Qfalse);
|
62
|
+
|
63
|
+
keys = rb_funcall(options, rb_intern("keys"), 0);
|
64
|
+
|
65
|
+
for (i = 0; i < RARRAY_LEN(keys); i++) {
|
66
|
+
k = rb_funcall(keys, rb_intern("[]"), 1, INT2FIX(i));
|
67
|
+
m = rb_funcall(rb_funcall(k, rb_intern("to_s"), 0),
|
68
|
+
rb_intern("+"), 1, rb_str_new2("=")
|
69
|
+
);
|
70
|
+
|
71
|
+
if (rb_respond_to(self, mid = rb_intern(StringValueCStr(m)))) {
|
72
|
+
rb_funcall(self, mid, 1, rb_hash_aref(options, k));
|
73
|
+
}
|
74
|
+
else {
|
75
|
+
k = rb_funcall(k, rb_intern("inspect"), 0);
|
76
|
+
rb_raise(rb_eArgError, "illegal option: %s", StringValueCStr(k));
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
36
80
|
return Qnil;
|
37
81
|
}
|
38
82
|
|
39
83
|
/* Frees resources allocated */
|
40
|
-
static VALUE
|
84
|
+
static VALUE
|
85
|
+
rb_magic_close(VALUE self) {
|
41
86
|
magic_t cookie;
|
42
87
|
|
88
|
+
if (RTEST(rb_magic_closed_p(self))) {
|
89
|
+
return Qnil;
|
90
|
+
}
|
91
|
+
|
43
92
|
GetMagicCookie(self, cookie);
|
44
93
|
magic_close(cookie);
|
45
94
|
|
46
95
|
/* This keeps rb_magic_free from trying to free closed objects */
|
47
96
|
RDATA(self)->data = NULL;
|
48
97
|
|
98
|
+
rb_iv_set(self, "closed", Qtrue);
|
99
|
+
|
49
100
|
return Qnil;
|
50
101
|
}
|
51
102
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
magic_t cookie;
|
56
|
-
|
57
|
-
cookie = magic_open(NUM2INT(flags));
|
58
|
-
if (cookie == NULL)
|
59
|
-
rb_fatal("out of memory");
|
60
|
-
if (magic_load(cookie, NULL) == -1)
|
61
|
-
rb_fatal("%s", magic_error(cookie));
|
62
|
-
|
63
|
-
obj = Data_Wrap_Struct(class, 0, rb_magic_free, cookie);
|
64
|
-
rb_obj_call_init(obj, 1, &flags);
|
65
|
-
|
66
|
-
return obj;
|
103
|
+
static VALUE
|
104
|
+
rb_magic_closed_p(VALUE self) {
|
105
|
+
return rb_attr_get(self, rb_intern("closed"));
|
67
106
|
}
|
68
107
|
|
69
108
|
/* Return a string describing file */
|
70
|
-
static VALUE
|
109
|
+
static VALUE
|
110
|
+
rb_magic_file(int argc, VALUE *argv, VALUE self) {
|
111
|
+
VALUE file, s;
|
71
112
|
const char *m;
|
72
113
|
magic_t cookie;
|
73
114
|
|
115
|
+
rb_scan_args(argc, argv, "11", &file, &s);
|
116
|
+
|
74
117
|
m = StringValuePtr(file);
|
75
118
|
GetMagicCookie(self, cookie);
|
76
|
-
if ((m = magic_file(cookie, m)) == NULL)
|
77
|
-
rb_raise(rb_FileMagicError, magic_error(cookie));
|
78
119
|
|
79
|
-
|
120
|
+
if ((m = magic_file(cookie, m)) == NULL) {
|
121
|
+
rb_raise(rb_FileMagicError, "%s", magic_error(cookie));
|
122
|
+
}
|
123
|
+
|
124
|
+
return rb_magic_apply_simple(self, m, s);
|
80
125
|
}
|
81
126
|
|
82
127
|
/* Return a string describing the string buffer */
|
83
|
-
static VALUE
|
84
|
-
|
128
|
+
static VALUE
|
129
|
+
rb_magic_buffer(int argc, VALUE *argv, VALUE self) {
|
130
|
+
VALUE buffer, s;
|
85
131
|
const char *m;
|
86
132
|
magic_t cookie;
|
87
133
|
|
134
|
+
rb_scan_args(argc, argv, "11", &buffer, &s);
|
135
|
+
|
88
136
|
m = StringValuePtr(buffer);
|
89
137
|
GetMagicCookie(self, cookie);
|
90
|
-
if ((m = magic_buffer(cookie, m, i)) == NULL)
|
91
|
-
rb_raise(rb_FileMagicError, magic_error(cookie));
|
92
138
|
|
93
|
-
|
139
|
+
if ((m = magic_buffer(cookie, m, RSTRING_LEN(buffer))) == NULL) {
|
140
|
+
rb_raise(rb_FileMagicError, "%s", magic_error(cookie));
|
141
|
+
}
|
142
|
+
|
143
|
+
return rb_magic_apply_simple(self, m, s);
|
144
|
+
}
|
145
|
+
|
146
|
+
/* Get the flags as array of symbols */
|
147
|
+
static VALUE
|
148
|
+
rb_magic_getflags(VALUE self) {
|
149
|
+
VALUE ary = rb_ary_new();
|
150
|
+
VALUE map = rb_const_get(cFileMagic, rb_intern("FLAGS_BY_INT"));
|
151
|
+
int i = NUM2INT(rb_attr_get(self, rb_intern("_flags"))), j = 0;
|
152
|
+
|
153
|
+
while ((i -= j) > 0) {
|
154
|
+
j = pow(2, (int)(log(i) / log(2)));
|
155
|
+
rb_ary_unshift(ary, rb_hash_aref(map, INT2FIX(j)));
|
156
|
+
}
|
157
|
+
|
158
|
+
return ary;
|
94
159
|
}
|
95
160
|
|
96
161
|
/* Set flags on the cookie object */
|
97
|
-
static VALUE
|
162
|
+
static VALUE
|
163
|
+
rb_magic_setflags(VALUE self, VALUE flags) {
|
98
164
|
int retval;
|
99
165
|
magic_t cookie;
|
100
166
|
|
167
|
+
flags = rb_Array(flags);
|
168
|
+
flags = rb_magic_flags_to_int(RARRAY_LEN(flags), RARRAY_PTR(flags));
|
169
|
+
rb_iv_set(self, "_flags", flags);
|
170
|
+
|
101
171
|
GetMagicCookie(self, cookie);
|
102
172
|
retval = magic_setflags(cookie, NUM2INT(flags));
|
103
173
|
|
@@ -105,20 +175,24 @@ static VALUE rb_magic_setflags(VALUE self, VALUE flags) {
|
|
105
175
|
}
|
106
176
|
|
107
177
|
/* Checks validity of a magic database file */
|
108
|
-
static VALUE
|
178
|
+
static VALUE
|
179
|
+
rb_magic_check(int argc, VALUE *argv, VALUE self) {
|
180
|
+
VALUE s;
|
181
|
+
const char *file;
|
109
182
|
int retval;
|
110
|
-
const char *m;
|
111
183
|
magic_t cookie;
|
112
184
|
|
185
|
+
file = rb_scan_args(argc, argv, "01", &s) == 1 ? StringValuePtr(s) : NULL;
|
186
|
+
|
113
187
|
GetMagicCookie(self, cookie);
|
114
|
-
|
115
|
-
retval = magic_check(cookie, m);
|
188
|
+
retval = magic_check(cookie, file);
|
116
189
|
|
117
190
|
return INT2FIX(retval);
|
118
191
|
}
|
119
192
|
|
120
193
|
/* Compiles a magic database file */
|
121
|
-
static VALUE
|
194
|
+
static VALUE
|
195
|
+
rb_magic_compile(VALUE self, VALUE file) {
|
122
196
|
int retval;
|
123
197
|
const char *m;
|
124
198
|
magic_t cookie;
|
@@ -130,85 +204,165 @@ static VALUE rb_magic_compile(VALUE self, VALUE file) {
|
|
130
204
|
return INT2FIX(retval);
|
131
205
|
}
|
132
206
|
|
133
|
-
|
207
|
+
static VALUE
|
208
|
+
rb_magic_flags_to_int(int argc, VALUE *argv) {
|
209
|
+
VALUE map = rb_const_get(cFileMagic, rb_intern("FLAGS_BY_SYM"));
|
210
|
+
VALUE f, g;
|
211
|
+
int i = MAGIC_NONE, j;
|
212
|
+
|
213
|
+
for (j = 0; j < argc; j++) {
|
214
|
+
f = argv[j];
|
215
|
+
|
216
|
+
switch (TYPE(f)) {
|
217
|
+
case T_SYMBOL:
|
218
|
+
if (RTEST(g = rb_hash_aref(map, f))) {
|
219
|
+
f = g;
|
220
|
+
/* fall through */
|
221
|
+
}
|
222
|
+
else {
|
223
|
+
f = rb_funcall(f, rb_intern("inspect"), 0);
|
224
|
+
rb_raise(rb_eArgError,
|
225
|
+
"%s: %s", NIL_P(g) ? "no such flag" : "flag not available",
|
226
|
+
StringValueCStr(f)
|
227
|
+
);
|
228
|
+
break;
|
229
|
+
}
|
230
|
+
case T_FIXNUM:
|
231
|
+
i |= NUM2INT(f);
|
232
|
+
break;
|
233
|
+
default:
|
234
|
+
rb_raise(rb_eTypeError,
|
235
|
+
"wrong argument type %s (expected Fixnum or Symbol)",
|
236
|
+
rb_obj_classname(f)
|
237
|
+
);
|
238
|
+
}
|
239
|
+
}
|
240
|
+
|
241
|
+
return INT2FIX(i);
|
242
|
+
}
|
243
|
+
|
244
|
+
static VALUE
|
245
|
+
rb_magic_apply_simple(VALUE self, const char *m, VALUE s) {
|
246
|
+
VALUE str = rb_str_new2(m);
|
247
|
+
|
248
|
+
if (RTEST(NIL_P(s) ? rb_attr_get(self, rb_intern("@simplified")) : s)) {
|
249
|
+
rb_funcall(str, rb_intern("downcase!"), 0);
|
250
|
+
|
251
|
+
return rb_funcall(str, rb_intern("slice"), 2,
|
252
|
+
rb_const_get(cFileMagic, rb_intern("SIMPLE_RE")),
|
253
|
+
INT2FIX(1)
|
254
|
+
);
|
255
|
+
}
|
256
|
+
else {
|
257
|
+
return str;
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
261
|
+
/*
|
262
|
+
GC never seems to happen until the program terminates, but this is called
|
263
|
+
on any unclosed objects
|
264
|
+
*/
|
265
|
+
static void
|
266
|
+
rb_magic_free(magic_t cookie) {
|
267
|
+
magic_close(cookie);
|
268
|
+
}
|
269
|
+
|
270
|
+
void
|
271
|
+
Init_filemagic() {
|
134
272
|
cFileMagic = rb_define_class("FileMagic", rb_cObject);
|
135
273
|
|
136
|
-
rb_define_singleton_method(cFileMagic, "
|
274
|
+
rb_define_singleton_method(cFileMagic, "new", rb_magic_new, -1);
|
137
275
|
|
138
|
-
rb_define_method(cFileMagic, "
|
139
|
-
rb_define_method(cFileMagic, "
|
140
|
-
rb_define_method(cFileMagic, "
|
141
|
-
rb_define_method(cFileMagic, "
|
142
|
-
rb_define_method(cFileMagic, "
|
143
|
-
rb_define_method(cFileMagic, "
|
144
|
-
rb_define_method(cFileMagic, "
|
276
|
+
rb_define_method(cFileMagic, "initialize", rb_magic_init, -1);
|
277
|
+
rb_define_method(cFileMagic, "close", rb_magic_close, 0);
|
278
|
+
rb_define_method(cFileMagic, "closed?", rb_magic_closed_p, 0);
|
279
|
+
rb_define_method(cFileMagic, "file", rb_magic_file, -1);
|
280
|
+
rb_define_method(cFileMagic, "buffer", rb_magic_buffer, -1);
|
281
|
+
rb_define_method(cFileMagic, "flags", rb_magic_getflags, 0);
|
282
|
+
rb_define_method(cFileMagic, "flags=", rb_magic_setflags, 1);
|
283
|
+
rb_define_method(cFileMagic, "check", rb_magic_check, -1);
|
284
|
+
rb_define_method(cFileMagic, "compile", rb_magic_compile, 1);
|
285
|
+
|
286
|
+
rb_alias(cFileMagic, rb_intern("valid?"), rb_intern("check"));
|
145
287
|
|
146
288
|
rb_FileMagicError = rb_define_class_under(cFileMagic, "FileMagicError", rb_eStandardError);
|
147
289
|
|
148
|
-
|
290
|
+
#ifdef MAGIC_NONE
|
149
291
|
rb_define_const(cFileMagic, "MAGIC_NONE", INT2FIX(MAGIC_NONE));
|
150
|
-
|
151
|
-
|
292
|
+
#endif
|
293
|
+
#ifdef MAGIC_DEBUG
|
152
294
|
rb_define_const(cFileMagic, "MAGIC_DEBUG", INT2FIX(MAGIC_DEBUG));
|
153
|
-
|
154
|
-
|
295
|
+
#endif
|
296
|
+
#ifdef MAGIC_SYMLINK
|
155
297
|
rb_define_const(cFileMagic, "MAGIC_SYMLINK", INT2FIX(MAGIC_SYMLINK));
|
156
|
-
|
157
|
-
|
298
|
+
#endif
|
299
|
+
#ifdef MAGIC_COMPRESS
|
158
300
|
rb_define_const(cFileMagic, "MAGIC_COMPRESS", INT2FIX(MAGIC_COMPRESS));
|
159
|
-
|
160
|
-
|
301
|
+
#endif
|
302
|
+
#ifdef MAGIC_DEVICES
|
161
303
|
rb_define_const(cFileMagic, "MAGIC_DEVICES", INT2FIX(MAGIC_DEVICES));
|
162
|
-
|
163
|
-
|
304
|
+
#endif
|
305
|
+
#ifdef MAGIC_MIME_TYPE
|
164
306
|
rb_define_const(cFileMagic, "MAGIC_MIME_TYPE", INT2FIX(MAGIC_MIME_TYPE));
|
165
|
-
|
166
|
-
|
307
|
+
#endif
|
308
|
+
#ifdef MAGIC_CONTINUE
|
167
309
|
rb_define_const(cFileMagic, "MAGIC_CONTINUE", INT2FIX(MAGIC_CONTINUE));
|
168
|
-
|
169
|
-
|
310
|
+
#endif
|
311
|
+
#ifdef MAGIC_CHECK
|
170
312
|
rb_define_const(cFileMagic, "MAGIC_CHECK", INT2FIX(MAGIC_CHECK));
|
171
|
-
|
172
|
-
|
313
|
+
#endif
|
314
|
+
#ifdef MAGIC_PRESERVE_ATIME
|
173
315
|
rb_define_const(cFileMagic, "MAGIC_PRESERVE_ATIME", INT2FIX(MAGIC_PRESERVE_ATIME));
|
174
|
-
|
175
|
-
|
316
|
+
#endif
|
317
|
+
#ifdef MAGIC_RAW
|
176
318
|
rb_define_const(cFileMagic, "MAGIC_RAW", INT2FIX(MAGIC_RAW));
|
177
|
-
|
178
|
-
|
319
|
+
#endif
|
320
|
+
#ifdef MAGIC_ERROR
|
179
321
|
rb_define_const(cFileMagic, "MAGIC_ERROR", INT2FIX(MAGIC_ERROR));
|
180
|
-
|
181
|
-
|
322
|
+
#endif
|
323
|
+
#ifdef MAGIC_MIME_ENCODING
|
182
324
|
rb_define_const(cFileMagic, "MAGIC_MIME_ENCODING", INT2FIX(MAGIC_MIME_ENCODING));
|
183
|
-
|
184
|
-
|
325
|
+
#endif
|
326
|
+
#ifdef MAGIC_MIME
|
185
327
|
rb_define_const(cFileMagic, "MAGIC_MIME", INT2FIX(MAGIC_MIME));
|
186
|
-
|
187
|
-
|
328
|
+
#endif
|
329
|
+
#ifdef MAGIC_APPLE
|
330
|
+
rb_define_const(cFileMagic, "MAGIC_APPLE", INT2FIX(MAGIC_APPLE));
|
331
|
+
#endif
|
332
|
+
#ifdef MAGIC_NO_CHECK_COMPRESS
|
188
333
|
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_COMPRESS", INT2FIX(MAGIC_NO_CHECK_COMPRESS));
|
189
|
-
|
190
|
-
|
334
|
+
#endif
|
335
|
+
#ifdef MAGIC_NO_CHECK_TAR
|
191
336
|
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_TAR", INT2FIX(MAGIC_NO_CHECK_TAR));
|
192
|
-
|
193
|
-
|
337
|
+
#endif
|
338
|
+
#ifdef MAGIC_NO_CHECK_SOFT
|
194
339
|
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_SOFT", INT2FIX(MAGIC_NO_CHECK_SOFT));
|
195
|
-
|
196
|
-
|
340
|
+
#endif
|
341
|
+
#ifdef MAGIC_NO_CHECK_APPTYPE
|
197
342
|
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_APPTYPE", INT2FIX(MAGIC_NO_CHECK_APPTYPE));
|
198
|
-
|
199
|
-
|
343
|
+
#endif
|
344
|
+
#ifdef MAGIC_NO_CHECK_ELF
|
200
345
|
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_ELF", INT2FIX(MAGIC_NO_CHECK_ELF));
|
201
|
-
|
202
|
-
|
203
|
-
rb_define_const(cFileMagic, "
|
204
|
-
|
205
|
-
|
206
|
-
rb_define_const(cFileMagic, "
|
207
|
-
|
208
|
-
|
346
|
+
#endif
|
347
|
+
#ifdef MAGIC_NO_CHECK_TEXT
|
348
|
+
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_TEXT", INT2FIX(MAGIC_NO_CHECK_TEXT));
|
349
|
+
#endif
|
350
|
+
#ifdef MAGIC_NO_CHECK_CDF
|
351
|
+
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_CDF", INT2FIX(MAGIC_NO_CHECK_CDF));
|
352
|
+
#endif
|
353
|
+
#ifdef MAGIC_NO_CHECK_TOKENS
|
209
354
|
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_TOKENS", INT2FIX(MAGIC_NO_CHECK_TOKENS));
|
210
|
-
|
211
|
-
|
355
|
+
#endif
|
356
|
+
#ifdef MAGIC_NO_CHECK_ENCODING
|
357
|
+
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_ENCODING", INT2FIX(MAGIC_NO_CHECK_ENCODING));
|
358
|
+
#endif
|
359
|
+
#ifdef MAGIC_NO_CHECK_ASCII
|
360
|
+
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_ASCII", INT2FIX(MAGIC_NO_CHECK_ASCII));
|
361
|
+
#endif
|
362
|
+
#ifdef MAGIC_NO_CHECK_FORTRAN
|
212
363
|
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_FORTRAN", INT2FIX(MAGIC_NO_CHECK_FORTRAN));
|
213
|
-
|
364
|
+
#endif
|
365
|
+
#ifdef MAGIC_NO_CHECK_TROFF
|
366
|
+
rb_define_const(cFileMagic, "MAGIC_NO_CHECK_TROFF", INT2FIX(MAGIC_NO_CHECK_TROFF));
|
367
|
+
#endif
|
214
368
|
}
|
data/ext/filemagic.h
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#ifndef __FILEMAGIC_H_
|
2
|
+
#define __FILEMAGIC_H_
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include <magic.h>
|
6
|
+
#include <math.h>
|
7
|
+
|
8
|
+
/* Ruby 1.8.5 compatibility */
|
9
|
+
#ifndef RSTRING_LEN
|
10
|
+
#define RSTRING_LEN(s) (RSTRING(s)->len)
|
11
|
+
#endif
|
12
|
+
#ifndef RSTRING_PTR
|
13
|
+
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
|
14
|
+
#endif
|
15
|
+
#ifndef RARRAY_LEN
|
16
|
+
#define RARRAY_LEN(s) (RARRAY(s)->len)
|
17
|
+
#endif
|
18
|
+
#ifndef RARRAY_PTR
|
19
|
+
#define RARRAY_PTR(s) (RARRAY(s)->ptr)
|
20
|
+
#endif
|
21
|
+
|
22
|
+
#define GetMagicCookie(obj, cookie) {\
|
23
|
+
if (RTEST(rb_magic_closed_p(obj)))\
|
24
|
+
rb_raise(rb_eRuntimeError, "closed stream");\
|
25
|
+
Data_Get_Struct(obj, struct magic_set, cookie);\
|
26
|
+
}
|
27
|
+
|
28
|
+
static VALUE cFileMagic, rb_FileMagicError;
|
29
|
+
|
30
|
+
static VALUE rb_magic_new(int, VALUE*, VALUE);
|
31
|
+
static VALUE rb_magic_init(int, VALUE*, VALUE);
|
32
|
+
|
33
|
+
static VALUE rb_magic_close(VALUE);
|
34
|
+
static VALUE rb_magic_closed_p(VALUE);
|
35
|
+
static VALUE rb_magic_file(int, VALUE*, VALUE);
|
36
|
+
static VALUE rb_magic_buffer(int, VALUE*, VALUE);
|
37
|
+
static VALUE rb_magic_getflags(VALUE);
|
38
|
+
static VALUE rb_magic_setflags(VALUE, VALUE);
|
39
|
+
static VALUE rb_magic_check(int, VALUE*, VALUE);
|
40
|
+
static VALUE rb_magic_compile(VALUE, VALUE);
|
41
|
+
|
42
|
+
static VALUE rb_magic_flags_to_int(int, VALUE*);
|
43
|
+
static VALUE rb_magic_apply_simple(VALUE, const char*, VALUE);
|
44
|
+
|
45
|
+
static void rb_magic_free(magic_t);
|
46
|
+
void Init_filemagic(void);
|
47
|
+
|
48
|
+
#endif /* __FILEMAGIC_H_ */
|
data/lib/filemagic.rb
CHANGED
@@ -17,15 +17,19 @@ class FileMagic
|
|
17
17
|
:error, # Handle ENOENT etc as real errors
|
18
18
|
:mime_encoding, # Return only the MIME encoding
|
19
19
|
:mime, # MAGIC_MIME_TYPE | MAGIC_MIME_ENCODING
|
20
|
+
:apple, # Return the Apple creator and type
|
20
21
|
:no_check_compress, # Don't check for compressed files
|
21
22
|
:no_check_tar, # Don't check for tar files
|
22
23
|
:no_check_soft, # Don't check magic entries
|
23
24
|
:no_check_apptype, # Don't check application type
|
24
25
|
:no_check_elf, # Don't check for elf details
|
25
|
-
:
|
26
|
-
:
|
26
|
+
:no_check_text, # Don't check for text files
|
27
|
+
:no_check_cdf, # Don't check for cdf files
|
27
28
|
:no_check_tokens, # Don't check ascii/tokens
|
28
|
-
:
|
29
|
+
:no_check_encoding, # Don't check text encodings
|
30
|
+
:no_check_ascii, # MAGIC_NO_CHECK_TEXT
|
31
|
+
:no_check_fortran, # Don't check ascii/fortran
|
32
|
+
:no_check_troff # Don't check ascii/troff
|
29
33
|
].inject({}) { |flags, flag|
|
30
34
|
const = "MAGIC_#{flag.to_s.upcase}"
|
31
35
|
flags.update(flag => const_defined?(const) && const_get(const))
|
@@ -34,7 +38,8 @@ class FileMagic
|
|
34
38
|
# Map flag values to their names (Integer => :name).
|
35
39
|
FLAGS_BY_INT = FLAGS_BY_SYM.invert.update(0 => :none)
|
36
40
|
|
37
|
-
|
41
|
+
# Extract "simple" MIME type
|
42
|
+
SIMPLE_RE = %r{([.\w\/-]+)}
|
38
43
|
|
39
44
|
@fm = Hash.new { |fm, flags|
|
40
45
|
fm.has_key?(key = flags.to_s) ? fm[key] : fm[key] = new(*flags)
|
@@ -42,7 +47,7 @@ class FileMagic
|
|
42
47
|
|
43
48
|
class << self
|
44
49
|
|
45
|
-
# Provide a "magic singleton"
|
50
|
+
# Provide a "magic singleton".
|
46
51
|
def fm(*flags)
|
47
52
|
@fm.delete(flags.to_s) if @fm[flags].closed?
|
48
53
|
@fm[flags]
|
@@ -54,26 +59,8 @@ class FileMagic
|
|
54
59
|
@fm.clear
|
55
60
|
end
|
56
61
|
|
57
|
-
#
|
58
|
-
|
59
|
-
warn "warning: FileMagic::new() does not take block; use FileMagic::open() instead" if block_given?
|
60
|
-
|
61
|
-
options = flags.last.is_a?(Hash) ? flags.pop : {}
|
62
|
-
|
63
|
-
fm = fm_new(build_flags(*flags))
|
64
|
-
|
65
|
-
options.each { |option, value|
|
66
|
-
if fm.respond_to?(method = "#{option}=")
|
67
|
-
fm.send(method, value)
|
68
|
-
else
|
69
|
-
raise ArgumentError, "illegal option: #{option.inspect}"
|
70
|
-
end
|
71
|
-
}
|
72
|
-
|
73
|
-
fm
|
74
|
-
end
|
75
|
-
|
76
|
-
# Just like #new, but takes an optional block, in which case #close is called at the end.
|
62
|
+
# Just like #new, but takes an optional block, in which case #close
|
63
|
+
# is called at the end and the value of the block is returned.
|
77
64
|
def open(*flags)
|
78
65
|
fm = new(*flags)
|
79
66
|
|
@@ -83,115 +70,26 @@ class FileMagic
|
|
83
70
|
ensure
|
84
71
|
fm.close
|
85
72
|
end
|
73
|
+
else
|
74
|
+
fm
|
86
75
|
end
|
87
|
-
|
88
|
-
fm
|
89
76
|
end
|
90
77
|
|
91
|
-
# Just a short-cut
|
78
|
+
# Just a short-cut to #open with the +mime+ flag set.
|
92
79
|
def mime(*flags, &block)
|
93
80
|
open(:mime, *flags, &block)
|
94
81
|
end
|
95
82
|
|
96
|
-
# Build the actual flags from the named flags passed as arguments.
|
97
|
-
def build_flags(*flags)
|
98
|
-
int_flags = *flags
|
99
|
-
|
100
|
-
unless int_flags.is_a?(Integer)
|
101
|
-
int_flags = MAGIC_NONE
|
102
|
-
|
103
|
-
flags.flatten.each { |flag|
|
104
|
-
if value = flag.is_a?(Integer) ? flag : FLAGS_BY_SYM[flag.to_sym]
|
105
|
-
int_flags |= value
|
106
|
-
else
|
107
|
-
err = value.nil? ? 'no such flag' : 'flag not available'
|
108
|
-
raise ArgumentError, "#{err}: #{flag}"
|
109
|
-
end
|
110
|
-
}
|
111
|
-
end
|
112
|
-
|
113
|
-
int_flags
|
114
|
-
end
|
115
|
-
|
116
|
-
end
|
117
|
-
|
118
|
-
# The actual processing happens in #new.
|
119
|
-
def initialize(*flags)
|
120
|
-
fm_initialize(*flags)
|
121
|
-
|
122
|
-
@flags = flags
|
123
|
-
@closed = false
|
124
83
|
end
|
125
84
|
|
126
|
-
|
127
|
-
return if closed?
|
128
|
-
|
129
|
-
fm_close
|
130
|
-
@closed = true
|
131
|
-
end
|
132
|
-
|
133
|
-
# Optionally cut off additional information after mime-type.
|
134
|
-
def file(file, simplified = simplified?)
|
135
|
-
simplify_mime(fm_file(file), simplified)
|
136
|
-
end
|
137
|
-
|
138
|
-
# Returns the flags as integer.
|
139
|
-
def int_flags
|
140
|
-
@flags.first
|
141
|
-
end
|
142
|
-
|
143
|
-
# Returns the flags as array of symbols.
|
144
|
-
def flags
|
145
|
-
int, flags, log2 = int_flags, [], Math.log(2)
|
146
|
-
|
147
|
-
while int > 0
|
148
|
-
flags << FLAGS_BY_INT[flag = 2 ** Math.log(int).div(log2)]
|
149
|
-
int -= flag
|
150
|
-
end
|
151
|
-
|
152
|
-
flags.reverse
|
153
|
-
end
|
154
|
-
|
155
|
-
# Optionally cut off additional information after mime-type.
|
156
|
-
def buffer(buffer, simplified = simplified?)
|
157
|
-
simplify_mime(fm_buffer(buffer), simplified)
|
158
|
-
end
|
159
|
-
|
160
|
-
def setflags(*flags)
|
161
|
-
@flags = [self.class.build_flags(*flags)]
|
162
|
-
fm_setflags(int_flags)
|
163
|
-
end
|
164
|
-
|
165
|
-
alias_method :flags=, :setflags
|
166
|
-
|
167
|
-
def check(file = "\0")
|
168
|
-
fm_check(file)
|
169
|
-
end
|
170
|
-
|
171
|
-
alias_method :valid?, :check
|
172
|
-
|
173
|
-
def compile(file)
|
174
|
-
fm_compile(file)
|
175
|
-
end
|
85
|
+
attr_writer :simplified
|
176
86
|
|
177
87
|
def simplified?
|
178
88
|
@simplified
|
179
89
|
end
|
180
90
|
|
181
|
-
def closed?
|
182
|
-
@closed
|
183
|
-
end
|
184
|
-
|
185
91
|
def inspect
|
186
|
-
|
187
|
-
str.insert(-2, ' (closed)') if closed?
|
188
|
-
str
|
189
|
-
end
|
190
|
-
|
191
|
-
private
|
192
|
-
|
193
|
-
def simplify_mime(mime, simplified = true)
|
194
|
-
simplified ? mime[/([.\w\/-]+)/, 1].downcase : mime
|
92
|
+
super.insert(-2, closed? ? ' (closed)' : '')
|
195
93
|
end
|
196
94
|
|
197
95
|
end
|
data/lib/filemagic/ext.rb
CHANGED
@@ -23,6 +23,7 @@ module FileMagic::Ext
|
|
23
23
|
flags.unshift :mime
|
24
24
|
file_type(file, *flags)
|
25
25
|
end
|
26
|
+
|
26
27
|
alias_method :mime, :mime_type
|
27
28
|
|
28
29
|
def content_type(file, *flags)
|
@@ -37,11 +38,13 @@ module FileMagic::Ext
|
|
37
38
|
def file_type(*flags)
|
38
39
|
self.class.file_type(self, *flags)
|
39
40
|
end
|
41
|
+
|
40
42
|
alias_method :file, :file_type
|
41
43
|
|
42
44
|
def mime_type(*flags)
|
43
45
|
self.class.mime_type(self, *flags)
|
44
46
|
end
|
47
|
+
|
45
48
|
alias_method :mime, :mime_type
|
46
49
|
|
47
50
|
def content_type(*flags)
|
data/lib/filemagic/version.rb
CHANGED
data/test/filemagic_test.rb
CHANGED
@@ -62,17 +62,19 @@ class TestFileMagic < Test::Unit::TestCase
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def test_block
|
65
|
-
block_fm =
|
66
|
-
|
67
|
-
|
65
|
+
block_fm = nil
|
66
|
+
res = FileMagic.open(FileMagic::MAGIC_NONE) { |fm|
|
67
|
+
block_fm = fm
|
68
|
+
fm.file(path_to('pyfile'))
|
68
69
|
}
|
70
|
+
assert_equal('a python script text executable', res)
|
69
71
|
assert block_fm.closed?
|
70
72
|
end
|
71
73
|
|
72
74
|
def test_setflags
|
73
75
|
fm = FileMagic.new(FileMagic::MAGIC_NONE)
|
74
76
|
assert_equal([], fm.flags)
|
75
|
-
fm.
|
77
|
+
fm.flags = FileMagic::MAGIC_SYMLINK
|
76
78
|
assert_equal([:symlink], fm.flags)
|
77
79
|
fm.close
|
78
80
|
end
|
@@ -80,11 +82,19 @@ class TestFileMagic < Test::Unit::TestCase
|
|
80
82
|
def test_abbr
|
81
83
|
fm = FileMagic.new(:mime, :continue)
|
82
84
|
assert_equal([:mime_type, :continue, :mime_encoding] , fm.flags)
|
83
|
-
fm.
|
85
|
+
fm.flags = :symlink
|
84
86
|
assert_equal([:symlink], fm.flags)
|
85
87
|
fm.close
|
86
88
|
end
|
87
89
|
|
90
|
+
def test_close
|
91
|
+
fm = FileMagic.new
|
92
|
+
fm.close
|
93
|
+
assert fm.closed?
|
94
|
+
fm.close
|
95
|
+
assert fm.closed?
|
96
|
+
end
|
97
|
+
|
88
98
|
# tests adapted from mahoro:
|
89
99
|
|
90
100
|
def test_mahoro_file
|
@@ -120,7 +130,14 @@ class TestFileMagic < Test::Unit::TestCase
|
|
120
130
|
|
121
131
|
def test_abbrev_mime_type
|
122
132
|
fm = FileMagic.mime
|
123
|
-
|
133
|
+
|
134
|
+
assert !fm.simplified?
|
135
|
+
assert_equal('text/plain; charset=us-ascii', fm.file(path_to('perl')))
|
136
|
+
|
137
|
+
fm.simplified = true
|
138
|
+
assert fm.simplified?
|
139
|
+
assert_equal('text/plain', fm.file(path_to('perl')))
|
140
|
+
assert_equal('application/vnd.ms-office', fm.file(path_to('excel-example.xls')))
|
124
141
|
end
|
125
142
|
|
126
143
|
# utility methods:
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-filemagic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Travis Whitton
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-09-
|
19
|
+
date: 2010-09-14 00:00:00 +02:00
|
20
20
|
default_executable:
|
21
21
|
dependencies: []
|
22
22
|
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- lib/filemagic/ext.rb
|
35
35
|
- lib/filemagic/version.rb
|
36
36
|
- lib/filemagic.rb
|
37
|
+
- ext/filemagic.h
|
37
38
|
- ext/filemagic.c
|
38
39
|
- test/pyfile
|
39
40
|
- test/mahoro.c
|