ruby-filemagic 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,28 +1,49 @@
1
1
  --------------------------------------------------------------------------------
2
2
  7/28/2003 version 0.1.0
3
3
 
4
- o Initial release.
4
+ * Initial release.
5
5
 
6
6
  --------------------------------------------------------------------------------
7
7
  7/30/2003 version 0.1.1
8
8
 
9
- o Added manual close method
10
- o Added unit test suite
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
- 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!
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
- o Added mahoro source file and tests for reference and inspiration
28
- o We have a Rubyforge project now! :-)
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.3.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 from Rubyforge[http://rubyforge.org]:
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/**/*.c', 'test/*'].to_a,
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
- 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:
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
- FileMagic.open("somefile.txt") do |file|
8
- # close is called at the end of this block
9
- end
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("magic")
4
- if have_library("magic", "magic_open") and have_header("magic.h")
5
- create_makefile("filemagic")
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 "ruby.h"
17
- #include <magic.h>
16
+ #include "filemagic.h"
18
17
 
19
- static VALUE cFileMagic, rb_FileMagicError;
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
- #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
- }
24
+ if (rb_block_given_p()) {
25
+ rb_warn("FileMagic::new() does not take block; use FileMagic::open() instead");
26
+ }
26
27
 
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);
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 rb_magic_init(VALUE self, VALUE flags) {
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 rb_magic_close(VALUE self) {
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
- /* FileMagic.new */
53
- static VALUE rb_magic_new(VALUE class, VALUE flags) {
54
- VALUE obj;
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 rb_magic_file(VALUE self, VALUE file) {
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
- return rb_str_new2(m);
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 rb_magic_buffer(VALUE self, VALUE buffer) {
84
- int i = RSTRING_LEN(buffer);
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
- return rb_str_new2(m);
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 rb_magic_setflags(VALUE self, VALUE flags) {
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 rb_magic_check(VALUE self, VALUE file) {
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
- m = StringValuePtr(file);
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 rb_magic_compile(VALUE self, VALUE file) {
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
- void Init_filemagic() {
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, "fm_new", rb_magic_new, 1);
274
+ rb_define_singleton_method(cFileMagic, "new", rb_magic_new, -1);
137
275
 
138
- rb_define_method(cFileMagic, "fm_initialize", rb_magic_init, 1);
139
- rb_define_method(cFileMagic, "fm_close", rb_magic_close, 0);
140
- rb_define_method(cFileMagic, "fm_file", rb_magic_file, 1);
141
- rb_define_method(cFileMagic, "fm_buffer", rb_magic_buffer, 1);
142
- rb_define_method(cFileMagic, "fm_setflags", rb_magic_setflags, 1);
143
- rb_define_method(cFileMagic, "fm_check", rb_magic_check, 1);
144
- rb_define_method(cFileMagic, "fm_compile", rb_magic_compile, 1);
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
- #ifdef MAGIC_NONE
290
+ #ifdef MAGIC_NONE
149
291
  rb_define_const(cFileMagic, "MAGIC_NONE", INT2FIX(MAGIC_NONE));
150
- #endif
151
- #ifdef MAGIC_DEBUG
292
+ #endif
293
+ #ifdef MAGIC_DEBUG
152
294
  rb_define_const(cFileMagic, "MAGIC_DEBUG", INT2FIX(MAGIC_DEBUG));
153
- #endif
154
- #ifdef MAGIC_SYMLINK
295
+ #endif
296
+ #ifdef MAGIC_SYMLINK
155
297
  rb_define_const(cFileMagic, "MAGIC_SYMLINK", INT2FIX(MAGIC_SYMLINK));
156
- #endif
157
- #ifdef MAGIC_COMPRESS
298
+ #endif
299
+ #ifdef MAGIC_COMPRESS
158
300
  rb_define_const(cFileMagic, "MAGIC_COMPRESS", INT2FIX(MAGIC_COMPRESS));
159
- #endif
160
- #ifdef MAGIC_DEVICES
301
+ #endif
302
+ #ifdef MAGIC_DEVICES
161
303
  rb_define_const(cFileMagic, "MAGIC_DEVICES", INT2FIX(MAGIC_DEVICES));
162
- #endif
163
- #ifdef MAGIC_MIME_TYPE
304
+ #endif
305
+ #ifdef MAGIC_MIME_TYPE
164
306
  rb_define_const(cFileMagic, "MAGIC_MIME_TYPE", INT2FIX(MAGIC_MIME_TYPE));
165
- #endif
166
- #ifdef MAGIC_CONTINUE
307
+ #endif
308
+ #ifdef MAGIC_CONTINUE
167
309
  rb_define_const(cFileMagic, "MAGIC_CONTINUE", INT2FIX(MAGIC_CONTINUE));
168
- #endif
169
- #ifdef MAGIC_CHECK
310
+ #endif
311
+ #ifdef MAGIC_CHECK
170
312
  rb_define_const(cFileMagic, "MAGIC_CHECK", INT2FIX(MAGIC_CHECK));
171
- #endif
172
- #ifdef MAGIC_PRESERVE_ATIME
313
+ #endif
314
+ #ifdef MAGIC_PRESERVE_ATIME
173
315
  rb_define_const(cFileMagic, "MAGIC_PRESERVE_ATIME", INT2FIX(MAGIC_PRESERVE_ATIME));
174
- #endif
175
- #ifdef MAGIC_RAW
316
+ #endif
317
+ #ifdef MAGIC_RAW
176
318
  rb_define_const(cFileMagic, "MAGIC_RAW", INT2FIX(MAGIC_RAW));
177
- #endif
178
- #ifdef MAGIC_ERROR
319
+ #endif
320
+ #ifdef MAGIC_ERROR
179
321
  rb_define_const(cFileMagic, "MAGIC_ERROR", INT2FIX(MAGIC_ERROR));
180
- #endif
181
- #ifdef MAGIC_MIME_ENCODING
322
+ #endif
323
+ #ifdef MAGIC_MIME_ENCODING
182
324
  rb_define_const(cFileMagic, "MAGIC_MIME_ENCODING", INT2FIX(MAGIC_MIME_ENCODING));
183
- #endif
184
- #ifdef MAGIC_MIME
325
+ #endif
326
+ #ifdef MAGIC_MIME
185
327
  rb_define_const(cFileMagic, "MAGIC_MIME", INT2FIX(MAGIC_MIME));
186
- #endif
187
- #ifdef MAGIC_NO_CHECK_COMPRESS
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
- #endif
190
- #ifdef MAGIC_NO_CHECK_TAR
334
+ #endif
335
+ #ifdef MAGIC_NO_CHECK_TAR
191
336
  rb_define_const(cFileMagic, "MAGIC_NO_CHECK_TAR", INT2FIX(MAGIC_NO_CHECK_TAR));
192
- #endif
193
- #ifdef MAGIC_NO_CHECK_SOFT
337
+ #endif
338
+ #ifdef MAGIC_NO_CHECK_SOFT
194
339
  rb_define_const(cFileMagic, "MAGIC_NO_CHECK_SOFT", INT2FIX(MAGIC_NO_CHECK_SOFT));
195
- #endif
196
- #ifdef MAGIC_NO_CHECK_APPTYPE
340
+ #endif
341
+ #ifdef MAGIC_NO_CHECK_APPTYPE
197
342
  rb_define_const(cFileMagic, "MAGIC_NO_CHECK_APPTYPE", INT2FIX(MAGIC_NO_CHECK_APPTYPE));
198
- #endif
199
- #ifdef MAGIC_NO_CHECK_ELF
343
+ #endif
344
+ #ifdef MAGIC_NO_CHECK_ELF
200
345
  rb_define_const(cFileMagic, "MAGIC_NO_CHECK_ELF", INT2FIX(MAGIC_NO_CHECK_ELF));
201
- #endif
202
- #ifdef MAGIC_NO_CHECK_ASCII
203
- rb_define_const(cFileMagic, "MAGIC_NO_CHECK_ASCII", INT2FIX(MAGIC_NO_CHECK_ASCII));
204
- #endif
205
- #ifdef MAGIC_NO_CHECK_TROFF
206
- rb_define_const(cFileMagic, "MAGIC_NO_CHECK_TROFF", INT2FIX(MAGIC_NO_CHECK_TROFF));
207
- #endif
208
- #ifdef MAGIC_NO_CHECK_TOKENS
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
- #endif
211
- #ifdef MAGIC_NO_CHECK_FORTRAN
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
- #endif
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
- :no_check_ascii, # Don't check for ascii files
26
- :no_check_troff, # Don't check ascii/troff
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
- :no_check_fortran # Don't check ascii/fortran
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
- attr_writer :simplified
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
- # Allow shorter names for flags; now also takes options.
58
- def new(*flags)
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
- def close
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
- str = super
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)
@@ -3,7 +3,7 @@ class FileMagic
3
3
  module Version
4
4
 
5
5
  MAJOR = 0
6
- MINOR = 3
6
+ MINOR = 4
7
7
  TINY = 0
8
8
 
9
9
  class << self
@@ -62,17 +62,19 @@ class TestFileMagic < Test::Unit::TestCase
62
62
  end
63
63
 
64
64
  def test_block
65
- block_fm = FileMagic.open(FileMagic::MAGIC_NONE) { |fm|
66
- res = fm.file(path_to('pyfile'))
67
- assert_equal('a python script text executable', res)
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.setflags(FileMagic::MAGIC_SYMLINK)
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.setflags(:symlink)
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
- assert_match(/\Aapplication\/vnd.ms-/, fm.file(path_to('excel-example.xls')))
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: 19
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 0.3.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-10 00:00:00 +02:00
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