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 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