ruby-magic 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,244 @@
1
+ /* :enddoc: */
2
+
3
+ /*
4
+ * ruby-magic.h
5
+ *
6
+ * Copyright 2013-2014 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
+ #if !defined(_RUBY_MAGIC_H)
22
+ #define _RUBY_MAGIC_H 1
23
+
24
+ #if defined(__cplusplus)
25
+ extern "C" {
26
+ #endif
27
+
28
+ #include "common.h"
29
+ #include "functions.h"
30
+
31
+ #define DATA_P(x) (TYPE(x) == T_DATA)
32
+ #define STRING_P(x) (TYPE(x) == T_STRING)
33
+ #define ARRAY_P(x) (TYPE(x) == T_ARRAY)
34
+
35
+ #if !defined(STR2CSTR)
36
+ # define STR2CSTR(x) StringValuePtr(x)
37
+ #endif
38
+
39
+ #if !defined(RVAL2CSTR)
40
+ # define RVAL2CSTR(x) (NIL_P(x) ? NULL : STR2CSTR(x))
41
+ #endif
42
+
43
+ #if !defined(CSTR2RVAL)
44
+ # define CSTR2RVAL(x) ((x) == NULL ? Qnil : rb_str_new2(x))
45
+ #endif
46
+
47
+ #if !defined(RARRAY_LEN)
48
+ # define RARRAY_LEN(a) (RARRAY(a)->len)
49
+ #endif
50
+
51
+ #if !defined(RSTRING_LEN)
52
+ # define RSTRING_LEN(s) (RSTRING(s)->len)
53
+ #endif
54
+
55
+ #if !defined(RSTRING_PTR)
56
+ # define RSTRING_PTR(s) (RSTRING(s)->ptr)
57
+ #endif
58
+
59
+ #define RSTRING_EMPTY_P(s) (RSTRING_LEN(s) == 0)
60
+ #define RARRAY_EMPTY_P(a) (RARRAY_LEN(a) == 0)
61
+ #define RARRAY_FIRST(a) (RARRAY_EMPTY_P(a) ? Qnil : RARRAY_PTR(a)[0])
62
+
63
+ #define NOGVL_FUNCTION (VALUE (*)(void *))
64
+
65
+ #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && \
66
+ defined(HAVE_RUBY_THREAD_H) && HAVE_RUBY_THREAD_H
67
+ # include <ruby/thread.h>
68
+ # define NOGVL(f, d) \
69
+ rb_thread_call_without_gvl((f), (d), RUBY_UBF_IO, NULL)
70
+ #elif defined(HAVE_RB_THREAD_BLOCKING_REGION)
71
+ # define NOGVL(f, d) \
72
+ rb_thread_blocking_region(NOGVL_FUNCTION(f), (d), RUBY_UBF_IO, NULL)
73
+ #else
74
+ # include <rubysig.h>
75
+ static inline VALUE
76
+ fake_blocking_region(VALUE (*f)(ANYARGS), void *data)
77
+ {
78
+ VALUE rv;
79
+
80
+ TRAP_BEG;
81
+ rv = f(data);
82
+ TRAP_END;
83
+
84
+ return rv;
85
+ }
86
+ # define NOGVL(f, d) fake_blocking_region(NOGVL_FUNCTION(f), (d))
87
+ #endif
88
+
89
+ #define MAGIC_SYNCHRONIZED(f, d) magic_lock(object, (f), (d))
90
+
91
+ #define MAGIC_COOKIE(c) \
92
+ Data_Get_Struct(object, struct magic_set, (c))
93
+
94
+ #define MAGIC_CLOSED_P(o) RTEST(rb_mgc_closed((o)))
95
+
96
+ #define MAGIC_GENERIC_ERROR(k, e, m) \
97
+ do { \
98
+ VALUE __e_##k = magic_generic_error((k), (e), (m)); \
99
+ rb_exc_raise(__e_##k); \
100
+ } while(0)
101
+
102
+ #define MAGIC_LIBRARY_ERROR(c) \
103
+ do { \
104
+ VALUE __e_library = magic_library_error(rb_mgc_eMagicError, (c)); \
105
+ rb_exc_raise(__e_library); \
106
+ } while(0)
107
+
108
+ #define CHECK_MAGIC_OPEN(o) \
109
+ do { \
110
+ if (MAGIC_CLOSED_P(o)) { \
111
+ MAGIC_GENERIC_ERROR(rb_mgc_eLibraryError, EFAULT, \
112
+ error(E_MAGIC_LIBRARY_CLOSED)); \
113
+ } \
114
+ } while(0) \
115
+
116
+ #define error(t) errors[(t)]
117
+
118
+ enum error {
119
+ E_UNKNOWN = 0,
120
+ E_NOT_IMPLEMENTED,
121
+ E_MAGIC_LIBRARY_INITIALIZE,
122
+ E_MAGIC_LIBRARY_CLOSED,
123
+ E_FLAG_INVALID_VALUE,
124
+ E_FLAG_NOT_IMPLEMENTED
125
+ };
126
+
127
+ union file {
128
+ int fd;
129
+ const char *path;
130
+ };
131
+
132
+ struct buffer {
133
+ size_t size;
134
+ const char *buffer;
135
+ };
136
+
137
+ typedef union file file_t;
138
+ typedef struct buffer buffer_t;
139
+
140
+ struct magic_arguments {
141
+ int flags;
142
+ magic_t cookie;
143
+ union {
144
+ file_t file;
145
+ buffer_t buffer;
146
+ } data;
147
+ };
148
+
149
+ struct magic_exception {
150
+ int magic_errno;
151
+ const char *magic_error;
152
+ VALUE klass;
153
+ };
154
+
155
+ typedef struct magic_arguments magic_arguments_t;
156
+ typedef struct magic_exception magic_exception_t;
157
+
158
+ static const char *errors[] = {
159
+ "unknown error",
160
+ "function is not implemented",
161
+ "failed to initialize Magic library",
162
+ "Magic library is not open",
163
+ "unknown or invalid flag specified",
164
+ "flag is not implemented",
165
+ NULL
166
+ };
167
+
168
+ inline static VALUE
169
+ magic_size(VALUE v)
170
+ {
171
+ if (ARRAY_P(v) || STRING_P(v)) {
172
+ return rb_funcall(v, rb_intern("size"), 0, NULL);
173
+ }
174
+
175
+ return Qnil;
176
+ }
177
+
178
+ inline static VALUE
179
+ magic_shift(VALUE v)
180
+ {
181
+ if (ARRAY_P(v)) {
182
+ return rb_funcall(v, rb_intern("shift"), 0, NULL);
183
+ }
184
+
185
+ return Qnil;
186
+ }
187
+
188
+ inline static VALUE
189
+ magic_split(VALUE a, VALUE b)
190
+ {
191
+ if (STRING_P(a) && STRING_P(b)) {
192
+ return rb_funcall(a, rb_intern("split"), 1, b);
193
+ }
194
+
195
+ return Qnil;
196
+ }
197
+
198
+ inline static VALUE
199
+ magic_join(VALUE a, VALUE b)
200
+ {
201
+ if (ARRAY_P(a) && STRING_P(b)) {
202
+ return rb_funcall(a, rb_intern("join"), 1, b);
203
+ }
204
+
205
+ return Qnil;
206
+ }
207
+
208
+ RUBY_EXTERN ID id_at_flags, id_at_path, id_at_mutex;
209
+
210
+ RUBY_EXTERN VALUE rb_cMagic;
211
+
212
+ RUBY_EXTERN VALUE rb_mgc_eError;
213
+ RUBY_EXTERN VALUE rb_mgc_eMagicError;
214
+ RUBY_EXTERN VALUE rb_mgc_eLibraryError;
215
+ RUBY_EXTERN VALUE rb_mgc_eFlagsError;
216
+ RUBY_EXTERN VALUE rb_mgc_eNotImplementedError;
217
+
218
+ RUBY_EXTERN VALUE rb_mgc_initialize(VALUE object, VALUE arguments);
219
+
220
+ RUBY_EXTERN VALUE rb_mgc_close(VALUE object);
221
+ RUBY_EXTERN VALUE rb_mgc_closed(VALUE object);
222
+
223
+ RUBY_EXTERN VALUE rb_mgc_get_path(VALUE object);
224
+
225
+ RUBY_EXTERN VALUE rb_mgc_get_flags(VALUE object);
226
+ RUBY_EXTERN VALUE rb_mgc_set_flags(VALUE object, VALUE value);
227
+
228
+ RUBY_EXTERN VALUE rb_mgc_load(VALUE object, VALUE arguments);
229
+ RUBY_EXTERN VALUE rb_mgc_compile(VALUE object, VALUE arguments);
230
+ RUBY_EXTERN VALUE rb_mgc_check(VALUE object, VALUE arguments);
231
+
232
+ RUBY_EXTERN VALUE rb_mgc_file(VALUE object, VALUE value);
233
+ RUBY_EXTERN VALUE rb_mgc_buffer(VALUE object, VALUE value);
234
+ RUBY_EXTERN VALUE rb_mgc_descriptor(VALUE object, VALUE value);
235
+
236
+ RUBY_EXTERN VALUE rb_mgc_version(VALUE object);
237
+
238
+ #if defined(__cplusplus)
239
+ }
240
+ #endif
241
+
242
+ #endif /* _RUBY_MAGIC_H */
243
+
244
+ /* vim: set ts=8 sw=4 sts=2 et : */
@@ -0,0 +1,124 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ # :stopdoc:
4
+
5
+ #
6
+ # core/file.rb
7
+ #
8
+ # Copyright 2013-2014 Krzysztof Wilczynski
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ # :startdoc:
24
+
25
+ #
26
+ #
27
+ #
28
+ class File
29
+ class << self
30
+ #
31
+ # call-seq:
32
+ # File.magic( path ) -> string, array or nil
33
+ #
34
+ # Returns
35
+ #
36
+ # Example:
37
+ #
38
+ # See also: File::mime and File::type
39
+ #
40
+ def magic(path, flags = Magic::NONE)
41
+ path = path.path if path.respond_to?(:path)
42
+ path ||= path.to_path if path.respond_to?(:to_path)
43
+ path ||= path.to_s
44
+
45
+ Magic.open(flags) {|mgc| mgc.file(path) }
46
+ rescue Magic::Error
47
+ end
48
+
49
+ #
50
+ # call-seq:
51
+ # File.mime( path ) -> string, array or nil
52
+ #
53
+ # Returns
54
+ #
55
+ # Example:
56
+ #
57
+ # See also: File::magic and File::type
58
+ #
59
+ def mime(path)
60
+ magic(path, Magic::MIME)
61
+ end
62
+
63
+ #
64
+ # call-seq:
65
+ # File.type( path ) -> string, array or nil
66
+ #
67
+ # Returns
68
+ #
69
+ # Example:
70
+ #
71
+ # See also: File::magic and File::mime
72
+ #
73
+ def type(path)
74
+ magic(path, Magic::MIME_TYPE)
75
+ end
76
+ end
77
+
78
+ #
79
+ # call-seq:
80
+ # File.magic( path ) -> string, array or nil
81
+ #
82
+ # Returns
83
+ #
84
+ # Example:
85
+ #
86
+ # See also: File#mime and File#type
87
+ #
88
+ def magic
89
+ self.class.magic(self)
90
+ end
91
+
92
+ #
93
+ # call-seq:
94
+ # File.mime( path ) -> string, array or nil
95
+ #
96
+ # Returns
97
+ #
98
+ # Example:
99
+ #
100
+ # See also: File#magic and File#type
101
+ #
102
+ def mime
103
+ self.class.mime(self)
104
+ end
105
+
106
+ #
107
+ # call-seq:
108
+ # File.type( path ) -> string, array or nil
109
+ #
110
+ # Returns
111
+ #
112
+ # Example:
113
+ #
114
+ # See also: File#magic and File#mime
115
+ #
116
+ def type
117
+ self.class.type(self)
118
+ end
119
+ end
120
+
121
+ # :enddoc:
122
+
123
+ # vim: set ts=2 sw=2 sts=2 et :
124
+ # encoding: utf-8
@@ -0,0 +1,76 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ # :stopdoc:
4
+
5
+ #
6
+ # core/string.rb
7
+ #
8
+ # Copyright 2013-2014 Krzysztof Wilczynski
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ # :startdoc:
24
+
25
+ #
26
+ #
27
+ #
28
+ class String
29
+ #
30
+ # call-seq:
31
+ # string.magic -> string, array or nil
32
+ #
33
+ # Returns
34
+ #
35
+ # Example:
36
+ #
37
+ # See also: String#mime and String#type
38
+ #
39
+ def magic(flags = Magic::NONE)
40
+ Magic.open(flags) {|mgc| mgc.buffer(self) }
41
+ rescue Magic::Error
42
+ end
43
+
44
+ #
45
+ # call-seq:
46
+ # string.mime -> string, array or nil
47
+ #
48
+ # Returns
49
+ #
50
+ # Example:
51
+ #
52
+ # See also: String#magic and String#type
53
+ #
54
+ def mime
55
+ magic(Magic::MIME)
56
+ end
57
+
58
+ #
59
+ # call-seq:
60
+ # string.type -> string, array or nil
61
+ #
62
+ # Returns
63
+ #
64
+ # Example:
65
+ #
66
+ # See also: String#magic and String#mime
67
+ #
68
+ def type
69
+ magic(Magic::MIME_TYPE)
70
+ end
71
+ end
72
+
73
+ # :enddoc:
74
+
75
+ # vim: set ts=2 sw=2 sts=2 et :
76
+ # encoding: utf-8
@@ -0,0 +1,76 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ # :stopdoc:
4
+
5
+ #
6
+ # version.rb
7
+ #
8
+ # Copyright 2013-2014 Krzysztof Wilczynski
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ # :startdoc:
24
+
25
+ class Magic
26
+ #
27
+ # Current version of _Magic_.
28
+ #
29
+ VERSION = '0.0.1'
30
+
31
+ class << self
32
+ #
33
+ # call-seq:
34
+ # Magic.version_to_a -> array
35
+ #
36
+ # Returns
37
+ #
38
+ # Example:
39
+ #
40
+ # Magic.version_to_a #=> [5, 17]
41
+ #
42
+ # Will raise <i>Magic::NotImplementedError</i> exception if, or
43
+ #
44
+ # See also: Magic::version_to_s
45
+ #
46
+ def version_to_a
47
+ [self.version / 100, self.version % 100]
48
+ end
49
+
50
+ #
51
+ # call-seq:
52
+ # Magic.version_to_s -> string
53
+ #
54
+ # Returns
55
+ #
56
+ # Example:
57
+ #
58
+ # Magic.version_to_s #=> "5.17"
59
+ #
60
+ # Will raise <i>Magic::NotImplementedError</i> exception if, or
61
+ #
62
+ # See also: Magic::version_to_a
63
+ #
64
+ def version_to_s
65
+ '%d.%02d' % self.version_to_a
66
+ end
67
+
68
+ alias_method :version_array, :version_to_a
69
+ alias_method :version_string, :version_to_s
70
+ end
71
+ end
72
+
73
+ # :enddoc:
74
+
75
+ # vim: set ts=2 sw=2 sts=2 et :
76
+ # encoding: utf-8
data/lib/magic.rb ADDED
@@ -0,0 +1,204 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ # :stopdoc:
4
+
5
+ #
6
+ # magic.rb
7
+ #
8
+ # Copyright 2013-2014 Krzysztof Wilczynski
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ require 'magic/magic'
24
+ require 'magic/version'
25
+ require 'magic/core/file'
26
+ require 'magic/core/string'
27
+
28
+ # :startdoc:
29
+
30
+ #
31
+ # File _Magic_ in Ruby.
32
+ #
33
+ # Simple interface to _libmagic_ for Ruby Programming Language.
34
+ #
35
+ class Magic
36
+ #
37
+ # call-seq:
38
+ # magic.inspect -> string
39
+ #
40
+ # Returns
41
+ #
42
+ # Example:
43
+ #
44
+ # magic = Magic.new #=> #<Magic:0x007fd5258a1108>
45
+ # magic.inspect #=> "#<Magic:0x007fd5258a1108 @flags=0, @path=[\"/etc/magic\", \"/usr/share/misc/magic\"]>"
46
+ #
47
+ def inspect
48
+ super.insert(-2, self.closed? ? ' (closed)' : '')
49
+ end
50
+
51
+ #
52
+ # call-seq:
53
+ # magic.flags_to_a( names ) -> array
54
+ #
55
+ # Returns an +array+
56
+ #
57
+ # Example:
58
+ #
59
+ # Will raise <i>Magic::LibraryError</i> exception if, or
60
+ #
61
+ # See also: Magic#flags
62
+ #
63
+ def flags_to_a(names = false)
64
+ raise LibraryError, "Magic library is not open" if closed?
65
+
66
+ n, i = 0, @flags
67
+
68
+ flags = []
69
+
70
+ return [names ? 'NONE' : 0] if @flags.zero?
71
+
72
+ @@flags_map ||= flags_as_map if names
73
+
74
+ while i > 0
75
+ n = 2 ** (Math.log(i) / Math.log(2)).to_i
76
+ i = i - n
77
+ flags.insert(0, names ? @@flags_map[n] : n)
78
+ end
79
+
80
+ flags
81
+ end
82
+
83
+ class << self
84
+ #
85
+ # call-seq:
86
+ # Magic.open( flags ) -> self
87
+ # Magic.open( flags ) {|magic| block } -> string or array
88
+ #
89
+ # Returns
90
+ #
91
+ # Example:
92
+ #
93
+ # See also: Magic::mime, Magic::type, Magic::encoding, Magic::compile and Magic::check
94
+ #
95
+ def open(flags = Magic::NONE)
96
+ magic = Magic.new
97
+ magic.flags = flags
98
+
99
+ if block_given?
100
+ begin
101
+ yield magic
102
+ ensure
103
+ magic.close
104
+ end
105
+ else
106
+ magic
107
+ end
108
+ end
109
+
110
+ #
111
+ # call-seq:
112
+ # Magic.mime -> self
113
+ # Magic.mime {|magic| block } -> string or array
114
+ #
115
+ # Returns
116
+ #
117
+ # Example:
118
+ #
119
+ # See also: Magic::open, Magic::type, Magic::encoding, Magic::compile and Magic::check
120
+ #
121
+ def mime(&block)
122
+ open(Magic::MIME, &block)
123
+ end
124
+
125
+ #
126
+ # call-seq:
127
+ # Magic.type -> self
128
+ # Magic.type {|magic| block } -> string or array
129
+ #
130
+ # Returns
131
+ #
132
+ # Example:
133
+ #
134
+ # See also: Magic::open, Magic::mime, Magic::encoding, Magic::compile and Magic::check
135
+ #
136
+ def type(&block)
137
+ open(Magic::MIME_TYPE, &block)
138
+ end
139
+
140
+ #
141
+ # call-seq:
142
+ # Magic.encoding -> self
143
+ # Magic.encoding {|magic| block } -> string or array
144
+ #
145
+ # Returns
146
+ #
147
+ # Example:
148
+ #
149
+ # See also: Magic::open, Magic::mime, Magic::type, Magic::compile and Magic::check
150
+ #
151
+ def encoding(&block)
152
+ open(Magic::MIME_ENCODING, &block)
153
+ end
154
+
155
+ #
156
+ # call-seq:
157
+ # Magic.compile( path, ... ) -> true
158
+ # Magic.compile( array ) -> true
159
+ #
160
+ # Returns
161
+ #
162
+ # Example:
163
+ #
164
+ # See also: Magic::open, Magic::mime, Magic::type, Magic::encoding, and Magic::check
165
+ #
166
+ def compile(path)
167
+ open {|m| m.compile(path) }
168
+ end
169
+
170
+ #
171
+ # call-seq:
172
+ # Magic.check( path, ... ) -> true or false
173
+ # Magic.check( array ) -> true or false
174
+ #
175
+ # Returns
176
+ #
177
+ # Example:
178
+ #
179
+ # See also: Magic::open, Magic::mime, Magic::type, Magic::encoding and Magic::compile
180
+ #
181
+ def check(path)
182
+ open {|m| m.check(path) }
183
+ end
184
+ end
185
+
186
+ alias_method :flags_array, :flags_to_a
187
+
188
+ private
189
+
190
+ def flags_as_map
191
+ self.class.constants.inject({}) do |flags,constant|
192
+ value = self.class.const_get(constant)
193
+ flags[value] = constant.to_s if value.is_a?(Fixnum)
194
+ flags
195
+ end
196
+ end
197
+ end
198
+
199
+ # :enddoc:
200
+
201
+ FileMagic = Magic
202
+
203
+ # vim: set ts=2 sw=2 sts=2 et :
204
+ # encoding: utf-8