ruby-magic 0.2.0 → 0.3.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.
@@ -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 : */