ruby-magic 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,23 +1,3 @@
1
- /* :enddoc: */
2
-
3
- /*
4
- * functions.h
5
- *
6
- * Copyright 2013-2015 Krzysztof Wilczynski
7
- *
8
- * Licensed under the Apache License, Version 2.0 (the "License");
9
- * you may not use this file except in compliance with the License.
10
- * You may obtain a copy of the License at
11
- *
12
- * http://www.apache.org/licenses/LICENSE-2.0
13
- *
14
- * Unless required by applicable law or agreed to in writing, software
15
- * distributed under the License is distributed on an "AS IS" BASIS,
16
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
- * See the License for the specific language governing permissions and
18
- * limitations under the License.
19
- */
20
-
21
1
  #if !defined(_FUNCTIONS_H)
22
2
  #define _FUNCTIONS_H 1
23
3
 
@@ -27,78 +7,56 @@ extern "C" {
27
7
 
28
8
  #include "common.h"
29
9
 
30
- #if defined(HAVE_BROKEN_MAGIC)
31
- # define OVERRIDE_LOCALE(f, r, ...) \
32
- do { \
33
- save_t __l_##f; \
34
- override_current_locale(&(__l_##f)); \
35
- r = f(__VA_ARGS__); \
36
- restore_current_locale(&(__l_##f)); \
37
- } while(0)
38
- #else
39
- # define OVERRIDE_LOCALE(f, r, ...) \
40
- do { \
41
- r = f(__VA_ARGS__); \
42
- } while(0)
43
- #endif
44
-
45
- #define SUPPRESS_EVERYTHING(f, r, ...) \
46
- do { \
47
- save_t __e_##f; \
48
- suppress_error_output(&(__e_##f)); \
49
- OVERRIDE_LOCALE(f, r, __VA_ARGS__); \
50
- restore_error_output(&(__e_##f)); \
51
- } while(0)
52
-
53
- #define MAGIC_FUNCTION(f, r, x, ...) \
54
- do { \
55
- if ((x) & MAGIC_ERROR) { \
56
- OVERRIDE_LOCALE(f, r, __VA_ARGS__); \
57
- } \
58
- else { \
59
- SUPPRESS_EVERYTHING(f, r, __VA_ARGS__); \
60
- } \
61
- } while(0)
62
-
63
- struct file_data {
64
- int old_fd;
65
- int new_fd;
66
- fpos_t position;
67
- };
68
-
69
- typedef struct file_data file_data_t;
70
-
71
- struct locale_data {
72
- #if defined(HAVE_SAFE_LOCALE)
73
- locale_t old_locale;
74
- locale_t new_locale;
75
- #else
76
- char *old_locale;
77
- #endif
78
- };
10
+ #define MAGIC_FUNCTION(f, r, x, ...) \
11
+ do { \
12
+ if ((x) & MAGIC_DEBUG) \
13
+ r = f(__VA_ARGS__); \
14
+ else { \
15
+ save_t __##f; \
16
+ override_error_output(&(__##f)); \
17
+ r = f(__VA_ARGS__); \
18
+ restore_error_output(&(__##f)); \
19
+ } \
20
+ } while(0)
21
+
22
+ typedef struct file_data {
23
+ fpos_t position;
24
+ int old_fd;
25
+ int new_fd;
26
+ } file_data_t;
27
+
28
+ typedef struct save {
29
+ file_data_t file;
30
+ int status;
31
+ } save_t;
32
+
33
+ extern magic_t magic_open_wrapper(int flags);
34
+ extern void magic_close_wrapper(magic_t magic);
35
+
36
+ extern const char* magic_error_wrapper(magic_t magic);
37
+ extern int magic_errno_wrapper(magic_t magic);
79
38
 
80
- typedef struct locale_data locale_data_t;
39
+ extern const char* magic_getpath_wrapper(void);
81
40
 
82
- struct save {
83
- int status;
84
- union {
85
- file_data_t file;
86
- locale_data_t locale;
87
- } data;
88
- };
41
+ extern int magic_getparam_wrapper(magic_t magic, int parameter, void *value);
42
+ extern int magic_setparam_wrapper(magic_t magic, int parameter,
43
+ const void *value);
89
44
 
90
- typedef struct save save_t;
45
+ extern int magic_getflags_wrapper(magic_t magic);
46
+ extern int magic_setflags_wrapper(magic_t magic, int flags);
91
47
 
92
- extern const char* magic_getpath_wrapper(void);
48
+ extern int magic_load_wrapper(magic_t magic, const char *magic_file, int flags);
49
+ extern int magic_load_buffers_wrapper(magic_t magic, void **buffers,
50
+ size_t *sizes, size_t count, int flags);
93
51
 
94
- extern int magic_setflags_wrapper(struct magic_set *ms, int flags);
95
- extern int magic_load_wrapper(struct magic_set *ms, const char *magicfile, int flags);
96
- extern int magic_compile_wrapper(struct magic_set *ms, const char *magicfile, int flags);
97
- extern int magic_check_wrapper(struct magic_set *ms, const char *magicfile, int flags);
52
+ extern int magic_compile_wrapper(magic_t magic, const char *magic_file, int flags);
53
+ extern int magic_check_wrapper(magic_t magic, const char *magic_file, int flags);
98
54
 
99
- extern const char* magic_file_wrapper(struct magic_set *ms, const char *filename, int flags);
100
- extern const char* magic_buffer_wrapper(struct magic_set *ms, const void *buffer, size_t size, int flags);
101
- extern const char* magic_descriptor_wrapper(struct magic_set *ms, int fd, int flags);
55
+ extern const char* magic_file_wrapper(magic_t magic, const char *filename,
56
+ int flags);
57
+ extern const char* magic_buffer_wrapper(magic_t magic, const void *buffer,
58
+ size_t size, int flags);
59
+ extern const char* magic_descriptor_wrapper(magic_t magic, int fd, int flags);
102
60
 
103
61
  extern int magic_version_wrapper(void);
104
62
 
@@ -107,5 +65,3 @@ extern int magic_version_wrapper(void);
107
65
  #endif
108
66
 
109
67
  #endif /* _FUNCTIONS_H */
110
-
111
- /* vim: set ts=8 sw=4 sts=2 et : */
@@ -1,48 +1,39 @@
1
- /* :stopdoc: */
2
-
3
- /*
4
- * ruby-magic.c
5
- *
6
- * Copyright 2013-2015 Krzysztof Wilczynski
7
- *
8
- * Licensed under the Apache License, Version 2.0 (the "License");
9
- * you may not use this file except in compliance with the License.
10
- * You may obtain a copy of the License at
11
- *
12
- * http://www.apache.org/licenses/LICENSE-2.0
13
- *
14
- * Unless required by applicable law or agreed to in writing, software
15
- * distributed under the License is distributed on an "AS IS" BASIS,
16
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
- * See the License for the specific language governing permissions and
18
- * limitations under the License.
19
- */
20
-
21
1
  #if defined(__cplusplus)
22
2
  extern "C" {
23
3
  #endif
24
4
 
25
5
  #include "ruby-magic.h"
26
6
 
27
- ID id_at_flags, id_at_path, id_at_mutex;
7
+ static int rb_mgc_do_not_auto_load;
8
+ static int rb_mgc_do_not_stop_on_error;
9
+ static int rb_mgc_warning;
10
+
11
+ ID id_at_flags;
12
+ ID id_at_paths;
28
13
 
29
- VALUE rb_cMagic = Qnil;
14
+ VALUE rb_cMagic = Qundef;
30
15
 
31
- VALUE rb_mgc_eError = Qnil;
32
- VALUE rb_mgc_eMagicError = Qnil;
33
- VALUE rb_mgc_eLibraryError = Qnil;
34
- VALUE rb_mgc_eFlagsError = Qnil;
35
- VALUE rb_mgc_eNotImplementedError = Qnil;
16
+ VALUE rb_mgc_eError = Qundef;
17
+ VALUE rb_mgc_eMagicError = Qundef;
18
+ VALUE rb_mgc_eLibraryError = Qundef;
19
+ VALUE rb_mgc_eParameterError = Qundef;
20
+ VALUE rb_mgc_eFlagsError = Qundef;
21
+ VALUE rb_mgc_eNotImplementedError = Qundef;
36
22
 
37
23
  void Init_magic(void);
38
24
 
39
- static VALUE magic_close_internal(void *data);
25
+ static VALUE magic_get_parameter_internal(void *data);
26
+ static VALUE magic_set_parameter_internal(void *data);
27
+ static VALUE magic_get_flags_internal(void *data);
28
+ static VALUE magic_set_flags_internal(void *data);
40
29
  static VALUE magic_load_internal(void *data);
30
+ static VALUE magic_load_buffers_internal(void *data);
41
31
  static VALUE magic_compile_internal(void *data);
42
32
  static VALUE magic_check_internal(void *data);
43
33
  static VALUE magic_file_internal(void *data);
44
34
  static VALUE magic_buffer_internal(void *data);
45
35
  static VALUE magic_descriptor_internal(void *data);
36
+ static VALUE magic_close_internal(void *data);
46
37
 
47
38
  static void* nogvl_magic_load(void *data);
48
39
  static void* nogvl_magic_compile(void *data);
@@ -51,937 +42,1554 @@ static void* nogvl_magic_file(void *data);
51
42
  static void* nogvl_magic_descriptor(void *data);
52
43
 
53
44
  static VALUE magic_allocate(VALUE klass);
45
+ static void magic_mark(void *data);
54
46
  static void magic_free(void *data);
55
-
56
47
  static VALUE magic_exception_wrapper(VALUE value);
57
48
  static VALUE magic_exception(void *data);
58
-
49
+ static void magic_library_close(void *data);
59
50
  static VALUE magic_library_error(VALUE klass, void *data);
60
51
  static VALUE magic_generic_error(VALUE klass, int magic_errno,
61
- const char *magic_error);
62
-
63
- static VALUE magic_lock(VALUE object, VALUE (*function)(ANYARGS), void *data);
52
+ const char *magic_error);
53
+ static VALUE magic_lock(VALUE object, VALUE (*function)(ANYARGS),
54
+ void *data);
64
55
  static VALUE magic_unlock(VALUE object);
56
+ static VALUE magic_return(void *data);
57
+ static int magic_flags(VALUE object);
58
+ static int magic_set_flags(VALUE object, VALUE value);
59
+ static VALUE magic_set_paths(VALUE object, VALUE value);
65
60
 
66
- static VALUE magic_return(VALUE value, void *data);
61
+ /*
62
+ * call-seq:
63
+ * Magic.do_not_auto_load -> boolean
64
+ *
65
+ * Returns +true+ if the global +do_not_auto_load+ flag is set, or +false+
66
+ * otherwise.
67
+ *
68
+ * Example:
69
+ *
70
+ * Magic.do_not_auto_load #=> false
71
+ * Magic.do_not_auto_load = true #=> true
72
+ * Magic.do_not_auto_load #=> true
73
+ *
74
+ * See also: Magic::new, Magic#loaded?, Magic#load and Magic#load_buffers
75
+ */
76
+ VALUE
77
+ rb_mgc_get_do_not_auto_load_global(RB_UNUSED_VAR(VALUE object))
78
+ {
79
+ return CBOOL2RVAL(rb_mgc_do_not_auto_load);
80
+ }
67
81
 
68
- /* :startdoc: */
82
+ /*
83
+ * call-seq:
84
+ * Magic.do_not_auto_load= ( boolean ) -> boolean
85
+ *
86
+ * Sets the global +do_not_auto_load+ flag for the Magic object and each of the
87
+ * Magic object instances. This flag can be used to disable automatic loading of
88
+ * the Magic database files.
89
+ *
90
+ * Returns +true+ if the global +do_not_auto_load+ flag is set, or +false+
91
+ * otherwise.
92
+ *
93
+ * Example:
94
+ *
95
+ * Magic.do_not_auto_load #=> false
96
+ * Magic.do_not_auto_load = true #=> true
97
+ * Magic.do_not_auto_load #=> true
98
+ *
99
+ * Example:
100
+ *
101
+ * Magic.do_not_auto_load = true #=> true
102
+ * magic = Magic.new
103
+ * magic.loaded? #=> false
104
+ * magic.load_buffers(File.read(magic.paths[0] + ".mgc")) #=> nil
105
+ * magic.loaded? #=> true
106
+ *
107
+ * See also: Magic::new, Magic#loaded?, Magic#load and Magic#load_buffers
108
+ */
109
+ VALUE
110
+ rb_mgc_set_do_not_auto_load_global(RB_UNUSED_VAR(VALUE object), VALUE value)
111
+ {
112
+ rb_mgc_do_not_auto_load = RVAL2CBOOL(value);
113
+ return value;
114
+ }
69
115
 
70
116
  /*
71
117
  * call-seq:
72
- * Magic.new -> self
73
- * Magic.new( path, ... ) -> self
74
- * Magic.new( array ) -> self
118
+ * Magic.do_not_stop_on_error -> boolean
75
119
  *
76
- * Opens the underlying _Magic_ database and returns a new _Magic_.
120
+ * Returns +true+ if the global +do_not_stop_on_error+ flag is set, or +false+
121
+ * otherwise.
122
+ *
123
+ * Example:
124
+ *
125
+ * Magic.do_not_stop_on_error #=> false
126
+ * Magic.do_not_stop_on_error = true #=> true
127
+ * Magic.do_not_stop_on_error #=> true
128
+ *
129
+ * See also: Magic::new, Magic::open and Magic#do_not_stop_on_error
130
+ */
131
+ VALUE
132
+ rb_mgc_get_do_not_stop_on_error_global(RB_UNUSED_VAR(VALUE object))
133
+ {
134
+ return CBOOL2RVAL(rb_mgc_do_not_stop_on_error);
135
+ }
136
+
137
+ /*
138
+ * call-seq:
139
+ * Magic.do_not_stop_on_error= (boolean) -> boolean
77
140
  *
78
141
  * Example:
79
142
  *
80
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
143
+ * Magic.do_not_stop_on_error #=> false
144
+ * Magic.do_not_stop_on_error = true #=> true
145
+ * Magic.do_not_stop_on_error #=> true
146
+ *
147
+ * See also: Magic::new, Magic::open and Magic#do_not_stop_on_error
148
+ */
149
+ VALUE
150
+ rb_mgc_set_do_not_stop_on_error_global(RB_UNUSED_VAR(VALUE object), VALUE value)
151
+ {
152
+ rb_mgc_do_not_stop_on_error = RVAL2CBOOL(value);
153
+ return value;
154
+ }
155
+
156
+ /*
157
+ * call-seq:
158
+ * Magic.new -> self
159
+ * Magic.new( string, ... ) -> self
160
+ * Magic.new( array ) -> self
161
+ *
162
+ * Opens the underlying _Magic_ database and returns a new _Magic_.
163
+ *
164
+ * Example:
81
165
  *
82
- * Will raise <i>Magic::LibraryError</i> exception if, or
83
- * <i>Magic::MagicError</i> exception if
166
+ * magic = Magic.new
167
+ * magic.class #=> Magic
84
168
  *
85
169
  * See also: Magic::open, Magic::mime, Magic::type, Magic::encoding, Magic::compile and Magic::check
86
170
  */
87
171
  VALUE
88
172
  rb_mgc_initialize(VALUE object, VALUE arguments)
89
173
  {
90
- VALUE mutex = Qnil;
91
-
92
- magic_arguments_t ma;
93
- const char *klass = NULL;
174
+ magic_object_t *mo;
175
+ const char *klass = "Magic";
94
176
 
95
- if (rb_block_given_p()) {
96
- klass = "Magic";
177
+ if (!NIL_P(object))
178
+ klass = rb_obj_classname(object);
97
179
 
98
- if (!NIL_P(object)) {
99
- klass = rb_class2name(CLASS_OF(object));
100
- }
180
+ if (rb_block_given_p())
181
+ MAGIC_WARNING(0, "%s::new() does not take block; use %s::open() instead",
182
+ klass, klass);
101
183
 
102
- rb_warn("%s::new() does not take block; use %s::open() instead",
103
- klass, klass);
104
- }
184
+ if(RTEST(rb_eval_string("ENV['MAGIC_DO_NOT_STOP_ON_ERROR']")))
185
+ rb_mgc_do_not_stop_on_error = 1;
105
186
 
106
- mutex = rb_class_new_instance(0, 0, rb_const_get(rb_cObject,
107
- rb_intern("Mutex")));
187
+ if(RTEST(rb_eval_string("ENV['MAGIC_DO_NOT_AUTOLOAD']")))
188
+ rb_mgc_do_not_auto_load = 1;
108
189
 
109
- rb_ivar_set(object, id_at_mutex, mutex);
190
+ MAGIC_OBJECT(mo);
191
+ mo->stop_on_errors = 1;
192
+ if (rb_mgc_do_not_stop_on_error)
193
+ mo->stop_on_errors = 0;
110
194
 
111
- MAGIC_COOKIE(ma.cookie);
195
+ mo->mutex = rb_class_new_instance(0, 0, rb_const_get(rb_cObject,
196
+ rb_intern("Mutex")));
112
197
 
113
- ma.flags = MAGIC_NONE;
114
- ma.data.file.path = NULL;
198
+ magic_set_flags(object, INT2NUM(MAGIC_NONE));
199
+ magic_set_paths(object, RARRAY_EMPTY);
115
200
 
116
- rb_ivar_set(object, id_at_flags, INT2NUM(ma.flags));
117
- rb_mgc_load(object, arguments);
201
+ if (rb_mgc_do_not_auto_load) {
202
+ if (!RARRAY_EMPTY_P(arguments))
203
+ MAGIC_WARNING(1, "%s::do_not_auto_load is set; using %s#new() to load "
204
+ "Magic database from a file will have no effect",
205
+ klass, klass);
206
+ return object;
207
+ }
118
208
 
119
- return object;
209
+ rb_mgc_load(object, arguments);
210
+ return object;
120
211
  }
121
212
 
122
213
  /*
123
214
  * call-seq:
124
- * magic.close -> nil
125
- *
126
- * Closes the underlying _Magic_ database.
127
- *
128
- * Example:
129
- *
130
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
131
- * magic.close #=> nil
215
+ * magic.do_not_stop_on_error -> boolean
132
216
  *
133
- * See also: Magic#closed?
217
+ * See also: Magic::new, Magic::open and Magic::do_not_stop_on_error
134
218
  */
135
219
  VALUE
136
- rb_mgc_close(VALUE object)
220
+ rb_mgc_get_do_not_stop_on_error(VALUE object)
137
221
  {
138
- magic_t cookie;
222
+ magic_object_t *mo;
223
+
224
+ MAGIC_CHECK_OPEN(object);
225
+ MAGIC_OBJECT(mo);
139
226
 
140
- MAGIC_COOKIE(cookie);
227
+ return CBOOL2RVAL(!mo->stop_on_errors);
228
+ }
141
229
 
142
- if (cookie) {
143
- MAGIC_SYNCHRONIZED(magic_close_internal, cookie);
230
+ /*
231
+ * call-seq:
232
+ * magic.do_not_stop_on_error= ( boolean ) -> boolean
233
+ *
234
+ * See also: Magic::new, Magic::open and Magic::do_not_stop_on_error
235
+ */
236
+ VALUE
237
+ rb_mgc_set_do_not_stop_on_error(VALUE object, VALUE value)
238
+ {
239
+ magic_object_t *mo;
144
240
 
145
- if (DATA_P(object)) {
146
- DATA_PTR(object) = NULL;
147
- }
148
- }
241
+ MAGIC_CHECK_OPEN(object);
242
+ MAGIC_OBJECT(mo);
149
243
 
150
- return Qnil;
244
+ mo->stop_on_errors = !RVAL2CBOOL(value);
245
+ return value;
151
246
  }
152
247
 
153
248
  /*
154
249
  * call-seq:
155
- * magic.closed? -> true or false
250
+ * magic.open? -> true or false
156
251
  *
157
252
  * Returns +true+ if the underlying _Magic_ database is open,
158
253
  * or +false+ otherwise.
159
254
  *
160
255
  * Example:
161
256
  *
162
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
163
- * magic.closed? #=> false
164
- * magic.close #=> nil
165
- * magic.closed? #=> true
257
+ * magic = Magic.new
258
+ * magic.open? #=> true
259
+ * magic.close #=> nil
260
+ * magic.open? #=> false
166
261
  *
167
- * See also: Magic#close
262
+ * See also: Magic#close?, Magic#close and Magic#new
168
263
  */
169
264
  VALUE
170
- rb_mgc_closed(VALUE object)
265
+ rb_mgc_open_p(VALUE object)
171
266
  {
172
- magic_t cookie;
173
-
174
- MAGIC_COOKIE(cookie);
175
-
176
- if (DATA_P(object) && DATA_PTR(object) && cookie) {
177
- return Qfalse;
178
- }
179
-
180
- return Qtrue;
267
+ return MAGIC_CLOSED_P(object) ? Qfalse : Qtrue;
181
268
  }
182
269
 
183
270
  /*
184
271
  * call-seq:
185
- * magic.path -> array
272
+ * magic.close -> nil
186
273
  *
187
- * Returns an +array+
274
+ * Closes the underlying _Magic_ database.
188
275
  *
189
276
  * Example:
190
277
  *
191
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
192
- * magic.path #=> ["/etc/magic", "/usr/share/misc/magic"]
278
+ * magic = Magic.new
279
+ * magic.close #=> nil
193
280
  *
194
- * Will raise <i>Magic::LibraryError</i> exception if
281
+ * See also: Magic#closed?, Magic#open? and Magic#new
195
282
  */
196
283
  VALUE
197
- rb_mgc_get_path(VALUE object)
284
+ rb_mgc_close(VALUE object)
198
285
  {
199
- VALUE value = Qnil;
200
- const char *cstring = NULL;
286
+ magic_object_t *mo;
201
287
 
202
- CHECK_MAGIC_OPEN(object);
288
+ if (MAGIC_CLOSED_P(object))
289
+ return Qnil;
203
290
 
204
- value = rb_ivar_get(object, id_at_path);
205
- if (!NIL_P(value) && !RARRAY_EMPTY_P(value) && !getenv("MAGIC")) {
206
- return value;
207
- }
291
+ MAGIC_OBJECT(mo);
292
+ if (mo) {
293
+ MAGIC_SYNCHRONIZED(magic_close_internal, mo);
294
+ if (DATA_P(object))
295
+ DATA_PTR(object) = NULL;
296
+ }
208
297
 
209
- cstring = magic_getpath_wrapper();
210
- value = magic_split(CSTR2RVAL(cstring), CSTR2RVAL(":"));
211
-
212
- return rb_ivar_set(object, id_at_path, value);
298
+ return Qnil;
213
299
  }
214
300
 
215
301
  /*
216
302
  * call-seq:
217
- * magic.flags -> integer
303
+ * magic.closed? -> true or false
218
304
  *
219
- * Returns
305
+ * Returns +true+ if the underlying _Magic_ database is closed,
306
+ * or +false+ otherwise.
220
307
  *
221
308
  * Example:
222
309
  *
223
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
224
- * magic.flags #=> 0
225
- * magic.flags = Magic::MIME #=> 1040
226
- * magic.flags #=> 1040
310
+ * magic = Magic.new
311
+ * magic.closed? #=> false
312
+ * magic.close #=> nil
313
+ * magic.closed? #=> true
227
314
  *
228
- * See also: Magic#flags_to_a
315
+ * See also: Magic#close, Magic#open? and #Magic#new
229
316
  */
230
317
  VALUE
231
- rb_mgc_get_flags(VALUE object)
318
+ rb_mgc_close_p(VALUE object)
232
319
  {
233
- CHECK_MAGIC_OPEN(object);
234
- return rb_ivar_get(object, id_at_flags);
320
+ magic_object_t *mo;
321
+ magic_t cookie = NULL;
322
+
323
+ MAGIC_OBJECT(mo);
324
+ if (mo)
325
+ cookie = mo->cookie;
326
+
327
+ if (DATA_P(object) && cookie)
328
+ return Qfalse;
329
+
330
+ return Qtrue;
235
331
  }
236
332
 
237
333
  /*
238
334
  * call-seq:
239
- * magic.flags= (integer) -> integer
335
+ * magic.paths -> array
240
336
  *
241
337
  * Example:
242
338
  *
243
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
244
- * magic.flags = Magic::MIME #=> 1040
245
- * magic.flags = Magic::MIME_TYPE #=> 16
339
+ * magic = Magic.new
340
+ * magic.paths #=> ["/etc/magic", "/usr/share/misc/magic"]
246
341
  *
247
- * Will raise <i>Magic::FlagsError</i> exception if, or
248
- * <i>Magic::LibraryError</i> exception if, or
249
- * <i>Magic::NotImplementedError</i> exception if, or
250
342
  */
251
343
  VALUE
252
- rb_mgc_set_flags(VALUE object, VALUE value)
344
+ rb_mgc_get_paths(VALUE object)
253
345
  {
254
- int local_errno;
255
- magic_t cookie;
346
+ const char *cstring = NULL;
347
+ VALUE value = Qundef;
256
348
 
257
- Check_Type(value, T_FIXNUM);
349
+ MAGIC_CHECK_OPEN(object);
258
350
 
259
- CHECK_MAGIC_OPEN(object);
260
- MAGIC_COOKIE(cookie);
351
+ value = rb_ivar_get(object, id_at_paths);
352
+ if (!NIL_P(value) && !RARRAY_EMPTY_P(value) && !getenv("MAGIC"))
353
+ return value;
261
354
 
262
- if (magic_setflags_wrapper(cookie, NUM2INT(value)) < 0) {
263
- local_errno = errno;
355
+ cstring = magic_getpath_wrapper();
356
+ value = magic_split(CSTR2RVAL(cstring), CSTR2RVAL(":"));
357
+ RB_GC_GUARD(value);
264
358
 
265
- switch (local_errno) {
266
- case EINVAL:
267
- MAGIC_GENERIC_ERROR(rb_mgc_eFlagsError, EINVAL,
268
- error(E_FLAG_INVALID_VALUE));
269
- break;
270
- case ENOSYS:
271
- MAGIC_GENERIC_ERROR(rb_mgc_eNotImplementedError, ENOSYS,
272
- error(E_FLAG_NOT_IMPLEMENTED));
273
- break;
274
- default:
275
- MAGIC_LIBRARY_ERROR(cookie);
276
- break;
277
- }
278
- }
279
-
280
- return rb_ivar_set(object, id_at_flags, value);
359
+ return value;
281
360
  }
282
361
 
283
362
  /*
284
363
  * call-seq:
285
- * magic.load -> array
286
- * magic.load( path, ... ) -> array
287
- * magic.load( array ) -> array
288
- *
289
- * Example:
290
- *
291
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
292
- * magic.load #=> ["/etc/magic", "/usr/share/misc/magic"]
293
- * magic.load("/usr/share/misc/magic", "/etc/magic") #=> ["/usr/share/misc/magic", "/etc/magic"]
294
- * magic.load #=> ["/etc/magic", "/usr/share/misc/magic"]
295
- *
296
- * Will raise <i>Magic::LibraryError</i> exception if, or
297
- *
298
- * See also: Magic#check, Magic#compile, Magic::check and Magic::compile
364
+ * magic.get_parameter( integer ) -> integer
299
365
  */
300
366
  VALUE
301
- rb_mgc_load(VALUE object, VALUE arguments)
367
+ rb_mgc_get_parameter(VALUE object, VALUE tag)
302
368
  {
303
- magic_arguments_t ma;
304
- VALUE value = Qnil;
369
+ int local_errno;
370
+ magic_object_t *mo;
371
+ magic_arguments_t ma;
305
372
 
306
- CHECK_MAGIC_OPEN(object);
307
- MAGIC_COOKIE(ma.cookie);
373
+ MAGIC_CHECK_INTEGER_TYPE(tag);
374
+ MAGIC_CHECK_OPEN(object);
375
+ MAGIC_COOKIE(mo, ma.cookie);
308
376
 
309
- if (!RARRAY_EMPTY_P(arguments) && !NIL_P(RARRAY_FIRST(arguments))) {
310
- value = magic_join(arguments, CSTR2RVAL(":"));
311
- ma.data.file.path = RVAL2CSTR(value);
312
- }
313
- else {
314
- ma.data.file.path = magic_getpath_wrapper();
315
- }
377
+ ma.type.parameter.tag = NUM2INT(tag);
316
378
 
317
- ma.flags = NUM2INT(rb_mgc_get_flags(object));
379
+ MAGIC_SYNCHRONIZED(magic_get_parameter_internal, &ma);
380
+ local_errno = errno;
318
381
 
319
- if (!MAGIC_SYNCHRONIZED(magic_load_internal, &ma)) {
320
- MAGIC_LIBRARY_ERROR(ma.cookie);
321
- }
382
+ if (ma.status < 0) {
383
+ if (local_errno == EINVAL)
384
+ MAGIC_GENERIC_ERROR(rb_mgc_eParameterError,
385
+ local_errno,
386
+ E_PARAM_INVALID_TYPE);
322
387
 
323
- value = magic_split(CSTR2RVAL(ma.data.file.path), CSTR2RVAL(":"));
388
+ MAGIC_LIBRARY_ERROR(ma.cookie);
389
+ }
324
390
 
325
- return rb_ivar_set(object, id_at_path, value);
391
+ return SIZET2NUM(ma.type.parameter.value);
326
392
  }
327
393
 
328
394
  /*
329
395
  * call-seq:
330
- * magic.compile -> true
331
- * magic.compile( path, ... ) -> true
332
- * magic.compile( array ) -> true
396
+ * magic.set_parameter( integer, integer ) -> nil
397
+ */
398
+ VALUE
399
+ rb_mgc_set_parameter(VALUE object, VALUE tag, VALUE value)
400
+ {
401
+ int local_errno;
402
+ magic_object_t *mo;
403
+ magic_arguments_t ma;
404
+
405
+ MAGIC_CHECK_INTEGER_TYPE(tag);
406
+ MAGIC_CHECK_INTEGER_TYPE(value);
407
+ MAGIC_CHECK_OPEN(object);
408
+ MAGIC_COOKIE(mo, ma.cookie);
409
+
410
+ ma.type.parameter.tag = NUM2INT(tag);
411
+ ma.type.parameter.value = NUM2SIZET(value);
412
+
413
+ MAGIC_SYNCHRONIZED(magic_set_parameter_internal, &ma);
414
+ local_errno = errno;
415
+
416
+ if (ma.status < 0) {
417
+ switch (local_errno) {
418
+ case EINVAL:
419
+ MAGIC_GENERIC_ERROR(rb_mgc_eParameterError,
420
+ local_errno,
421
+ E_PARAM_INVALID_TYPE);
422
+ case EOVERFLOW:
423
+ MAGIC_GENERIC_ERROR(rb_mgc_eParameterError,
424
+ local_errno,
425
+ E_PARAM_INVALID_VALUE);
426
+ }
427
+ MAGIC_LIBRARY_ERROR(ma.cookie);
428
+ }
429
+
430
+ return Qnil;
431
+ }
432
+
433
+ /*
434
+ * call-seq:
435
+ * magic.flags -> integer
333
436
  *
334
437
  * Example:
335
438
  *
336
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
439
+ * magic = Magic.new
440
+ * magic.flags #=> 0
441
+ * magic.flags = Magic::MIME #=> 1040
442
+ * magic.flags #=> 1040
337
443
  *
338
- * Will raise <i>Magic::LibraryError</i> exception if, or
339
- *
340
- * See also: Magic#check, Magic::check and Magic::compile
444
+ * See also: Magic#flags_to_a
341
445
  */
342
446
  VALUE
343
- rb_mgc_compile(VALUE object, VALUE arguments)
447
+ rb_mgc_get_flags(VALUE object)
344
448
  {
345
- magic_arguments_t ma;
346
- VALUE value = Qnil;
449
+ int local_errno;
450
+ magic_object_t *mo;
451
+ magic_arguments_t ma;
347
452
 
348
- CHECK_MAGIC_OPEN(object);
349
- MAGIC_COOKIE(ma.cookie);
453
+ MAGIC_CHECK_OPEN(object);
454
+ MAGIC_COOKIE(mo, ma.cookie);
350
455
 
351
- if (!RARRAY_EMPTY_P(arguments)) {
352
- value = magic_join(arguments, CSTR2RVAL(":"));
353
- }
354
- else {
355
- value = magic_join(rb_mgc_get_path(object), CSTR2RVAL(":"));
356
- }
456
+ MAGIC_SYNCHRONIZED(magic_get_flags_internal, &ma);
457
+ local_errno = errno;
357
458
 
358
- ma.flags = NUM2INT(rb_mgc_get_flags(object));
359
- ma.data.file.path = RVAL2CSTR(value);
459
+ if (ma.flags < 0 && local_errno == ENOSYS)
460
+ return rb_ivar_get(object, id_at_flags);
360
461
 
361
- if (!MAGIC_SYNCHRONIZED(magic_compile_internal, &ma)) {
362
- MAGIC_LIBRARY_ERROR(ma.cookie);
363
- }
364
-
365
- return Qtrue;
462
+ return INT2NUM(ma.flags);
366
463
  }
367
464
 
368
465
  /*
369
466
  * call-seq:
370
- * magic.check -> true or false
371
- * magic.check( path, ... ) -> true or false
372
- * magic.check( array ) -> true or false
467
+ * magic.flags= ( integer ) -> integer
373
468
  *
374
469
  * Example:
375
470
  *
376
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
471
+ * magic = Magic.new
472
+ * magic.flags = Magic::MIME #=> 1040
473
+ * magic.flags = Magic::MIME_TYPE #=> 16
474
+ */
475
+ VALUE
476
+ rb_mgc_set_flags(VALUE object, VALUE value)
477
+ {
478
+ int local_errno;
479
+ magic_object_t *mo;
480
+ magic_arguments_t ma;
481
+
482
+ MAGIC_CHECK_INTEGER_TYPE(value);
483
+ MAGIC_CHECK_OPEN(object);
484
+ MAGIC_COOKIE(mo, ma.cookie);
485
+
486
+ ma.flags = NUM2INT(value);
487
+
488
+ MAGIC_SYNCHRONIZED(magic_set_flags_internal, &ma);
489
+ local_errno = errno;
490
+
491
+ if (ma.status < 0) {
492
+ switch (local_errno) {
493
+ case EINVAL:
494
+ MAGIC_GENERIC_ERROR(rb_mgc_eFlagsError,
495
+ local_errno,
496
+ E_FLAG_INVALID_TYPE);
497
+ case ENOSYS:
498
+ MAGIC_GENERIC_ERROR(rb_mgc_eNotImplementedError,
499
+ local_errno,
500
+ E_FLAG_NOT_IMPLEMENTED);
501
+ }
502
+ MAGIC_LIBRARY_ERROR(ma.cookie);
503
+ }
504
+
505
+ return rb_ivar_set(object, id_at_flags, INT2NUM(ma.flags));
506
+ }
507
+
508
+ /*
509
+ * call-seq:
510
+ * magic.load -> nil
511
+ * magic.load( string, ... ) -> nil
512
+ * magic.load( array ) -> nil
377
513
  *
378
- * Will raise <i>Magic::LibraryError</i> exception if, or
514
+ * Example:
379
515
  *
380
- * See also: Magic#compile, Magic::compile and Magic::check
516
+ * See also: Magic#check, Magic#compile, Magic::check and Magic::compile
381
517
  */
382
518
  VALUE
383
- rb_mgc_check(VALUE object, VALUE arguments)
519
+ rb_mgc_load(VALUE object, VALUE arguments)
384
520
  {
385
- magic_arguments_t ma;
386
- VALUE value = Qnil;
387
-
388
- CHECK_MAGIC_OPEN(object);
389
- MAGIC_COOKIE(ma.cookie);
390
-
391
- if (!RARRAY_EMPTY_P(arguments)) {
392
- value = magic_join(arguments, CSTR2RVAL(":"));
393
- }
394
- else {
395
- value = magic_join(rb_mgc_get_path(object), CSTR2RVAL(":"));
396
- }
397
-
398
- ma.flags = NUM2INT(rb_mgc_get_flags(object));
399
- ma.data.file.path = RVAL2CSTR(value);
400
-
401
- if (!MAGIC_SYNCHRONIZED(magic_check_internal, &ma)) {
402
- return Qfalse;
403
- }
521
+ magic_object_t *mo;
522
+ magic_arguments_t ma;
523
+ const char *klass = "Magic";
524
+ VALUE value = Qundef;
525
+
526
+ if (ARRAY_P(RARRAY_FIRST(arguments)))
527
+ arguments = magic_flatten(arguments);
528
+
529
+ MAGIC_CHECK_ARRAY_OF_STRINGS(arguments);
530
+ MAGIC_CHECK_OPEN(object);
531
+ MAGIC_COOKIE(mo, ma.cookie);
532
+
533
+ if (rb_mgc_do_not_auto_load) {
534
+ if (!NIL_P(object))
535
+ klass = rb_obj_classname(object);
536
+
537
+ MAGIC_WARNING(2, "%s::do_not_auto_load is set; using %s#load "
538
+ "will load Magic database from a file",
539
+ klass, klass);
540
+ }
541
+
542
+ ma.flags = magic_flags(object);
543
+
544
+ if (!RARRAY_EMPTY_P(arguments)) {
545
+ value = magic_join(arguments, CSTR2RVAL(":"));
546
+ ma.type.file.path = RVAL2CSTR(value);
547
+ }
548
+ else
549
+ ma.type.file.path = magic_getpath_wrapper();
550
+
551
+ magic_set_paths(object, RARRAY_EMPTY);
552
+
553
+ MAGIC_SYNCHRONIZED(magic_load_internal, &ma);
554
+ if (ma.status < 0) {
555
+ mo->database_loaded = 0;
556
+ MAGIC_LIBRARY_ERROR(ma.cookie);
557
+ }
558
+ mo->database_loaded = 1;
559
+
560
+ value = magic_split(CSTR2RVAL(ma.type.file.path), CSTR2RVAL(":"));
561
+ magic_set_paths(object, value);
562
+ RB_GC_GUARD(value);
563
+
564
+ return Qnil;
565
+ }
404
566
 
405
- return Qtrue;
567
+ /*
568
+ * call-seq:
569
+ * magic.load_buffers( string, ... ) -> nil
570
+ * magic.load_buffers( array ) -> nil
571
+ *
572
+ * See also: Magic#load and Magic::do_not_auto_load
573
+ */
574
+ VALUE
575
+ rb_mgc_load_buffers(VALUE object, VALUE arguments)
576
+ {
577
+ size_t count;
578
+ int local_errno;
579
+ magic_object_t *mo;
580
+ magic_arguments_t ma;
581
+ void **pointers = NULL;
582
+ size_t *sizes = NULL;
583
+ VALUE value = Qundef;
584
+
585
+ count = (size_t)RARRAY_LEN(arguments);
586
+ MAGIC_CHECK_ARGUMENT_MISSING(count, 1);
587
+
588
+ if (ARRAY_P(RARRAY_FIRST(arguments))) {
589
+ arguments = magic_flatten(arguments);
590
+ count = (size_t)RARRAY_LEN(arguments);
591
+ }
592
+
593
+ MAGIC_CHECK_ARRAY_EMPTY(arguments);
594
+ MAGIC_CHECK_ARRAY_OF_STRINGS(arguments);
595
+ MAGIC_CHECK_OPEN(object);
596
+ MAGIC_COOKIE(mo, ma.cookie);
597
+
598
+ pointers = ALLOC_N(void *, count);
599
+ if (!pointers) {
600
+ local_errno = ENOMEM;
601
+ goto error;
602
+ }
603
+
604
+ sizes = ALLOC_N(size_t, count);
605
+ if (!sizes) {
606
+ ruby_xfree(pointers);
607
+ local_errno = ENOMEM;
608
+ goto error;
609
+ }
610
+
611
+ for (size_t i = 0; i < count; i++) {
612
+ value = RARRAY_AREF(arguments, (long)i);
613
+ pointers[i] = (void *)RSTRING_PTR(value);
614
+ sizes[i] = (size_t)RSTRING_LEN(value);
615
+ }
616
+
617
+ ma.flags = magic_flags(object);
618
+ ma.type.buffers.count = count;
619
+ ma.type.buffers.pointers = pointers;
620
+ ma.type.buffers.sizes = sizes;
621
+
622
+ magic_set_paths(object, RARRAY_EMPTY);
623
+
624
+ MAGIC_SYNCHRONIZED(magic_load_buffers_internal, &ma);
625
+ if (ma.status < 0) {
626
+ local_errno = errno;
627
+ ruby_xfree(pointers);
628
+ ruby_xfree(sizes);
629
+ goto error;
630
+ }
631
+ mo->database_loaded = 1;
632
+
633
+ ruby_xfree(pointers);
634
+ ruby_xfree(sizes);
635
+
636
+ return Qnil;
637
+ error:
638
+ mo->database_loaded = 0;
639
+
640
+ if (local_errno == ENOMEM)
641
+ MAGIC_GENERIC_ERROR(rb_mgc_eLibraryError,
642
+ local_errno,
643
+ E_NOT_ENOUGH_MEMORY);
644
+
645
+ MAGIC_LIBRARY_ERROR(ma.cookie);
406
646
  }
407
647
 
408
648
  /*
409
649
  * call-seq:
410
- * magic.file( path ) -> string or array
650
+ * magic.loaded? -> true or false
411
651
  *
412
- * Returns
652
+ * Returns +true+ if at least a single Magic database file had been loaded, or
653
+ * +false+ otherwise. Magic database files can be loaded from a file or from an
654
+ * in-memory buffer.
413
655
  *
414
656
  * Example:
415
657
  *
416
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
658
+ * magic = Magic.new
659
+ * magic.loaded? #=> true
417
660
  *
418
- * Will raise <i>Magic::LibraryError</i> exception if, or
661
+ * Example:
419
662
  *
420
- * See also: Magic#buffer and Magic#descriptor
663
+ * Magic.do_not_auto_load = true #=> true
664
+ * magic = Magic.new
665
+ * magic.loaded? #=> false
666
+ *
667
+ * See also: Magic#load and Magic#load_buffers
421
668
  */
422
669
  VALUE
423
- rb_mgc_file(VALUE object, VALUE value)
670
+ rb_mgc_load_p(VALUE object)
424
671
  {
425
- int rv;
426
- magic_arguments_t ma;
427
- const char *cstring = NULL;
428
- const char *empty = "(null)";
672
+ magic_object_t *mo;
429
673
 
430
- Check_Type(value, T_STRING);
674
+ MAGIC_CHECK_OPEN(object);
675
+ MAGIC_OBJECT(mo);
431
676
 
432
- CHECK_MAGIC_OPEN(object);
433
- MAGIC_COOKIE(ma.cookie);
677
+ return CBOOL2RVAL(mo->database_loaded);
678
+ }
434
679
 
435
- ma.flags = NUM2INT(rb_mgc_get_flags(object));
436
- ma.data.file.path = RVAL2CSTR(value);
680
+ /*
681
+ * call-seq:
682
+ * magic.compile( string ) -> nil
683
+ * magic.compile( array ) -> nil
684
+ *
685
+ * See also: Magic#check, Magic::check and Magic::compile
686
+ */
687
+ VALUE
688
+ rb_mgc_compile(VALUE object, VALUE value)
689
+ {
690
+ magic_object_t *mo;
691
+ magic_arguments_t ma;
437
692
 
438
- cstring = (const char *)MAGIC_SYNCHRONIZED(magic_file_internal, &ma);
439
- if (!cstring) {
440
- rv = magic_version_wrapper();
693
+ MAGIC_CHECK_STRING_TYPE(value);
694
+ MAGIC_CHECK_OPEN(object);
695
+ MAGIC_COOKIE(mo, ma.cookie);
441
696
 
442
- if (ma.flags & MAGIC_ERROR) {
443
- MAGIC_LIBRARY_ERROR(ma.cookie);
444
- }
445
- else if (rv < 515) {
446
- (void)magic_errno(ma.cookie);
447
- cstring = magic_error(ma.cookie);
448
- }
449
- }
697
+ ma.flags = magic_flags(object);
698
+ ma.type.file.path = RVAL2CSTR(value);
450
699
 
451
- assert(cstring != NULL && "Must be a valid pointer to `const char' type");
452
- assert(strncmp(cstring, empty, strlen(empty)) != 0 && \
453
- "Empty or invalid result");
700
+ MAGIC_SYNCHRONIZED(magic_compile_internal, &ma);
701
+ if (ma.status < 0)
702
+ MAGIC_LIBRARY_ERROR(ma.cookie);
454
703
 
455
- return magic_return(CSTR2RVAL(cstring), &ma);
704
+ return Qnil;
456
705
  }
457
706
 
458
707
  /*
459
708
  * call-seq:
460
- * magic.buffer( string ) -> string or array
461
- *
462
- * Returns
463
- *
464
- * Example:
709
+ * magic.check( string ) -> true or false
710
+ * magic.check( array ) -> true or false
465
711
  *
466
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
712
+ * See also: Magic#compile, Magic::compile and Magic::check
713
+ */
714
+ VALUE
715
+ rb_mgc_check(VALUE object, VALUE value)
716
+ {
717
+ magic_object_t *mo;
718
+ magic_arguments_t ma;
719
+
720
+ MAGIC_CHECK_STRING_TYPE(value);
721
+ MAGIC_CHECK_OPEN(object);
722
+ MAGIC_COOKIE(mo, ma.cookie);
723
+
724
+ ma.flags = magic_flags(object);
725
+ ma.type.file.path = RVAL2CSTR(value);
726
+
727
+ MAGIC_SYNCHRONIZED(magic_check_internal, &ma);
728
+ return ma.status < 0 ? Qfalse : Qtrue;
729
+ }
730
+
731
+ /*
732
+ * call-seq:
733
+ * magic.file( object ) -> string or array
734
+ * magic.file( string ) -> string or array
467
735
  *
468
- * Will raise <i>Magic::LibraryError</i> exception if, or
736
+ * See also: Magic#buffer and Magic#descriptor
737
+ */
738
+ VALUE
739
+ rb_mgc_file(VALUE object, VALUE value)
740
+ {
741
+ magic_object_t *mo;
742
+ magic_arguments_t ma;
743
+ const char *empty = "(null)";
744
+
745
+ if (NIL_P(value))
746
+ goto error;
747
+
748
+ MAGIC_CHECK_OPEN(object);
749
+ MAGIC_CHECK_LOADED(object);
750
+ MAGIC_COOKIE(mo, ma.cookie);
751
+
752
+ if (rb_respond_to(value, rb_intern("to_io")))
753
+ return rb_mgc_descriptor(object, value);
754
+
755
+ value = magic_path(value);
756
+ if (NIL_P(value))
757
+ goto error;
758
+
759
+ ma.stop_on_errors = mo->stop_on_errors;
760
+ ma.flags = magic_flags(object);
761
+ ma.type.file.path = RVAL2CSTR(value);
762
+
763
+ MAGIC_SYNCHRONIZED(magic_file_internal, &ma);
764
+ if (!ma.result) {
765
+ /*
766
+ * Handle the case when the "ERROR" flag is set regardless of the
767
+ * current version of the underlying Magic library.
768
+ *
769
+ * Prior to version 5.15 the correct behavior that concerns the
770
+ * following IEEE 1003.1 standards was broken:
771
+ *
772
+ * http://pubs.opengroup.org/onlinepubs/007904975/utilities/file.html
773
+ * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/file.html
774
+ *
775
+ * This is an attempt to mitigate the problem and correct it to achieve
776
+ * the desired behavior as per the standards.
777
+ */
778
+ if (mo->stop_on_errors || (ma.flags & MAGIC_ERROR))
779
+ MAGIC_LIBRARY_ERROR(ma.cookie);
780
+ else
781
+ ma.result = magic_error_wrapper(ma.cookie);
782
+ }
783
+ if (!ma.result)
784
+ MAGIC_GENERIC_ERROR(rb_mgc_eMagicError, EINVAL, E_UNKNOWN);
785
+
786
+ assert(ma.result != NULL && \
787
+ "Must be a valid pointer to `const char' type");
788
+
789
+ /*
790
+ * Depending on the version of the underlying Magic library the magic_file()
791
+ * function can fail and either yield no results or return the "(null)"
792
+ * string instead. Often this would indicate that an older version of the
793
+ * Magic library is in use.
794
+ */
795
+ assert(strncmp(ma.result, empty, strlen(empty)) != 0 && \
796
+ "Empty or invalid result");
797
+
798
+ return magic_return(&ma);
799
+ error:
800
+ MAGIC_ARGUMENT_TYPE_ERROR(value, "String or IO-like object");
801
+ }
802
+
803
+ /*
804
+ * call-seq:
805
+ * magic.buffer( string ) -> string or array
469
806
  *
470
807
  * See also: Magic#file and Magic#descriptor
471
808
  */
472
809
  VALUE
473
810
  rb_mgc_buffer(VALUE object, VALUE value)
474
811
  {
475
- magic_arguments_t ma;
476
- const char *cstring = NULL;
812
+ magic_object_t *mo;
813
+ magic_arguments_t ma;
477
814
 
478
- Check_Type(value, T_STRING);
815
+ MAGIC_CHECK_STRING_TYPE(value);
816
+ MAGIC_CHECK_OPEN(object);
817
+ MAGIC_CHECK_LOADED(object);
818
+ MAGIC_COOKIE(mo, ma.cookie);
479
819
 
480
- CHECK_MAGIC_OPEN(object);
481
- MAGIC_COOKIE(ma.cookie);
820
+ StringValue(value);
482
821
 
483
- ma.flags = NUM2INT(rb_mgc_get_flags(object));
822
+ ma.flags = magic_flags(object);
823
+ ma.type.buffers.pointers = (void **)RSTRING_PTR(value);
824
+ ma.type.buffers.sizes = (size_t *)RSTRING_LEN(value);
484
825
 
485
- ma.data.buffer.size = RSTRING_LEN(value);
486
- ma.data.buffer.buffer = RVAL2CSTR(value);
826
+ MAGIC_SYNCHRONIZED(magic_buffer_internal, &ma);
827
+ if (!ma.result)
828
+ MAGIC_LIBRARY_ERROR(ma.cookie);
487
829
 
488
- cstring = (const char *)MAGIC_SYNCHRONIZED(magic_buffer_internal, &ma);
489
- if (!cstring) {
490
- MAGIC_LIBRARY_ERROR(ma.cookie);
491
- }
830
+ assert(ma.result != NULL && \
831
+ "Must be a valid pointer to `const char' type");
492
832
 
493
- return magic_return(CSTR2RVAL(cstring), &ma);
833
+ return magic_return(&ma);
494
834
  }
495
835
 
496
836
  /*
497
837
  * call-seq:
838
+ * magic.descriptor( object ) -> string or array
498
839
  * magic.descriptor( integer ) -> string or array
499
840
  *
500
- * Returns
501
- *
502
- * Example:
503
- *
504
- * magic = Magic.new #=> #<Magic:0x007f8fdc012e58>
505
- *
506
- * Will raise <i>Magic::LibraryError</i> exception if, or
507
- *
508
841
  * See also: Magic#file and Magic#buffer
509
842
  */
510
843
  VALUE
511
844
  rb_mgc_descriptor(VALUE object, VALUE value)
512
845
  {
513
- magic_arguments_t ma;
514
- const char *cstring = NULL;
846
+ int local_errno;
847
+ magic_object_t *mo;
848
+ magic_arguments_t ma;
849
+
850
+ if (rb_respond_to(value, rb_intern("to_io")))
851
+ value = INT2NUM(magic_fileno(value));
852
+
853
+ MAGIC_CHECK_INTEGER_TYPE(value);
854
+ MAGIC_CHECK_OPEN(object);
855
+ MAGIC_CHECK_LOADED(object);
856
+ MAGIC_COOKIE(mo, ma.cookie);
515
857
 
516
- Check_Type(value, T_FIXNUM);
858
+ ma.flags = magic_flags(object);
859
+ ma.type.file.fd = NUM2INT(value);
517
860
 
518
- CHECK_MAGIC_OPEN(object);
519
- MAGIC_COOKIE(ma.cookie);
861
+ MAGIC_SYNCHRONIZED(magic_descriptor_internal, &ma);
862
+ local_errno = errno;
520
863
 
521
- ma.flags = NUM2INT(rb_mgc_get_flags(object));
522
- ma.data.file.fd = NUM2INT(value);
864
+ if (!ma.result) {
865
+ if (local_errno == EBADF)
866
+ rb_raise(rb_eIOError, "Bad file descriptor");
523
867
 
524
- cstring = (const char *)MAGIC_SYNCHRONIZED(magic_descriptor_internal, &ma);
525
- if (!cstring) {
526
- MAGIC_LIBRARY_ERROR(ma.cookie);
527
- }
868
+ MAGIC_LIBRARY_ERROR(ma.cookie);
869
+ }
528
870
 
529
- return magic_return(CSTR2RVAL(cstring), &ma);
871
+ assert(ma.result != NULL && \
872
+ "Must be a valid pointer to `const char' type");
873
+
874
+ return magic_return(&ma);
530
875
  }
531
876
 
532
877
  /*
533
878
  * call-seq:
534
879
  * Magic.version -> integer
535
880
  *
536
- * Returns
537
- *
538
881
  * Example:
539
882
  *
540
- * Magic.version #=> 517
541
- *
542
- * Will raise <i>Magic::NotImplementedError</i> exception if, or
883
+ * Magic.version #=> 517
543
884
  *
544
885
  * See also: Magic::version_to_a and Magic::version_to_s
545
886
  */
546
887
  VALUE
547
- rb_mgc_version(VALUE object)
888
+ rb_mgc_version(RB_UNUSED_VAR(VALUE object))
548
889
  {
549
- int rv;
550
- int local_errno;
551
-
552
- UNUSED(object);
553
-
554
- rv = magic_version_wrapper();
555
- local_errno = errno;
556
-
557
- if (rv < 0 && local_errno == ENOSYS) {
558
- MAGIC_GENERIC_ERROR(rb_mgc_eNotImplementedError, ENOSYS,
559
- error(E_NOT_IMPLEMENTED));
560
- }
561
-
562
- return INT2NUM(rv);
890
+ return INT2NUM(magic_version_wrapper());
563
891
  }
564
892
 
565
- /* :stopdoc: */
566
-
567
893
  static inline void*
568
894
  nogvl_magic_load(void *data)
569
895
  {
570
- int rv;
571
- magic_arguments_t *ma = data;
896
+ magic_arguments_t *ma = data;
572
897
 
573
- rv = magic_load_wrapper(ma->cookie, ma->data.file.path, ma->flags);
574
- return rv < 0 ? NULL : data;
898
+ ma->status = magic_load_wrapper(ma->cookie,
899
+ ma->type.file.path,
900
+ ma->flags);
901
+ return NULL;
575
902
  }
576
903
 
577
904
  static inline void*
578
905
  nogvl_magic_compile(void *data)
579
906
  {
580
- int rv;
581
- magic_arguments_t *ma = data;
907
+ magic_arguments_t *ma = data;
582
908
 
583
- rv = magic_compile_wrapper(ma->cookie, ma->data.file.path, ma->flags);
584
- return rv < 0 ? NULL : data;
909
+ ma->status = magic_compile_wrapper(ma->cookie,
910
+ ma->type.file.path,
911
+ ma->flags);
912
+ return NULL;
585
913
  }
586
914
 
587
915
  static inline void*
588
916
  nogvl_magic_check(void *data)
589
917
  {
590
- int rv;
591
- magic_arguments_t *ma = data;
918
+ magic_arguments_t *ma = data;
592
919
 
593
- rv = magic_check_wrapper(ma->cookie, ma->data.file.path, ma->flags);
594
- return rv < 0 ? NULL : data;
920
+ ma->status = magic_check_wrapper(ma->cookie,
921
+ ma->type.file.path,
922
+ ma->flags);
923
+ return NULL;
595
924
  }
596
925
 
597
926
  static inline void*
598
927
  nogvl_magic_file(void *data)
599
928
  {
600
- magic_arguments_t *ma = data;
601
- return (void *)magic_file_wrapper(ma->cookie, ma->data.file.path, ma->flags);
929
+ magic_arguments_t *ma = data;
930
+
931
+ ma->result = magic_file_wrapper(ma->cookie,
932
+ ma->type.file.path,
933
+ ma->flags);
934
+ return NULL;
602
935
  }
603
936
 
604
937
  static inline void*
605
938
  nogvl_magic_descriptor(void *data)
606
939
  {
607
- magic_arguments_t *ma = data;
608
- return (void *)magic_descriptor_wrapper(ma->cookie, ma->data.file.fd, ma->flags);
940
+ magic_arguments_t *ma = data;
941
+
942
+ ma->result = magic_descriptor_wrapper(ma->cookie,
943
+ ma->type.file.fd,
944
+ ma->flags);
945
+ return NULL;
946
+ }
947
+
948
+ static inline VALUE
949
+ magic_get_parameter_internal(void *data)
950
+ {
951
+ size_t value;
952
+ magic_arguments_t *ma = data;
953
+
954
+ ma->status = magic_getparam_wrapper(ma->cookie,
955
+ ma->type.parameter.tag,
956
+ &value);
957
+ ma->type.parameter.value = value;
958
+ return (VALUE)NULL;
959
+ }
960
+
961
+ static inline VALUE
962
+ magic_set_parameter_internal(void *data)
963
+ {
964
+ size_t value;
965
+ magic_arguments_t *ma = data;
966
+
967
+ value = ma->type.parameter.value;
968
+ ma->status = magic_setparam_wrapper(ma->cookie,
969
+ ma->type.parameter.tag,
970
+ &value);
971
+ return (VALUE)NULL;
972
+ }
973
+
974
+ static inline VALUE
975
+ magic_get_flags_internal(void *data)
976
+ {
977
+ magic_arguments_t *ma = data;
978
+
979
+ ma->flags = magic_getflags_wrapper(ma->cookie);
980
+ return (VALUE)NULL;
981
+ }
982
+
983
+ static inline VALUE
984
+ magic_set_flags_internal(void *data)
985
+ {
986
+ magic_arguments_t *ma = data;
987
+
988
+ ma->status = magic_setflags_wrapper(ma->cookie, ma->flags);
989
+ return (VALUE)NULL;
609
990
  }
610
991
 
611
992
  static inline VALUE
612
993
  magic_close_internal(void *data)
613
994
  {
614
- magic_free(data);
615
- return Qnil;
995
+ magic_library_close(data);
996
+ return Qnil;
616
997
  }
617
998
 
618
999
  static inline VALUE
619
1000
  magic_load_internal(void *data)
620
1001
  {
621
- return (VALUE)NOGVL(nogvl_magic_load, data);
1002
+ return (VALUE)NOGVL(nogvl_magic_load, data);
1003
+ }
1004
+
1005
+ static inline VALUE
1006
+ magic_load_buffers_internal(void *data)
1007
+ {
1008
+ magic_arguments_t *ma = data;
1009
+
1010
+ ma->status = magic_load_buffers_wrapper(ma->cookie,
1011
+ ma->type.buffers.pointers,
1012
+ ma->type.buffers.sizes,
1013
+ ma->type.buffers.count,
1014
+ ma->flags);
1015
+ return (VALUE)NULL;
622
1016
  }
623
1017
 
624
1018
  static inline VALUE
625
1019
  magic_compile_internal(void *data)
626
1020
  {
627
- return (VALUE)NOGVL(nogvl_magic_compile, data);
1021
+ return (VALUE)NOGVL(nogvl_magic_compile, data);
628
1022
  }
629
1023
 
630
1024
  static inline VALUE
631
1025
  magic_check_internal(void *data)
632
1026
  {
633
- return (VALUE)NOGVL(nogvl_magic_check, data);
1027
+ return (VALUE)NOGVL(nogvl_magic_check, data);
634
1028
  }
635
1029
 
636
- static inline VALUE
1030
+ static VALUE
637
1031
  magic_file_internal(void *data)
638
1032
  {
639
- return (VALUE)NOGVL(nogvl_magic_file, data);
1033
+ int local_errno;
1034
+ int old_flags = 0;
1035
+ int restore_flags = 0;
1036
+ magic_arguments_t *ma = data;
1037
+
1038
+ if (ma->stop_on_errors) {
1039
+ old_flags = ma->flags;
1040
+ ma->flags |= MAGIC_ERROR;
1041
+ restore_flags = 1;
1042
+ }
1043
+ if (ma->flags & MAGIC_CONTINUE) {
1044
+ old_flags = ma->flags;
1045
+ ma->flags |= MAGIC_RAW;
1046
+ restore_flags = 1;
1047
+ }
1048
+ if (restore_flags && ma->flags)
1049
+ magic_setflags_wrapper(ma->cookie, ma->flags);
1050
+
1051
+ NOGVL(nogvl_magic_file, ma);
1052
+ local_errno = errno;
1053
+ /*
1054
+ * The Magic library often does not correctly report errors,
1055
+ * especially when certain flags (such as e.g., MAGIC_EXTENSION,
1056
+ * etc.) are set. Attempt to obtain an error code first from the
1057
+ * Magic library itself, and if that does not work, then from
1058
+ * the saved errno value.
1059
+ */
1060
+ if (magic_errno_wrapper(ma->cookie))
1061
+ ma->status = -1;
1062
+ else if (local_errno)
1063
+ ma->status = -1;
1064
+
1065
+ if (restore_flags && old_flags)
1066
+ magic_setflags_wrapper(ma->cookie, old_flags);
1067
+
1068
+ return (VALUE)NULL;
640
1069
  }
641
1070
 
642
- static inline VALUE
1071
+ static VALUE
643
1072
  magic_buffer_internal(void *data)
644
1073
  {
645
- magic_arguments_t *ma = data;
646
- return (VALUE)magic_buffer_wrapper(ma->cookie, ma->data.buffer.buffer,
647
- ma->data.buffer.size, ma->flags);
1074
+ int old_flags = 0;
1075
+ int restore_flags = 0;
1076
+ magic_arguments_t *ma = data;
1077
+
1078
+ if (ma->flags & MAGIC_CONTINUE) {
1079
+ old_flags = ma->flags;
1080
+ ma->flags |= MAGIC_RAW;
1081
+ restore_flags = 1;
1082
+ }
1083
+ if (restore_flags && ma->flags)
1084
+ magic_setflags_wrapper(ma->cookie, ma->flags);
1085
+
1086
+ ma->result = magic_buffer_wrapper(ma->cookie,
1087
+ (const void *)ma->type.buffers.pointers,
1088
+ (size_t)ma->type.buffers.sizes,
1089
+ ma->flags);
1090
+ if (restore_flags && old_flags)
1091
+ magic_setflags_wrapper(ma->cookie, old_flags);
1092
+
1093
+ return (VALUE)NULL;
648
1094
  }
649
1095
 
650
- static inline VALUE
1096
+ static VALUE
651
1097
  magic_descriptor_internal(void *data)
652
1098
  {
653
- return (VALUE)NOGVL(nogvl_magic_descriptor, data);
1099
+ int old_flags = 0;
1100
+ int restore_flags = 0;
1101
+ magic_arguments_t *ma = data;
1102
+
1103
+ if (ma->flags & MAGIC_CONTINUE) {
1104
+ old_flags = ma->flags;
1105
+ ma->flags |= MAGIC_RAW;
1106
+ restore_flags = 1;
1107
+ }
1108
+ if (restore_flags && ma->flags)
1109
+ magic_setflags_wrapper(ma->cookie, ma->flags);
1110
+
1111
+ NOGVL(nogvl_magic_descriptor, ma);
1112
+
1113
+ if (restore_flags && old_flags)
1114
+ magic_setflags_wrapper(ma->cookie, old_flags);
1115
+
1116
+ return (VALUE)NULL;
654
1117
  }
655
1118
 
656
1119
  static VALUE
657
1120
  magic_allocate(VALUE klass)
658
1121
  {
659
- magic_t cookie;
1122
+ int local_errno;
1123
+ magic_object_t *mo;
1124
+
1125
+ mo = (magic_object_t *)ruby_xmalloc(sizeof(magic_object_t));
1126
+ local_errno = ENOMEM;
1127
+
1128
+ if (!mo) {
1129
+ errno = local_errno;
1130
+ MAGIC_GENERIC_ERROR(rb_mgc_eLibraryError,
1131
+ local_errno,
1132
+ E_NOT_ENOUGH_MEMORY);
1133
+ }
1134
+
1135
+ mo->cookie = NULL;
1136
+ mo->mutex = Qundef;
1137
+ mo->database_loaded = 0;
1138
+ mo->stop_on_errors = 0;
1139
+
1140
+ mo->cookie = magic_open_wrapper(MAGIC_NONE);
1141
+ local_errno = ENOMEM;
1142
+
1143
+ if (!mo->cookie) {
1144
+ ruby_xfree(mo);
1145
+ mo = NULL;
1146
+ errno = local_errno;
1147
+ MAGIC_GENERIC_ERROR(rb_mgc_eLibraryError,
1148
+ local_errno,
1149
+ E_MAGIC_LIBRARY_INITIALIZE);
1150
+ }
1151
+
1152
+ return Data_Wrap_Struct(klass, magic_mark, magic_free, mo);
1153
+ }
1154
+
1155
+ static inline void
1156
+ magic_library_close(void *data)
1157
+ {
1158
+ magic_object_t *mo = data;
1159
+
1160
+ assert(mo != NULL && \
1161
+ "Must be a valid pointer to `magic_object_t' type");
1162
+
1163
+ if (mo->cookie)
1164
+ magic_close_wrapper(mo->cookie);
1165
+
1166
+ mo->cookie = NULL;
1167
+ }
1168
+
1169
+ static inline void
1170
+ magic_mark(void *data)
1171
+ {
1172
+ magic_object_t *mo = data;
660
1173
 
661
- cookie = magic_open(MAGIC_NONE);
662
- if (!cookie) {
663
- MAGIC_GENERIC_ERROR(rb_mgc_eLibraryError, ENOMEM,
664
- error(E_MAGIC_LIBRARY_INITIALIZE));
665
- }
1174
+ assert(mo != NULL && \
1175
+ "Must be a valid pointer to `magic_object_t' type");
666
1176
 
667
- return Data_Wrap_Struct(klass, NULL, magic_free, cookie);
1177
+ rb_gc_mark(mo->mutex);
668
1178
  }
669
1179
 
670
- static void
1180
+ static inline void
671
1181
  magic_free(void *data)
672
1182
  {
673
- magic_t cookie = data;
674
- assert(cookie != NULL && "Must be a valid pointer to `magic_t' type");
1183
+ magic_object_t *mo = data;
1184
+
1185
+ assert(mo != NULL && \
1186
+ "Must be a valid pointer to `magic_object_t' type");
675
1187
 
676
- if (cookie) {
677
- magic_close(cookie);
678
- cookie = NULL;
679
- }
1188
+ if (mo->cookie)
1189
+ magic_library_close(data);
1190
+
1191
+ mo->cookie = NULL;
1192
+ mo->mutex = Qundef;
1193
+
1194
+ ruby_xfree(mo);
680
1195
  }
681
1196
 
682
- static VALUE
1197
+ static inline VALUE
683
1198
  magic_exception_wrapper(VALUE value)
684
1199
  {
685
- magic_exception_t *e = (struct magic_exception *)value;
686
- return rb_exc_new2(e->klass, e->magic_error);
1200
+ magic_exception_t *e = (struct magic_exception *)value;
1201
+
1202
+ return rb_exc_new2(e->klass, e->magic_error);
687
1203
  }
688
1204
 
689
1205
  static VALUE
690
1206
  magic_exception(void *data)
691
1207
  {
692
- int exception = 0;
693
- VALUE object = Qnil;
1208
+ magic_exception_t *e = data;
1209
+ int exception = 0;
1210
+ VALUE object = Qundef;
694
1211
 
695
- magic_exception_t *e = data;
696
- assert(e != NULL && "Must be a valid pointer to `magic_exception_t' type");
1212
+ assert(e != NULL && \
1213
+ "Must be a valid pointer to `magic_exception_t' type");
697
1214
 
698
- object = rb_protect(magic_exception_wrapper, (VALUE)e, &exception);
1215
+ object = rb_protect(magic_exception_wrapper, (VALUE)e, &exception);
699
1216
 
700
- if (exception) {
701
- rb_jump_tag(exception);
702
- }
1217
+ if (exception)
1218
+ rb_jump_tag(exception);
703
1219
 
704
- rb_iv_set(object, "@errno", INT2NUM(e->magic_errno));
1220
+ rb_iv_set(object, "@errno", INT2NUM(e->magic_errno));
1221
+ RB_GC_GUARD(object);
705
1222
 
706
- return object;
1223
+ return object;
707
1224
  }
708
1225
 
709
- static VALUE
1226
+ static inline VALUE
710
1227
  magic_generic_error(VALUE klass, int magic_errno, const char *magic_error)
711
1228
  {
712
- magic_exception_t e;
1229
+ magic_exception_t e;
713
1230
 
714
- e.magic_errno = magic_errno;
715
- e.magic_error = magic_error;
716
- e.klass = klass;
1231
+ e.magic_errno = magic_errno;
1232
+ e.magic_error = magic_error;
1233
+ e.klass = klass;
717
1234
 
718
- return magic_exception(&e);
1235
+ return magic_exception(&e);
719
1236
  }
720
1237
 
721
1238
  static VALUE
722
1239
  magic_library_error(VALUE klass, void *data)
723
1240
  {
724
- magic_exception_t e;
725
- const char *message = NULL;
726
- const char *empty = "(null)";
1241
+ magic_exception_t e;
1242
+ const char *message = NULL;
1243
+ const char *empty = "(null)";
1244
+ magic_t cookie = data;
727
1245
 
728
- magic_t cookie = data;
729
- assert(cookie != NULL && "Must be a valid pointer to `magic_t' type");
1246
+ assert(cookie != NULL && \
1247
+ "Must be a valid pointer to `magic_t' type");
730
1248
 
731
- e.magic_errno = -1;
732
- e.magic_error = error(E_UNKNOWN);
733
- e.klass = klass;
1249
+ e.magic_errno = -1;
1250
+ e.magic_error = error(E_UNKNOWN);
1251
+ e.klass = klass;
734
1252
 
735
- message = magic_error(cookie);
736
- if (message) {
737
- e.magic_errno = magic_errno(cookie);
738
- e.magic_error = message;
739
- }
1253
+ message = magic_error_wrapper(cookie);
1254
+ if (message) {
1255
+ e.magic_errno = magic_errno_wrapper(cookie);
1256
+ e.magic_error = message;
1257
+ }
740
1258
 
741
- assert(strncmp(e.magic_error, empty, strlen(empty)) != 0 && \
742
- "Empty or invalid error message");
1259
+ assert(strncmp(e.magic_error, empty, strlen(empty)) != 0 && \
1260
+ "Empty or invalid error message");
743
1261
 
744
- return magic_exception(&e);
1262
+ return magic_exception(&e);
745
1263
  }
746
1264
 
747
1265
  VALUE
748
1266
  magic_lock(VALUE object, VALUE(*function)(ANYARGS), void *data)
749
1267
  {
750
- VALUE mutex = rb_ivar_get(object, id_at_mutex);
751
- rb_funcall(mutex, rb_intern("lock"), 0);
752
- return rb_ensure(function, (VALUE)data, magic_unlock, object);
1268
+ magic_object_t *mo;
1269
+
1270
+ MAGIC_OBJECT(mo);
1271
+ rb_funcall(mo->mutex, rb_intern("lock"), 0, Qundef);
1272
+
1273
+ return rb_ensure(function, (VALUE)data, magic_unlock, object);
753
1274
  }
754
1275
 
755
1276
  VALUE
756
1277
  magic_unlock(VALUE object)
757
1278
  {
758
- VALUE mutex = rb_ivar_get(object, id_at_mutex);
759
- rb_funcall(mutex, rb_intern("unlock"), 0);
760
- return Qnil;
1279
+ magic_object_t *mo;
1280
+
1281
+ MAGIC_OBJECT(mo);
1282
+ rb_funcall(mo->mutex, rb_intern("unlock"), 0, Qundef);
1283
+
1284
+ return Qnil;
761
1285
  }
762
1286
 
763
1287
  static VALUE
764
- magic_return(VALUE value, void *data)
1288
+ magic_return(void *data)
765
1289
  {
766
- magic_arguments_t *ma = data;
767
- VALUE array = Qnil;
1290
+ magic_arguments_t *ma = data;
1291
+ const char *unknown = "???";
1292
+ VALUE separator = Qundef;
1293
+ VALUE array = Qundef;
1294
+ VALUE string = Qundef;
1295
+
1296
+ string = CSTR2RVAL(ma->result);
1297
+ RB_GC_GUARD(string);
1298
+
1299
+ /*
1300
+ * The value below is a field separator that can be used to split results
1301
+ * when the CONTINUE flag is set causing all valid matches found by the
1302
+ * Magic library to be returned.
1303
+ */
1304
+ if (ma->flags & MAGIC_CONTINUE)
1305
+ separator = CSTR2RVAL(MAGIC_CONTINUE_SEPARATOR);
1306
+
1307
+ if (ma->flags & MAGIC_EXTENSION) {
1308
+ /*
1309
+ * A possible I/O-related error has occurred, and there is very
1310
+ * little sense processing the results, so return string as-is.
1311
+ */
1312
+ if (ma->status < 0)
1313
+ return string;
1314
+ /*
1315
+ * A number of Magic flags that support primarily files e.g.,
1316
+ * MAGIC_EXTENSION, etc., would not return a meaningful value for
1317
+ * directories and special files, and such. Thus, it's better to
1318
+ * return an empty string, to indicate lack of results, rather
1319
+ * than a confusing string consisting of three questions marks.
1320
+ */
1321
+ if (strncmp(ma->result, unknown, strlen(unknown)) == 0)
1322
+ return CSTR2RVAL("");
1323
+
1324
+ separator = CSTR2RVAL(MAGIC_EXTENSION_SEPARATOR);
1325
+ }
1326
+
1327
+ if (ma->flags & (MAGIC_CONTINUE | MAGIC_EXTENSION)) {
1328
+ array = magic_split(string, separator);
1329
+ RB_GC_GUARD(array);
1330
+ return (RARRAY_LEN(array) > 1) ? array : magic_shift(array);
1331
+ }
1332
+
1333
+ return string;
1334
+ }
768
1335
 
769
- if (ma->flags & MAGIC_CONTINUE) {
770
- array = magic_split(value, CSTR2RVAL("\x5c\x30\x31\x32\x2d\x20"));
771
- return (NUM2INT(magic_size(array)) > 1) ? array : magic_shift(array);
772
- }
1336
+ static inline int
1337
+ magic_flags(VALUE object)
1338
+ {
1339
+ return NUM2INT(rb_ivar_get(object, id_at_flags));
1340
+ }
773
1341
 
774
- return value;
1342
+ static inline int
1343
+ magic_set_flags(VALUE object, VALUE value)
1344
+ {
1345
+ return NUM2INT(rb_ivar_set(object, id_at_flags, value));
775
1346
  }
776
1347
 
777
- /* :startdoc: */
1348
+ static inline VALUE
1349
+ magic_set_paths(VALUE object, VALUE value)
1350
+ {
1351
+ return rb_ivar_set(object, id_at_paths, value);
1352
+ }
778
1353
 
779
1354
  void
780
1355
  Init_magic(void)
781
1356
  {
782
- id_at_path = rb_intern("@path");
783
- id_at_flags = rb_intern("@flags");
784
- id_at_mutex = rb_intern("@mutex");
785
-
786
- rb_cMagic = rb_define_class("Magic", rb_cObject);
787
- rb_define_alloc_func(rb_cMagic, magic_allocate);
788
-
789
- /*
790
- * Raised when _Magic_ encounters an error.
791
- */
792
- rb_mgc_eError = rb_define_class_under(rb_cMagic, "Error", rb_eStandardError);
793
-
794
- /*
795
- * Stores current value of +errno+
796
- */
797
- rb_define_attr(rb_mgc_eError, "errno", 1, 0);
798
-
799
- /*
800
- * Raised when
801
- */
802
- rb_mgc_eMagicError = rb_define_class_under(rb_cMagic, "MagicError", rb_mgc_eError);
803
-
804
- /*
805
- * Raised when
806
- */
807
- rb_mgc_eLibraryError = rb_define_class_under(rb_cMagic, "LibraryError", rb_mgc_eError);
808
-
809
- /*
810
- * Raised when
811
- */
812
- rb_mgc_eFlagsError = rb_define_class_under(rb_cMagic, "FlagsError", rb_mgc_eError);
813
-
814
- /*
815
- * Raised when
816
- */
817
- rb_mgc_eNotImplementedError = rb_define_class_under(rb_cMagic, "NotImplementedError", rb_mgc_eError);
818
-
819
- rb_define_method(rb_cMagic, "initialize", RUBY_METHOD_FUNC(rb_mgc_initialize), -2);
820
-
821
- rb_define_method(rb_cMagic, "close", RUBY_METHOD_FUNC(rb_mgc_close), 0);
822
- rb_define_method(rb_cMagic, "closed?", RUBY_METHOD_FUNC(rb_mgc_closed), 0);
823
-
824
- rb_define_method(rb_cMagic, "path", RUBY_METHOD_FUNC(rb_mgc_get_path), 0);
825
- rb_define_method(rb_cMagic, "flags", RUBY_METHOD_FUNC(rb_mgc_get_flags), 0);
826
- rb_define_method(rb_cMagic, "flags=", RUBY_METHOD_FUNC(rb_mgc_set_flags), 1);
827
-
828
- rb_define_method(rb_cMagic, "file", RUBY_METHOD_FUNC(rb_mgc_file), 1);
829
- rb_define_method(rb_cMagic, "buffer", RUBY_METHOD_FUNC(rb_mgc_buffer), 1);
830
- rb_define_method(rb_cMagic, "descriptor", RUBY_METHOD_FUNC(rb_mgc_descriptor), 1);
831
-
832
- rb_define_method(rb_cMagic, "load", RUBY_METHOD_FUNC(rb_mgc_load), -2);
833
- rb_define_method(rb_cMagic, "compile", RUBY_METHOD_FUNC(rb_mgc_compile), -2);
834
- rb_define_method(rb_cMagic, "check", RUBY_METHOD_FUNC(rb_mgc_check), -2);
835
-
836
- rb_alias(rb_cMagic, rb_intern("valid?"), rb_intern("check"));
837
-
838
- rb_define_singleton_method(rb_cMagic, "version", RUBY_METHOD_FUNC(rb_mgc_version), 0);
839
-
840
- /*
841
- * No special handling and/or flags specified. Default behaviour.
842
- */
843
- rb_define_const(rb_cMagic, "NONE", INT2NUM(MAGIC_NONE));
844
-
845
- /*
846
- * Print debugging messages to standard error output.
847
- */
848
- rb_define_const(rb_cMagic, "DEBUG", INT2NUM(MAGIC_DEBUG));
849
-
850
- /*
851
- * If the file queried is a symbolic link, follow it.
852
- */
853
- rb_define_const(rb_cMagic, "SYMLINK", INT2NUM(MAGIC_SYMLINK));
854
-
855
- /*
856
- * If the file is compressed, unpack it and look at the contents.
857
- */
858
- rb_define_const(rb_cMagic, "COMPRESS", INT2NUM(MAGIC_COMPRESS));
859
-
860
- /*
861
- * If the file is a block or character special device, then open
862
- * the device and try to look at the contents.
863
- */
864
- rb_define_const(rb_cMagic, "DEVICES", INT2NUM(MAGIC_DEVICES));
865
-
866
- /*
867
- * Return a MIME type string, instead of a textual description.
868
- */
869
- rb_define_const(rb_cMagic, "MIME_TYPE", INT2NUM(MAGIC_MIME_TYPE));
870
-
871
- /*
872
- * Return all matches, not just the first.
873
- */
874
- rb_define_const(rb_cMagic, "CONTINUE", INT2NUM(MAGIC_CONTINUE));
875
-
876
- /*
877
- * Check the Magic database for consistency and print warnings to
878
- * standard error output.
879
- */
880
- rb_define_const(rb_cMagic, "CHECK", INT2NUM(MAGIC_CHECK));
881
-
882
- /*
883
- * Attempt to preserve access time (atime, utime or utimes) of the
884
- * file queried on systems that support such system calls.
885
- */
886
- rb_define_const(rb_cMagic, "PRESERVE_ATIME", INT2NUM(MAGIC_PRESERVE_ATIME));
887
-
888
- /*
889
- * Do not translate unprintable characters to an octal representation.
890
- */
891
- rb_define_const(rb_cMagic, "RAW", INT2NUM(MAGIC_RAW));
892
-
893
- /*
894
- * Treat operating system errors while trying to open files and follow
895
- * symbolic links as first class errors, instead of storing them in the
896
- * Magic library error buffer for retrieval later.
897
- */
898
- rb_define_const(rb_cMagic, "ERROR", INT2NUM(MAGIC_ERROR));
899
-
900
- /*
901
- * Return a MIME encoding, instead of a textual description.
902
- */
903
- rb_define_const(rb_cMagic, "MIME_ENCODING", INT2NUM(MAGIC_MIME_ENCODING));
904
-
905
- /*
906
- * A shorthand for using MIME_TYPE and MIME_ENCODING flags together.
907
- */
908
- rb_define_const(rb_cMagic, "MIME", INT2NUM(MAGIC_MIME));
909
-
910
- /*
911
- * Return the Apple creator and type.
912
- */
913
- rb_define_const(rb_cMagic, "APPLE", INT2NUM(MAGIC_APPLE));
914
-
915
- /*
916
- * Do not look for, or inside compressed files.
917
- */
918
- rb_define_const(rb_cMagic, "NO_CHECK_COMPRESS", INT2NUM(MAGIC_NO_CHECK_COMPRESS));
919
-
920
- /*
921
- * Do not look for, or inside tar archive files.
922
- */
923
- rb_define_const(rb_cMagic, "NO_CHECK_TAR", INT2NUM(MAGIC_NO_CHECK_TAR));
924
-
925
- /*
926
- * Do not consult Magic files.
927
- */
928
- rb_define_const(rb_cMagic, "NO_CHECK_SOFT", INT2NUM(MAGIC_NO_CHECK_SOFT));
929
-
930
- /*
931
- * Check for EMX application type (only supported on EMX).
932
- */
933
- rb_define_const(rb_cMagic, "NO_CHECK_APPTYPE", INT2NUM(MAGIC_NO_CHECK_APPTYPE));
934
-
935
- /*
936
- * Do not check for ELF files (do not examine ELF file details).
937
- */
938
- rb_define_const(rb_cMagic, "NO_CHECK_ELF", INT2NUM(MAGIC_NO_CHECK_ELF));
939
-
940
- /*
941
- * Do not check for various types of text files.
942
- */
943
- rb_define_const(rb_cMagic, "NO_CHECK_TEXT", INT2NUM(MAGIC_NO_CHECK_TEXT));
944
-
945
- /*
946
- * Do not check for CDF files.
947
- */
948
- rb_define_const(rb_cMagic, "NO_CHECK_CDF", INT2NUM(MAGIC_NO_CHECK_CDF));
949
-
950
- /*
951
- * Do not look for known tokens inside ASCII files.
952
- */
953
- rb_define_const(rb_cMagic, "NO_CHECK_TOKENS", INT2NUM(MAGIC_NO_CHECK_TOKENS));
954
-
955
- /*
956
- * Return a MIME encoding, instead of a textual description.
957
- */
958
- rb_define_const(rb_cMagic, "NO_CHECK_ENCODING", INT2NUM(MAGIC_NO_CHECK_ENCODING));
959
-
960
- /*
961
- * Do not use built-in tests; only consult the Magic file.
962
- */
963
- rb_define_const(rb_cMagic, "NO_CHECK_BUILTIN", INT2NUM(MAGIC_NO_CHECK_BUILTIN));
964
-
965
- /*
966
- * Do not check for various types of text files, same as NO_CHECK_TEXT.
967
- */
968
- rb_define_const(rb_cMagic, "NO_CHECK_ASCII", INT2NUM(MAGIC_NO_CHECK_ASCII));
969
-
970
- /*
971
- * Do not look for Fortran sequences inside ASCII files.
972
- */
973
- rb_define_const(rb_cMagic, "NO_CHECK_FORTRAN", INT2NUM(MAGIC_NO_CHECK_FORTRAN));
974
-
975
- /*
976
- * Do not look for troff sequences inside ASCII files.
977
- */
978
- rb_define_const(rb_cMagic, "NO_CHECK_TROFF", INT2NUM(MAGIC_NO_CHECK_TROFF));
979
- }
980
-
981
- /* :enddoc: */
1357
+ id_at_paths = rb_intern("@paths");
1358
+ id_at_flags = rb_intern("@flags");
1359
+
1360
+ rb_cMagic = rb_define_class("Magic", rb_cObject);
1361
+ rb_define_alloc_func(rb_cMagic, magic_allocate);
1362
+ /*
1363
+ * Raised when _Magic_ encounters an error.
1364
+ */
1365
+ rb_mgc_eError = rb_define_class_under(rb_cMagic, "Error", rb_eStandardError);
1366
+ /*
1367
+ * Stores current value of +errno+
1368
+ */
1369
+ rb_define_attr(rb_mgc_eError, "errno", 1, 0);
1370
+ /*
1371
+ * Raised when
1372
+ */
1373
+ rb_mgc_eMagicError = rb_define_class_under(rb_cMagic, "MagicError", rb_mgc_eError);
1374
+ /*
1375
+ * Raised when
1376
+ */
1377
+ rb_mgc_eLibraryError = rb_define_class_under(rb_cMagic, "LibraryError", rb_mgc_eError);
1378
+ /*
1379
+ * Raised when
1380
+ */
1381
+ rb_mgc_eParameterError = rb_define_class_under(rb_cMagic, "ParameterError", rb_mgc_eError);
1382
+ /*
1383
+ * Raised when
1384
+ */
1385
+ rb_mgc_eFlagsError = rb_define_class_under(rb_cMagic, "FlagsError", rb_mgc_eError);
1386
+ /*
1387
+ * Raised when
1388
+ */
1389
+ rb_mgc_eNotImplementedError = rb_define_class_under(rb_cMagic, "NotImplementedError", rb_mgc_eError);
1390
+
1391
+ rb_define_singleton_method(rb_cMagic, "do_not_auto_load", RUBY_METHOD_FUNC(rb_mgc_get_do_not_auto_load_global), 0);
1392
+ rb_define_singleton_method(rb_cMagic, "do_not_auto_load=", RUBY_METHOD_FUNC(rb_mgc_set_do_not_auto_load_global), 1);
1393
+
1394
+ rb_define_singleton_method(rb_cMagic, "do_not_stop_on_error", RUBY_METHOD_FUNC(rb_mgc_get_do_not_stop_on_error_global), 0);
1395
+ rb_define_singleton_method(rb_cMagic, "do_not_stop_on_error=", RUBY_METHOD_FUNC(rb_mgc_set_do_not_stop_on_error_global), 1);
1396
+
1397
+ rb_define_singleton_method(rb_cMagic, "version", RUBY_METHOD_FUNC(rb_mgc_version), 0);
1398
+
1399
+ rb_define_method(rb_cMagic, "initialize", RUBY_METHOD_FUNC(rb_mgc_initialize), -2);
1400
+
1401
+ rb_define_method(rb_cMagic, "do_not_stop_on_error", RUBY_METHOD_FUNC(rb_mgc_get_do_not_stop_on_error), 0);
1402
+ rb_define_method(rb_cMagic, "do_not_stop_on_error=", RUBY_METHOD_FUNC(rb_mgc_set_do_not_stop_on_error), 1);
1403
+
1404
+ rb_define_method(rb_cMagic, "open?", RUBY_METHOD_FUNC(rb_mgc_open_p), 0);
1405
+ rb_define_method(rb_cMagic, "close", RUBY_METHOD_FUNC(rb_mgc_close), 0);
1406
+ rb_define_method(rb_cMagic, "closed?", RUBY_METHOD_FUNC(rb_mgc_close_p), 0);
1407
+
1408
+ rb_define_method(rb_cMagic, "paths", RUBY_METHOD_FUNC(rb_mgc_get_paths), 0);
1409
+
1410
+ rb_define_method(rb_cMagic, "get_parameter", RUBY_METHOD_FUNC(rb_mgc_get_parameter), 1);
1411
+ rb_define_method(rb_cMagic, "set_parameter", RUBY_METHOD_FUNC(rb_mgc_set_parameter), 2);
1412
+
1413
+ rb_define_method(rb_cMagic, "flags", RUBY_METHOD_FUNC(rb_mgc_get_flags), 0);
1414
+ rb_define_method(rb_cMagic, "flags=", RUBY_METHOD_FUNC(rb_mgc_set_flags), 1);
1415
+
1416
+ rb_define_method(rb_cMagic, "file", RUBY_METHOD_FUNC(rb_mgc_file), 1);
1417
+ rb_define_method(rb_cMagic, "buffer", RUBY_METHOD_FUNC(rb_mgc_buffer), 1);
1418
+ rb_define_method(rb_cMagic, "descriptor", RUBY_METHOD_FUNC(rb_mgc_descriptor), 1);
1419
+
1420
+ rb_alias(rb_cMagic, rb_intern("fd"), rb_intern("descriptor"));
1421
+
1422
+ rb_define_method(rb_cMagic, "load", RUBY_METHOD_FUNC(rb_mgc_load), -2);
1423
+ rb_define_method(rb_cMagic, "load_buffers", RUBY_METHOD_FUNC(rb_mgc_load_buffers), -2);
1424
+ rb_define_method(rb_cMagic, "loaded?", RUBY_METHOD_FUNC(rb_mgc_load_p), 0);
1425
+
1426
+ rb_alias(rb_cMagic, rb_intern("load_files"), rb_intern("load"));
1427
+
1428
+ rb_define_method(rb_cMagic, "compile", RUBY_METHOD_FUNC(rb_mgc_compile), 1);
1429
+ rb_define_method(rb_cMagic, "check", RUBY_METHOD_FUNC(rb_mgc_check), 1);
1430
+
1431
+ rb_alias(rb_cMagic, rb_intern("valid?"), rb_intern("check"));
1432
+
1433
+ /*
1434
+ * Controls how many levels of recursion will be followed for
1435
+ * indirect magic entries.
1436
+ */
1437
+ MAGIC_DEFINE_PARAMETER(INDIR_MAX);
1438
+ /*
1439
+ * Controls the maximum number of calls for name or use magic.
1440
+ */
1441
+ MAGIC_DEFINE_PARAMETER(NAME_MAX);
1442
+ /*
1443
+ * Controls how many ELF program sections will be processed.
1444
+ */
1445
+ MAGIC_DEFINE_PARAMETER(ELF_PHNUM_MAX);
1446
+ /*
1447
+ * Controls how many ELF sections will be processed.
1448
+ */
1449
+ MAGIC_DEFINE_PARAMETER(ELF_SHNUM_MAX);
1450
+ /*
1451
+ * Controls how many ELF notes will be processed.
1452
+ */
1453
+ MAGIC_DEFINE_PARAMETER(ELF_NOTES_MAX);
1454
+ /*
1455
+ * Controls the length limit for regular expression searches.
1456
+ */
1457
+ MAGIC_DEFINE_PARAMETER(REGEX_MAX);
1458
+ /*
1459
+ * Controls the maximum number of bytes to read from a file.
1460
+ */
1461
+ MAGIC_DEFINE_PARAMETER(BYTES_MAX);
1462
+ /*
1463
+ * No special handling and/or flags specified. Default behavior.
1464
+ */
1465
+ MAGIC_DEFINE_FLAG(NONE);
1466
+ /*
1467
+ * Print debugging messages to standard error output.
1468
+ */
1469
+ MAGIC_DEFINE_FLAG(DEBUG);
1470
+ /*
1471
+ * If the file queried is a symbolic link, follow it.
1472
+ */
1473
+ MAGIC_DEFINE_FLAG(SYMLINK);
1474
+ /*
1475
+ * If the file is compressed, unpack it and look at the contents.
1476
+ */
1477
+ MAGIC_DEFINE_FLAG(COMPRESS);
1478
+ /*
1479
+ * If the file is a block or character special device, then open
1480
+ * the device and try to look at the contents.
1481
+ */
1482
+ MAGIC_DEFINE_FLAG(DEVICES);
1483
+ /*
1484
+ * Return a MIME type string, instead of a textual description.
1485
+ */
1486
+ MAGIC_DEFINE_FLAG(MIME_TYPE);
1487
+ /*
1488
+ * Return all matches, not just the first.
1489
+ */
1490
+ MAGIC_DEFINE_FLAG(CONTINUE);
1491
+ /*
1492
+ * Check the Magic database for consistency and print warnings to
1493
+ * standard error output.
1494
+ */
1495
+ MAGIC_DEFINE_FLAG(CHECK);
1496
+ /*
1497
+ * Attempt to preserve access time (atime, utime or utimes) of the
1498
+ * file queried on systems that support such system calls.
1499
+ */
1500
+ MAGIC_DEFINE_FLAG(PRESERVE_ATIME);
1501
+ /*
1502
+ * Do not convert unprintable characters to an octal representation.
1503
+ */
1504
+ MAGIC_DEFINE_FLAG(RAW);
1505
+ /*
1506
+ * Treat operating system errors while trying to open files and follow
1507
+ * symbolic links as first class errors, instead of storing them in the
1508
+ * Magic library error buffer for retrieval later.
1509
+ */
1510
+ MAGIC_DEFINE_FLAG(ERROR);
1511
+ /*
1512
+ * Return a MIME encoding, instead of a textual description.
1513
+ */
1514
+ MAGIC_DEFINE_FLAG(MIME_ENCODING);
1515
+ /*
1516
+ * A shorthand for using MIME_TYPE and MIME_ENCODING flags together.
1517
+ */
1518
+ MAGIC_DEFINE_FLAG(MIME);
1519
+ /*
1520
+ * Return the Apple creator and type.
1521
+ */
1522
+ MAGIC_DEFINE_FLAG(APPLE);
1523
+ /*
1524
+ * Do not look for, or inside compressed files.
1525
+ */
1526
+ MAGIC_DEFINE_FLAG(NO_CHECK_COMPRESS);
1527
+ /*
1528
+ * Do not look for, or inside tar archive files.
1529
+ */
1530
+ MAGIC_DEFINE_FLAG(NO_CHECK_TAR);
1531
+ /*
1532
+ * Do not consult Magic files.
1533
+ */
1534
+ MAGIC_DEFINE_FLAG(NO_CHECK_SOFT);
1535
+ /*
1536
+ * Check for EMX application type (only supported on EMX).
1537
+ */
1538
+ MAGIC_DEFINE_FLAG(NO_CHECK_APPTYPE);
1539
+ /*
1540
+ * Do not check for ELF files (do not examine ELF file details).
1541
+ */
1542
+ MAGIC_DEFINE_FLAG(NO_CHECK_ELF);
1543
+ /*
1544
+ * Do not check for various types of text files.
1545
+ */
1546
+ MAGIC_DEFINE_FLAG(NO_CHECK_TEXT);
1547
+ /*
1548
+ * Do not check for CDF files.
1549
+ */
1550
+ MAGIC_DEFINE_FLAG(NO_CHECK_CDF);
1551
+ /*
1552
+ * Do not check for CSV files.
1553
+ */
1554
+ MAGIC_DEFINE_FLAG(NO_CHECK_CSV);
1555
+ /*
1556
+ * Do not look for known tokens inside ASCII files.
1557
+ */
1558
+ MAGIC_DEFINE_FLAG(NO_CHECK_TOKENS);
1559
+ /*
1560
+ * Return a MIME encoding, instead of a textual description.
1561
+ */
1562
+ MAGIC_DEFINE_FLAG(NO_CHECK_ENCODING);
1563
+ /*
1564
+ * Do not check for JSON files.
1565
+ */
1566
+ MAGIC_DEFINE_FLAG(NO_CHECK_JSON);
1567
+ /*
1568
+ * Do not use built-in tests; only consult the Magic file.
1569
+ */
1570
+ MAGIC_DEFINE_FLAG(NO_CHECK_BUILTIN);
1571
+ /*
1572
+ * Do not check for various types of text files, same as NO_CHECK_TEXT.
1573
+ */
1574
+ MAGIC_DEFINE_FLAG(NO_CHECK_ASCII);
1575
+ /*
1576
+ * Do not look for Fortran sequences inside ASCII files.
1577
+ */
1578
+ MAGIC_DEFINE_FLAG(NO_CHECK_FORTRAN);
1579
+ /*
1580
+ * Do not look for troff sequences inside ASCII files.
1581
+ */
1582
+ MAGIC_DEFINE_FLAG(NO_CHECK_TROFF);
1583
+ /*
1584
+ * Return a slash-separated list of extensions for this file type.
1585
+ */
1586
+ MAGIC_DEFINE_FLAG(EXTENSION);
1587
+ /*
1588
+ * Do not report on compression, only report about the uncompressed data.
1589
+ */
1590
+ MAGIC_DEFINE_FLAG(COMPRESS_TRANSP);
1591
+ }
982
1592
 
983
1593
  #if defined(__cplusplus)
984
1594
  }
985
1595
  #endif
986
-
987
- /* vim: set ts=8 sw=4 sts=2 et : */