ruby-magic 0.0.1

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