ruby-magic-static 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.
@@ -0,0 +1,67 @@
1
+ #if !defined(_FUNCTIONS_H)
2
+ #define _FUNCTIONS_H 1
3
+
4
+ #if defined(__cplusplus)
5
+ extern "C" {
6
+ #endif
7
+
8
+ #include "common.h"
9
+
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);
38
+
39
+ extern const char* magic_getpath_wrapper(void);
40
+
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);
44
+
45
+ extern int magic_getflags_wrapper(magic_t magic);
46
+ extern int magic_setflags_wrapper(magic_t magic, int flags);
47
+
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);
51
+
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);
54
+
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);
60
+
61
+ extern int magic_version_wrapper(void);
62
+
63
+ #if defined(__cplusplus)
64
+ }
65
+ #endif
66
+
67
+ #endif /* _FUNCTIONS_H */
@@ -0,0 +1,1595 @@
1
+ #if defined(__cplusplus)
2
+ extern "C" {
3
+ #endif
4
+
5
+ #include "ruby-magic.h"
6
+
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;
13
+
14
+ VALUE rb_cMagic = Qundef;
15
+
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;
22
+
23
+ void Init_magic(void);
24
+
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);
29
+ static VALUE magic_load_internal(void *data);
30
+ static VALUE magic_load_buffers_internal(void *data);
31
+ static VALUE magic_compile_internal(void *data);
32
+ static VALUE magic_check_internal(void *data);
33
+ static VALUE magic_file_internal(void *data);
34
+ static VALUE magic_buffer_internal(void *data);
35
+ static VALUE magic_descriptor_internal(void *data);
36
+ static VALUE magic_close_internal(void *data);
37
+
38
+ static void* nogvl_magic_load(void *data);
39
+ static void* nogvl_magic_compile(void *data);
40
+ static void* nogvl_magic_check(void *data);
41
+ static void* nogvl_magic_file(void *data);
42
+ static void* nogvl_magic_descriptor(void *data);
43
+
44
+ static VALUE magic_allocate(VALUE klass);
45
+ static void magic_mark(void *data);
46
+ static void magic_free(void *data);
47
+ static VALUE magic_exception_wrapper(VALUE value);
48
+ static VALUE magic_exception(void *data);
49
+ static void magic_library_close(void *data);
50
+ static VALUE magic_library_error(VALUE klass, void *data);
51
+ static VALUE magic_generic_error(VALUE klass, int magic_errno,
52
+ const char *magic_error);
53
+ static VALUE magic_lock(VALUE object, VALUE (*function)(ANYARGS),
54
+ void *data);
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);
60
+
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
+ }
81
+
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
+ }
115
+
116
+ /*
117
+ * call-seq:
118
+ * Magic.do_not_stop_on_error -> boolean
119
+ *
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
140
+ *
141
+ * Example:
142
+ *
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:
165
+ *
166
+ * magic = Magic.new
167
+ * magic.class #=> Magic
168
+ *
169
+ * See also: Magic::open, Magic::mime, Magic::type, Magic::encoding, Magic::compile and Magic::check
170
+ */
171
+ VALUE
172
+ rb_mgc_initialize(VALUE object, VALUE arguments)
173
+ {
174
+ magic_object_t *mo;
175
+ const char *klass = "Magic";
176
+
177
+ if (!NIL_P(object))
178
+ klass = rb_obj_classname(object);
179
+
180
+ if (rb_block_given_p())
181
+ MAGIC_WARNING(0, "%s::new() does not take block; use %s::open() instead",
182
+ klass, klass);
183
+
184
+ if(RTEST(rb_eval_string("ENV['MAGIC_DO_NOT_STOP_ON_ERROR']")))
185
+ rb_mgc_do_not_stop_on_error = 1;
186
+
187
+ if(RTEST(rb_eval_string("ENV['MAGIC_DO_NOT_AUTOLOAD']")))
188
+ rb_mgc_do_not_auto_load = 1;
189
+
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;
194
+
195
+ mo->mutex = rb_class_new_instance(0, 0, rb_const_get(rb_cObject,
196
+ rb_intern("Mutex")));
197
+
198
+ magic_set_flags(object, INT2NUM(MAGIC_NONE));
199
+ magic_set_paths(object, RARRAY_EMPTY);
200
+
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
+ }
208
+
209
+ rb_mgc_load(object, arguments);
210
+ return object;
211
+ }
212
+
213
+ /*
214
+ * call-seq:
215
+ * magic.do_not_stop_on_error -> boolean
216
+ *
217
+ * See also: Magic::new, Magic::open and Magic::do_not_stop_on_error
218
+ */
219
+ VALUE
220
+ rb_mgc_get_do_not_stop_on_error(VALUE object)
221
+ {
222
+ magic_object_t *mo;
223
+
224
+ MAGIC_CHECK_OPEN(object);
225
+ MAGIC_OBJECT(mo);
226
+
227
+ return CBOOL2RVAL(!mo->stop_on_errors);
228
+ }
229
+
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;
240
+
241
+ MAGIC_CHECK_OPEN(object);
242
+ MAGIC_OBJECT(mo);
243
+
244
+ mo->stop_on_errors = !RVAL2CBOOL(value);
245
+ return value;
246
+ }
247
+
248
+ /*
249
+ * call-seq:
250
+ * magic.open? -> true or false
251
+ *
252
+ * Returns +true+ if the underlying _Magic_ database is open,
253
+ * or +false+ otherwise.
254
+ *
255
+ * Example:
256
+ *
257
+ * magic = Magic.new
258
+ * magic.open? #=> true
259
+ * magic.close #=> nil
260
+ * magic.open? #=> false
261
+ *
262
+ * See also: Magic#close?, Magic#close and Magic#new
263
+ */
264
+ VALUE
265
+ rb_mgc_open_p(VALUE object)
266
+ {
267
+ return MAGIC_CLOSED_P(object) ? Qfalse : Qtrue;
268
+ }
269
+
270
+ /*
271
+ * call-seq:
272
+ * magic.close -> nil
273
+ *
274
+ * Closes the underlying _Magic_ database.
275
+ *
276
+ * Example:
277
+ *
278
+ * magic = Magic.new
279
+ * magic.close #=> nil
280
+ *
281
+ * See also: Magic#closed?, Magic#open? and Magic#new
282
+ */
283
+ VALUE
284
+ rb_mgc_close(VALUE object)
285
+ {
286
+ magic_object_t *mo;
287
+
288
+ if (MAGIC_CLOSED_P(object))
289
+ return Qnil;
290
+
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
+ }
297
+
298
+ return Qnil;
299
+ }
300
+
301
+ /*
302
+ * call-seq:
303
+ * magic.closed? -> true or false
304
+ *
305
+ * Returns +true+ if the underlying _Magic_ database is closed,
306
+ * or +false+ otherwise.
307
+ *
308
+ * Example:
309
+ *
310
+ * magic = Magic.new
311
+ * magic.closed? #=> false
312
+ * magic.close #=> nil
313
+ * magic.closed? #=> true
314
+ *
315
+ * See also: Magic#close, Magic#open? and #Magic#new
316
+ */
317
+ VALUE
318
+ rb_mgc_close_p(VALUE object)
319
+ {
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;
331
+ }
332
+
333
+ /*
334
+ * call-seq:
335
+ * magic.paths -> array
336
+ *
337
+ * Example:
338
+ *
339
+ * magic = Magic.new
340
+ * magic.paths #=> ["/etc/magic", "/usr/share/misc/magic"]
341
+ *
342
+ */
343
+ VALUE
344
+ rb_mgc_get_paths(VALUE object)
345
+ {
346
+ const char *cstring = NULL;
347
+ VALUE value = Qundef;
348
+
349
+ MAGIC_CHECK_OPEN(object);
350
+
351
+ value = rb_ivar_get(object, id_at_paths);
352
+ if (!NIL_P(value) && !RARRAY_EMPTY_P(value) && !getenv("MAGIC"))
353
+ return value;
354
+
355
+ cstring = magic_getpath_wrapper();
356
+ value = magic_split(CSTR2RVAL(cstring), CSTR2RVAL(":"));
357
+ RB_GC_GUARD(value);
358
+
359
+ return value;
360
+ }
361
+
362
+ /*
363
+ * call-seq:
364
+ * magic.get_parameter( integer ) -> integer
365
+ */
366
+ VALUE
367
+ rb_mgc_get_parameter(VALUE object, VALUE tag)
368
+ {
369
+ int local_errno;
370
+ magic_object_t *mo;
371
+ magic_arguments_t ma;
372
+
373
+ MAGIC_CHECK_INTEGER_TYPE(tag);
374
+ MAGIC_CHECK_OPEN(object);
375
+ MAGIC_COOKIE(mo, ma.cookie);
376
+
377
+ ma.type.parameter.tag = NUM2INT(tag);
378
+
379
+ MAGIC_SYNCHRONIZED(magic_get_parameter_internal, &ma);
380
+ local_errno = errno;
381
+
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);
387
+
388
+ MAGIC_LIBRARY_ERROR(ma.cookie);
389
+ }
390
+
391
+ return SIZET2NUM(ma.type.parameter.value);
392
+ }
393
+
394
+ /*
395
+ * call-seq:
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
436
+ *
437
+ * Example:
438
+ *
439
+ * magic = Magic.new
440
+ * magic.flags #=> 0
441
+ * magic.flags = Magic::MIME #=> 1040
442
+ * magic.flags #=> 1040
443
+ *
444
+ * See also: Magic#flags_to_a
445
+ */
446
+ VALUE
447
+ rb_mgc_get_flags(VALUE object)
448
+ {
449
+ int local_errno;
450
+ magic_object_t *mo;
451
+ magic_arguments_t ma;
452
+
453
+ MAGIC_CHECK_OPEN(object);
454
+ MAGIC_COOKIE(mo, ma.cookie);
455
+
456
+ MAGIC_SYNCHRONIZED(magic_get_flags_internal, &ma);
457
+ local_errno = errno;
458
+
459
+ if (ma.flags < 0 && local_errno == ENOSYS)
460
+ return rb_ivar_get(object, id_at_flags);
461
+
462
+ return INT2NUM(ma.flags);
463
+ }
464
+
465
+ /*
466
+ * call-seq:
467
+ * magic.flags= ( integer ) -> integer
468
+ *
469
+ * Example:
470
+ *
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
513
+ *
514
+ * Example:
515
+ *
516
+ * See also: Magic#check, Magic#compile, Magic::check and Magic::compile
517
+ */
518
+ VALUE
519
+ rb_mgc_load(VALUE object, VALUE arguments)
520
+ {
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
+ }
566
+
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);
646
+ }
647
+
648
+ /*
649
+ * call-seq:
650
+ * magic.loaded? -> true or false
651
+ *
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.
655
+ *
656
+ * Example:
657
+ *
658
+ * magic = Magic.new
659
+ * magic.loaded? #=> true
660
+ *
661
+ * Example:
662
+ *
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
668
+ */
669
+ VALUE
670
+ rb_mgc_load_p(VALUE object)
671
+ {
672
+ magic_object_t *mo;
673
+
674
+ MAGIC_CHECK_OPEN(object);
675
+ MAGIC_OBJECT(mo);
676
+
677
+ return CBOOL2RVAL(mo->database_loaded);
678
+ }
679
+
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;
692
+
693
+ MAGIC_CHECK_STRING_TYPE(value);
694
+ MAGIC_CHECK_OPEN(object);
695
+ MAGIC_COOKIE(mo, ma.cookie);
696
+
697
+ ma.flags = magic_flags(object);
698
+ ma.type.file.path = RVAL2CSTR(value);
699
+
700
+ MAGIC_SYNCHRONIZED(magic_compile_internal, &ma);
701
+ if (ma.status < 0)
702
+ MAGIC_LIBRARY_ERROR(ma.cookie);
703
+
704
+ return Qnil;
705
+ }
706
+
707
+ /*
708
+ * call-seq:
709
+ * magic.check( string ) -> true or false
710
+ * magic.check( array ) -> true or false
711
+ *
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
735
+ *
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
806
+ *
807
+ * See also: Magic#file and Magic#descriptor
808
+ */
809
+ VALUE
810
+ rb_mgc_buffer(VALUE object, VALUE value)
811
+ {
812
+ magic_object_t *mo;
813
+ magic_arguments_t ma;
814
+
815
+ MAGIC_CHECK_STRING_TYPE(value);
816
+ MAGIC_CHECK_OPEN(object);
817
+ MAGIC_CHECK_LOADED(object);
818
+ MAGIC_COOKIE(mo, ma.cookie);
819
+
820
+ StringValue(value);
821
+
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);
825
+
826
+ MAGIC_SYNCHRONIZED(magic_buffer_internal, &ma);
827
+ if (!ma.result)
828
+ MAGIC_LIBRARY_ERROR(ma.cookie);
829
+
830
+ assert(ma.result != NULL && \
831
+ "Must be a valid pointer to `const char' type");
832
+
833
+ return magic_return(&ma);
834
+ }
835
+
836
+ /*
837
+ * call-seq:
838
+ * magic.descriptor( object ) -> string or array
839
+ * magic.descriptor( integer ) -> string or array
840
+ *
841
+ * See also: Magic#file and Magic#buffer
842
+ */
843
+ VALUE
844
+ rb_mgc_descriptor(VALUE object, VALUE value)
845
+ {
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);
857
+
858
+ ma.flags = magic_flags(object);
859
+ ma.type.file.fd = NUM2INT(value);
860
+
861
+ MAGIC_SYNCHRONIZED(magic_descriptor_internal, &ma);
862
+ local_errno = errno;
863
+
864
+ if (!ma.result) {
865
+ if (local_errno == EBADF)
866
+ rb_raise(rb_eIOError, "Bad file descriptor");
867
+
868
+ MAGIC_LIBRARY_ERROR(ma.cookie);
869
+ }
870
+
871
+ assert(ma.result != NULL && \
872
+ "Must be a valid pointer to `const char' type");
873
+
874
+ return magic_return(&ma);
875
+ }
876
+
877
+ /*
878
+ * call-seq:
879
+ * Magic.version -> integer
880
+ *
881
+ * Example:
882
+ *
883
+ * Magic.version #=> 517
884
+ *
885
+ * See also: Magic::version_to_a and Magic::version_to_s
886
+ */
887
+ VALUE
888
+ rb_mgc_version(RB_UNUSED_VAR(VALUE object))
889
+ {
890
+ return INT2NUM(magic_version_wrapper());
891
+ }
892
+
893
+ static inline void*
894
+ nogvl_magic_load(void *data)
895
+ {
896
+ magic_arguments_t *ma = data;
897
+
898
+ ma->status = magic_load_wrapper(ma->cookie,
899
+ ma->type.file.path,
900
+ ma->flags);
901
+ return NULL;
902
+ }
903
+
904
+ static inline void*
905
+ nogvl_magic_compile(void *data)
906
+ {
907
+ magic_arguments_t *ma = data;
908
+
909
+ ma->status = magic_compile_wrapper(ma->cookie,
910
+ ma->type.file.path,
911
+ ma->flags);
912
+ return NULL;
913
+ }
914
+
915
+ static inline void*
916
+ nogvl_magic_check(void *data)
917
+ {
918
+ magic_arguments_t *ma = data;
919
+
920
+ ma->status = magic_check_wrapper(ma->cookie,
921
+ ma->type.file.path,
922
+ ma->flags);
923
+ return NULL;
924
+ }
925
+
926
+ static inline void*
927
+ nogvl_magic_file(void *data)
928
+ {
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;
935
+ }
936
+
937
+ static inline void*
938
+ nogvl_magic_descriptor(void *data)
939
+ {
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;
990
+ }
991
+
992
+ static inline VALUE
993
+ magic_close_internal(void *data)
994
+ {
995
+ magic_library_close(data);
996
+ return Qnil;
997
+ }
998
+
999
+ static inline VALUE
1000
+ magic_load_internal(void *data)
1001
+ {
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;
1016
+ }
1017
+
1018
+ static inline VALUE
1019
+ magic_compile_internal(void *data)
1020
+ {
1021
+ return (VALUE)NOGVL(nogvl_magic_compile, data);
1022
+ }
1023
+
1024
+ static inline VALUE
1025
+ magic_check_internal(void *data)
1026
+ {
1027
+ return (VALUE)NOGVL(nogvl_magic_check, data);
1028
+ }
1029
+
1030
+ static VALUE
1031
+ magic_file_internal(void *data)
1032
+ {
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;
1069
+ }
1070
+
1071
+ static VALUE
1072
+ magic_buffer_internal(void *data)
1073
+ {
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;
1094
+ }
1095
+
1096
+ static VALUE
1097
+ magic_descriptor_internal(void *data)
1098
+ {
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;
1117
+ }
1118
+
1119
+ static VALUE
1120
+ magic_allocate(VALUE klass)
1121
+ {
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;
1173
+
1174
+ assert(mo != NULL && \
1175
+ "Must be a valid pointer to `magic_object_t' type");
1176
+
1177
+ rb_gc_mark(mo->mutex);
1178
+ }
1179
+
1180
+ static inline void
1181
+ magic_free(void *data)
1182
+ {
1183
+ magic_object_t *mo = data;
1184
+
1185
+ assert(mo != NULL && \
1186
+ "Must be a valid pointer to `magic_object_t' type");
1187
+
1188
+ if (mo->cookie)
1189
+ magic_library_close(data);
1190
+
1191
+ mo->cookie = NULL;
1192
+ mo->mutex = Qundef;
1193
+
1194
+ ruby_xfree(mo);
1195
+ }
1196
+
1197
+ static inline VALUE
1198
+ magic_exception_wrapper(VALUE value)
1199
+ {
1200
+ magic_exception_t *e = (struct magic_exception *)value;
1201
+
1202
+ return rb_exc_new2(e->klass, e->magic_error);
1203
+ }
1204
+
1205
+ static VALUE
1206
+ magic_exception(void *data)
1207
+ {
1208
+ magic_exception_t *e = data;
1209
+ int exception = 0;
1210
+ VALUE object = Qundef;
1211
+
1212
+ assert(e != NULL && \
1213
+ "Must be a valid pointer to `magic_exception_t' type");
1214
+
1215
+ object = rb_protect(magic_exception_wrapper, (VALUE)e, &exception);
1216
+
1217
+ if (exception)
1218
+ rb_jump_tag(exception);
1219
+
1220
+ rb_iv_set(object, "@errno", INT2NUM(e->magic_errno));
1221
+ RB_GC_GUARD(object);
1222
+
1223
+ return object;
1224
+ }
1225
+
1226
+ static inline VALUE
1227
+ magic_generic_error(VALUE klass, int magic_errno, const char *magic_error)
1228
+ {
1229
+ magic_exception_t e;
1230
+
1231
+ e.magic_errno = magic_errno;
1232
+ e.magic_error = magic_error;
1233
+ e.klass = klass;
1234
+
1235
+ return magic_exception(&e);
1236
+ }
1237
+
1238
+ static VALUE
1239
+ magic_library_error(VALUE klass, void *data)
1240
+ {
1241
+ magic_exception_t e;
1242
+ const char *message = NULL;
1243
+ const char *empty = "(null)";
1244
+ magic_t cookie = data;
1245
+
1246
+ assert(cookie != NULL && \
1247
+ "Must be a valid pointer to `magic_t' type");
1248
+
1249
+ e.magic_errno = -1;
1250
+ e.magic_error = error(E_UNKNOWN);
1251
+ e.klass = klass;
1252
+
1253
+ message = magic_error_wrapper(cookie);
1254
+ if (message) {
1255
+ e.magic_errno = magic_errno_wrapper(cookie);
1256
+ e.magic_error = message;
1257
+ }
1258
+
1259
+ assert(strncmp(e.magic_error, empty, strlen(empty)) != 0 && \
1260
+ "Empty or invalid error message");
1261
+
1262
+ return magic_exception(&e);
1263
+ }
1264
+
1265
+ VALUE
1266
+ magic_lock(VALUE object, VALUE(*function)(ANYARGS), void *data)
1267
+ {
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);
1274
+ }
1275
+
1276
+ VALUE
1277
+ magic_unlock(VALUE object)
1278
+ {
1279
+ magic_object_t *mo;
1280
+
1281
+ MAGIC_OBJECT(mo);
1282
+ rb_funcall(mo->mutex, rb_intern("unlock"), 0, Qundef);
1283
+
1284
+ return Qnil;
1285
+ }
1286
+
1287
+ static VALUE
1288
+ magic_return(void *data)
1289
+ {
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
+ }
1335
+
1336
+ static inline int
1337
+ magic_flags(VALUE object)
1338
+ {
1339
+ return NUM2INT(rb_ivar_get(object, id_at_flags));
1340
+ }
1341
+
1342
+ static inline int
1343
+ magic_set_flags(VALUE object, VALUE value)
1344
+ {
1345
+ return NUM2INT(rb_ivar_set(object, id_at_flags, value));
1346
+ }
1347
+
1348
+ static inline VALUE
1349
+ magic_set_paths(VALUE object, VALUE value)
1350
+ {
1351
+ return rb_ivar_set(object, id_at_paths, value);
1352
+ }
1353
+
1354
+ void
1355
+ Init_magic(void)
1356
+ {
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
+ }
1592
+
1593
+ #if defined(__cplusplus)
1594
+ }
1595
+ #endif