file_signature 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/README.md +36 -10
  2. data/VERSION +1 -1
  3. data/lib/file_signature.rb +261 -40
  4. data/test/file_signature_test.rb +74 -11
  5. data/test/file_signature_test/sample.3g2 +0 -0
  6. data/test/file_signature_test/sample.3gp +0 -0
  7. data/test/file_signature_test/sample.aif +0 -0
  8. data/test/file_signature_test/sample.avi +0 -0
  9. data/test/file_signature_test/sample.bc +0 -0
  10. data/test/file_signature_test/sample.bmp +0 -0
  11. data/test/file_signature_test/sample.doc +0 -0
  12. data/test/file_signature_test/sample.elf +0 -0
  13. data/test/file_signature_test/sample.exe +0 -0
  14. data/test/file_signature_test/sample.fig +15 -0
  15. data/test/file_signature_test/sample.flac +0 -0
  16. data/test/file_signature_test/sample.gpg +0 -0
  17. data/test/file_signature_test/sample.ico +0 -0
  18. data/test/file_signature_test/sample.jar +0 -0
  19. data/test/file_signature_test/sample.jp2 +0 -0
  20. data/test/file_signature_test/sample.m3u8 +25 -0
  21. data/test/file_signature_test/sample.m4a +0 -0
  22. data/test/file_signature_test/sample.m4v +0 -0
  23. data/test/file_signature_test/sample.mid +0 -0
  24. data/test/file_signature_test/sample.mov +0 -0
  25. data/test/file_signature_test/sample.mp3 +0 -0
  26. data/test/file_signature_test/sample.mp4 +0 -0
  27. data/test/file_signature_test/sample.ogg +0 -0
  28. data/test/file_signature_test/sample.pdf +8 -0
  29. data/test/file_signature_test/sample.ppt +0 -0
  30. data/test/file_signature_test/sample.pptx +0 -0
  31. data/test/file_signature_test/sample.pubring.gpg +0 -0
  32. data/test/file_signature_test/sample.rar +0 -0
  33. data/test/file_signature_test/sample.rtf +0 -0
  34. data/test/file_signature_test/sample.sh +25 -0
  35. data/test/file_signature_test/sample.skr +0 -0
  36. data/test/file_signature_test/sample.spx +0 -0
  37. data/test/file_signature_test/sample.tar +0 -0
  38. data/test/file_signature_test/sample.tar.gz +0 -0
  39. data/test/file_signature_test/sample.wav +0 -0
  40. data/test/file_signature_test/sample.webm +0 -0
  41. data/test/file_signature_test/sample.webp +0 -0
  42. data/test/file_signature_test/sample.xcf +0 -0
  43. data/test/file_signature_test/sample.xcf.7z +0 -0
  44. data/test/file_signature_test/sample.xcf.Z +0 -0
  45. data/test/file_signature_test/sample.xcf.zip +0 -0
  46. data/test/file_signature_test/sample.xls +0 -0
  47. data/test/file_signature_test/sample.xlsx +0 -0
  48. data/test/file_signature_test/sample.xpm +39 -0
  49. data/test/file_signature_test/sample2.doc +0 -0
  50. data/test/file_signature_test/sample2.ppt +0 -0
  51. data/test/file_signature_test/sample2.xls +0 -0
  52. metadata +131 -26
data/README.md CHANGED
@@ -1,26 +1,26 @@
1
1
  * Repo: <http://github.com/robacarp/file_signature>
2
+ * Email: Jacques Distler, <distler@golem.ph.utexas.edu>
2
3
  * Email: Robert Carpenter, <coder@robacarp.com>
3
4
  * Email: Joel Parker Henderson, <joel@sixarm.com>
4
5
 
5
6
  ## Introduction
6
7
 
8
+ Magic numbers are patterns in the first few bytes of a file or data stream which (hopefully, uniquely) identify the type of the file or data stream. For example, a file which starts with "%!PS-Adobe-" is very likely a postscript file, whereas one which starts with the three bytes, 1F 8B 08, is very likely a gzip-compressed file.
7
9
 
8
- Magic numbers are the first bits of a file or data stream which uniquely identify the type of file or data stream.
9
-
10
- For example when the first bits are "BM", this identifies the file as a bitmap image file.
10
+ This gem allows you to check a file or IO stream against a list of known magic numbers, and thereby determine its type.
11
11
 
12
12
  Want to help? Feel free to fork it and submit a pull request.
13
13
 
14
14
 
15
15
  ## Install quickstart
16
16
 
17
- Install:
17
+ Install (for the previous 1.1.x version):
18
18
 
19
19
  gem install file_signature
20
20
 
21
- Bundler:
21
+ Bundler (for the current 1.2.x version):
22
22
 
23
- gem "file_signature", "~>1.0.0"
23
+ gem "file_signature", :git => 'http://github.com/distler/file_signature.git'
24
24
 
25
25
  Require:
26
26
 
@@ -28,9 +28,11 @@ Require:
28
28
 
29
29
  ## Details
30
30
 
31
- This gem infers based on widespread programming conventions for data file formats. It is tested on MRI 1.9.3. If you test it and find it working on other rubies please share your success.
31
+ This gem infers the content-type based on widespread programming conventions for data file formats. It is tested on MRI 1.8.7 and 1.9.3. If you test it and find it working on other rubies please share your success.
32
32
 
33
- These magic numbers are by convention and we are using this guide: http://www.astro.keele.ac.uk/oldusers/rno/Computing/File_magic.html
33
+ Our principal guide to these magic numbers is:
34
+ http://www.garykessler.net/library/file_sigs.html
35
+ But we've also found useful input from [libmagic](https://github.com/glensc/file/tree/master/magic/Magdir) and other sources on the internet.
34
36
 
35
37
  Typical uses of magic numbers:
36
38
 
@@ -44,16 +46,40 @@ Compare:
44
46
  * Unix magic() command for testing files on disk
45
47
  * http://shared-mime.rubyforge.org/
46
48
 
49
+ ## Usage
50
+
51
+ require 'file_signature'
52
+
53
+ The gem adds two class methods to the File class, and two instance methods to the IO class.
54
+
55
+ File.magic_number_type('myfile')
56
+
57
+ and
58
+
59
+ f = File.open('myfile')
60
+ f.magic_number_type
61
+
62
+ both return a symbol (or `nil` if the type is unrecognized) corresponding to the type of file found. Similarly,
63
+
64
+ File.mime_type('myfile')
65
+
66
+ and
67
+
68
+ f = File.open('myfile')
69
+ f.mime_type
70
+
71
+ return a string, which is the corresponding MIME-type ('`application/octet-stream`' if unrecognized).
72
+
47
73
  ##TODO
48
74
 
49
75
  * This library currently contains some pathetic handful of bytestrings for type identification... see if we can import some /usr/share/file/magic or something to extend this so its actually useful for more people.
50
- * I think it might be a good idea to return the full mime type somewhere.
51
-
76
+
52
77
 
53
78
  ## Changes
54
79
 
55
80
  * 2012-03-14 1.0.0 Update docs, tests
56
81
  * 2012-05-31 1.1.0 Add memo, reformat and rename things for clarity
82
+ * 2012-08-10 1.2.0 Many new magic numbers and corrections to existing ones, add methods to retrieve mime_type, *lots* of tests
57
83
 
58
84
  ## License
59
85
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.1
1
+ 1.2.0
@@ -5,65 +5,131 @@ Please see README
5
5
 
6
6
  class IO
7
7
 
8
- # We implement magic by using a lookup hash.
9
- # The key is a string that encodes the first bits.
8
+ # Most signatures are implemented using a lookup hash.
9
+ # The key is a string consisting of the first several bytes.
10
10
  # The value is a symbol that indicates the magic type.
11
+ # If none of these match, we look for more complicated matches
12
+ # below.
11
13
  #
12
14
  # Examples:
13
- # IO::MagicNumberType("BM") => :bitmap
14
- # IO::MagicNumberType("GIF8") => :gif
15
- # IO::MagicNumberType("\xa6\x00") => :pgp_encrypted_data
16
- #
17
- # Quirks:
18
- # - JPEG adjustment:
19
- # - Some cameras put JPEG Exif data in bytes 3 & 4,
20
- # so we only check the first two bytes of a JPEG.
21
- # - TIFF has two possible matches:
22
- # - MM** is Motorola big endian
23
- # - II** is Intel little ending
15
+ # IO::MagicNumberTypeMap("BM") => :bitmap
16
+ # IO::MagicNumberTypeMap("GIF8") => :gif
17
+ # IO::MagicNumberTypeMap("\xa6\x00") => :pgp_encrypted_data
24
18
  #
25
19
  # See:
26
20
  # - IO#magic_number_type
27
21
  # - File.magic_number_type
22
+ # - IO#mime_type
23
+ # - File.mime_type
28
24
 
29
25
  SignatureMap = {
30
26
  "BC" => :bitcode,
27
+ [0xDE,0xC0,0x17,0x0B].pack('c*') => :bitcode,
31
28
  "BM" => :bitmap,
32
- "BZ" => :bzip,
29
+ "BZh" => :bzip2,
33
30
  "MZ" => :exe,
34
31
  "SIMPLE"=> :fits,
35
- "GIF8" => :gif,
32
+ "GIF87a" => :gif,
33
+ "GIF89a" => :gif,
36
34
  "GKSM" => :gks,
37
35
  [0x01,0xDA].pack('c*') => :iris_rgb,
38
- [0xF1,0x00,0x40,0xBB].pack('c*') => :itc,
39
- [0xFF,0xD8].pack('c*') => :jpeg,
36
+ [0xFF,0xD8,0xFF].pack('c*') => :jpeg,
37
+ [0x00,0x00,0x00,0x0C,0x6A,0x50,0x20,0x20,0x0D,0x0A].pack('c*') => :jpeg2000,
40
38
  "IIN1" => :niff,
41
39
  "MThd" => :midi,
42
40
  "%PDF" => :pdf,
43
- "VIEW" => :pm,
44
- [0x89].pack('c*') + "PNG" => :png,
45
- "%!" => :postscript,
41
+ "{\\rtf" => :rtf,
42
+ [0x89].pack('c*') + "PNG" + [0x0D,0x0A,0x1A,0x0A].pack('c*') => :png,
43
+ "%!PS-Adobe-" => :postscript,
46
44
  "Y" + [0xA6].pack('c*') + "j" + [0x95].pack('c*') => :sun_rasterfile,
47
- "MM*" + [0x00].pack('c*') => :tiff,
45
+ "MM" + [0x00,0x2A].pack('c*') => :tiff,
46
+ "MM" + [0x00,0x2B].pack('c*') => :tiff,
48
47
  "II*" + [0x00].pack('c*') => :tiff,
48
+ "II+" + [0x00].pack('c*') => :tiff,
49
49
  "gimp xcf" => :gimp_xcf,
50
50
  "#FIG" => :xfig,
51
51
  "/* XPM */" => :xpm,
52
- [0x23,0x21].pack('c*') => :shebang,
52
+ "#!" => :shebang,
53
53
  [0x1F,0x9D].pack('c*') => :compress,
54
- [0x1F,0x8B].pack('c*') => :gzip,
55
- "PK" + [0x03,0x04].pack('c*') => :pkzip,
56
- "MZ" => :dos_os2_windows_executable,
57
- ".ELF" => :unix_elf,
54
+ [0x1F,0x8B,0x08].pack('c*') => :gzip,
55
+ "7z" + [0xBC,0xAF,0x27,0x1C].pack('c*') => :p7zip,
56
+ "Rar!" + [0x1A,0x07,0x00].pack('c*') => :rar,
57
+ [0x1A,0x45,0xDF,0xA3].pack('c*') => :webm,
58
+ [0x4F,0x67,0x67,0x53,0x00].pack('c*') => :ogg,
59
+ "fLaC" + [0x00,0x00,0x00,0x22].pack('c*') => :flac,
60
+ [0x00,0x00,0x01,0x00].pack('c*') => :ico,
61
+ [0x49,0x44,0x33].pack('c*') => :mp3,
62
+ "#EXTM3U" => :m3u8,
63
+ [0x7F].pack('c*') + "ELF" => :unix_elf,
58
64
  [0x99,0x00].pack('c*') => :pgp_public_ring,
59
- [0x95,0x01].pack('c*') => :pgp_security_ring,
60
- [0x95,0x00].pack('c*') => :pgp_security_ring,
65
+ [0x99,0x01].pack('c*') => :gnupg_public_ring,
66
+ [0x95,0x01].pack('c*') => :pgp_secret_ring,
67
+ [0x95,0x00].pack('c*') => :pgp_secret_ring,
61
68
  [0xA6,0x00].pack('c*') => :pgp_encrypted_data,
62
- [0xD0,0xCF,0x11,0xE0].pack('c*') => :docfile
69
+ [0x85,0x01].pack('c*') => :pgp_encrypted_data,
70
+ [0x85,0x02].pack('c*') => :pgp_encrypted_data,
63
71
  }
64
72
 
65
- SignatureSize = SignatureMap.keys.inject(0){ |m,k| k.length > m ? k.length : m }
73
+ MimeTypeMap = {
74
+ :compress => 'application/x-compress',
75
+ :gzip => 'application/x-gzip',
76
+ :pkzip => 'application/zip',
77
+ :p7zip => 'application/x-7z-compressed',
78
+ :ppt => 'application/vnd.ms-powerpoint',
79
+ :pptx => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
80
+ :xls => 'application/vnd.ms-excel',
81
+ :xlsx => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
82
+ :tar => 'application/x-tar',
83
+ :rar => 'application/x-rar-compressed',
84
+ :webm => 'video/webm',
85
+ :avi => 'video/x-msvideo',
86
+ :ogg => 'application/ogg',
87
+ :ico => 'image/vnd.microsoft.icon',
88
+ :mp3 => 'audio/mpeg',
89
+ :mp4 => 'video/mp4',
90
+ :video_3gpp => 'video/3gpp',
91
+ :video_3gpp2 => 'video/3gpp2',
92
+ :quicktime => 'video/quicktime',
93
+ :m4v => 'video/x-m4v',
94
+ :m4a => 'audio/mp4a-latm',
95
+ :aiff => 'audio/x-aiff',
96
+ :flac => 'audio/flac',
97
+ :niff => 'image/x-niff',
98
+ :midi => 'audio/midi',
99
+ :fits => 'image/fits',
100
+ :gimp_xcf => 'image/xcf',
101
+ :unix_elf => 'application/octet-stream',
102
+ :bitcode => 'application/octet-stream',
103
+ :gks => 'application/octet-stream',
104
+ :iris_rgb => 'application/octet-stream',
105
+ :pgp_encrypted_data => 'application/octet-stream',
106
+ :pgp_secret_ring => 'application/x-pgp-keyring',
107
+ :pgp_public_ring => 'application/x-pgp-keyring',
108
+ :gnupg_public_ring => 'application/x-pgp-keyring',
109
+ :docfile => 'application/msword',
110
+ :docx => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
111
+ :xfig => 'application/x-fig',
112
+ :xpm => 'image/x-xpixmap',
113
+ :shebang => 'text/plain',
114
+ :bitmap => 'image/bmp',
115
+ :png => 'image/png',
116
+ :gif => 'image/gif',
117
+ :jpeg => 'image/jpeg',
118
+ :jpeg2000 => 'image/jp2',
119
+ :sun_rasterfile => 'image/x-cmu-raster',
120
+ :postscript => 'application/postscript',
121
+ :pdf => 'application/pdf',
122
+ :rtf => 'text/rtf',
123
+ :jar => 'application/java-archive',
124
+ :tiff => 'image/tiff',
125
+ :bzip2 => 'application/x-bzip2',
126
+ :exe => 'application/x-msdownload',
127
+ :wave => 'audio/wave',
128
+ :webp => 'image/webp',
129
+ :m3u8 => 'application/vnd.apple.mpegURL'
130
+ }
66
131
 
132
+ SignatureSize = SignatureMap.keys.inject(16){ |m,k| k.length > m ? k.length : m }
67
133
 
68
134
  # Detect the data type by checking various "magic number" conventions
69
135
  # for the introductory bytes of a data stream
@@ -73,52 +139,207 @@ class IO
73
139
  # - :gzip = Unix GZIP compressed data, typical extension ".gz"
74
140
  # - :postscript = Postscript pages, typical extension ".ps"
75
141
  #
76
- # Return nil if there's no match for any known magic number.
142
+ # Return nil if there's no match for a known magic number.
77
143
  #
78
144
  # Example:
79
145
  # f = File.open("test.ps","rb")
80
- # put f.magic_number(s)
146
+ # f.magic_number_type
81
147
  # => :postscript
82
148
  #
83
149
  # See:
84
- # - IO::MagicNumberTypeHash
150
+ # - IO::MagicNumberTypeMap
151
+ # - IO::MimeTypeMap
85
152
  # - File.magic_number_type
153
+ # - IO#mime_type
154
+ # - File.mime_type
86
155
 
87
156
  def magic_number_type
157
+ #--
88
158
  return @magic_number_memo if defined? @magic_number_memo
89
159
 
90
160
  bytes = ""
161
+ bytes.force_encoding("ASCII-8BIT") if bytes.respond_to?(:force_encoding)
91
162
  type = nil
92
163
 
93
- while bytes.size < SignatureSize
94
- bytes += read(1)
164
+ read(SignatureSize).each_byte do |b|
165
+ bytes << b
95
166
  type = SignatureMap[bytes]
96
- break if type
167
+ return @magic_number_memo = type if type
168
+ end
169
+
170
+ # some cases require a more complicated match
171
+ case bytes[0,4]
172
+ when 'FORM'
173
+ type = :aiff if bytes[8,3] == 'AIF'
174
+ when 'RIFF'
175
+ case bytes[8,8]
176
+ when 'WAVEfmt '
177
+ type = :wave
178
+ when 'AVI LIST'
179
+ type = :avi
180
+ when /WEBPVP/
181
+ type = :webp
182
+ end
183
+ when "PK\003\004"
184
+ # What looks like a zip archive could contain various things
185
+ seek(30,IO::SEEK_SET)
186
+ # Look at the filename of the first file
187
+ case read(19)
188
+ when /META-INF\/PK/
189
+ type = :jar
190
+ when '[Content_Types].xml'
191
+ # This is a .docx, .pptx, or .xlsx file
192
+ # To figure out which, is grotty
193
+ curr_bytes = ['', '', '', '']
194
+ # skip to the 3rd file in the zip archive
195
+ 2.times do
196
+ while (c = getc) do
197
+ curr_bytes.push(c).shift
198
+ break if curr_bytes.join == "PK\003\004"
199
+ end
200
+ end
201
+ # and look at its filename
202
+ seek(26, IO::SEEK_CUR)
203
+ case read(5)
204
+ when "word/"
205
+ type = :docx
206
+ when /ppt\//
207
+ type = :pptx
208
+ when /xl\//
209
+ type = :xlsx
210
+ end
211
+ else
212
+ type = :pkzip
213
+ end
214
+ when [0xD0,0xCF,0x11,0xE0].pack('c*')
215
+ if bytes[4,4] == [0xA1,0xB1,0x1A,0xE1].pack('c*')
216
+ # MS Office documents have further magic bytes @ 512 byte-offset
217
+ seek(512,IO::SEEK_SET)
218
+ more_bytes = read(16)
219
+ case more_bytes[0,4]
220
+ when "\011\010\020\000"
221
+ type = :xls
222
+ when [0x60,0x21,0x1B,0xF0].pack('c*'),
223
+ [0x00,0x6E,0x1E,0xF0].pack('c*')
224
+ type = :ppt
225
+ when [0xEC,0xA5,0xC1,0x00].pack('c*')
226
+ type = :docfile
227
+ when [0xFD,0xFF,0xFF,0xFF].pack('c*')
228
+ case more_bytes[12,4]
229
+ when [0x04,0x00,0x00,0x00].pack('c*')
230
+ type = :xls
231
+ when [0x2D,0x00,0x00,0x00].pack('c*')
232
+ type = :docfile
233
+ end
234
+ end
235
+ end
97
236
  end
237
+ return (@magic_number_memo = type) if type
238
+
239
+ case bytes[4,4]
240
+ when 'moov'
241
+ type = :quicktime
242
+ when 'ftyp'
243
+ case bytes[8,3]
244
+ when 'iso', 'mp4', 'avc'
245
+ type = :mp4
246
+ when '3ge', '3gg', '3gp'
247
+ type = :video_3gpp
248
+ when '3g2'
249
+ type = :video_3gpp2
250
+ when 'M4A'
251
+ type = :m4a
252
+ when 'M4V'
253
+ type = :m4v
254
+ when 'qt '
255
+ type = :quicktime
256
+ end
257
+ end
258
+ return @magic_number_memo = type if type
259
+
260
+ #TAR files have magic bytes @ 257 byte-offset
261
+ seek(257,IO::SEEK_SET)
262
+ bytes = read(8)
263
+ type = :tar if (bytes[0,6] == "ustar\000" || bytes[0,8] == "ustar\040\040\000")
98
264
 
99
265
  @magic_number_memo = type
100
266
  end
101
267
 
268
+ #++
269
+ # Return the MIME type of the IO stream
270
+ # It's obtained by first finding the magic_number,
271
+ # and then looking up the MIME type from a hash.
272
+ # Returns 'application/octet-stream' for unknown types
273
+ #
274
+ # Example:
275
+ # f = File.open("test.ps","rb")
276
+ # f.mime_type
277
+ # => "application/postscript"
278
+ #
279
+ # See:
280
+ # - IO::MagicNumberTypeMap
281
+ # - IO::MimeTypeMap
282
+ # - IO#magic_number_type
283
+ # - File.magic_number_type
284
+ # - File.mime_type
285
+
286
+ def mime_type
287
+ return @mime_memo if defined? @mime_memo
288
+ type = self.magic_number_type
289
+ if type
290
+ m = MimeTypeMap[type]
291
+ else
292
+ m = 'application/octet-stream'
293
+ end
294
+ @mime_memo = m
295
+ end
296
+
102
297
  end
103
298
 
104
299
 
105
300
  class File
106
301
 
107
302
  # Detect the file's data type by opening the file then
108
- # using IO#magic_number_type to read the first bits.
303
+ # using IO#magic_number_type to read the first few bytes.
109
304
  #
110
305
  # Return a magic number type symbol, e.g. :bitmap, :jpg, etc.
306
+ # Returns nil if the data type is unknown
111
307
  #
112
308
  # Example:
113
- # puts File.magic_number_type("test.ps") => :postscript
309
+ # File.magic_number_type("test.ps")
310
+ # => :postscript
114
311
  #
115
312
  # See
116
- # - IO#MagicNumberTypeHash
117
- # - IO#magic_number_type
313
+ # - IO::MagicNumberTypeMap
314
+ # - IO::MimeTypeMap
315
+ # - IO#magic_number_type
316
+ # - IO#mime_type
317
+ # - File.mime_type
118
318
 
119
319
  def self.magic_number_type(file_name)
120
320
  File.open(file_name,"rb"){|f| f.magic_number_type }
121
321
  end
322
+
323
+ # Detect the file's data type by opening the file then
324
+ # using IO#magic_number_type to read the first few bytes.
325
+ #
326
+ # Return the MIME type of the file.
327
+ # Returns 'application/octet-stream' for unknown types.
328
+ #
329
+ # Example:
330
+ # File.mime_type("test.ps")
331
+ # => "application/postscript"
332
+ #
333
+ # See
334
+ # - IO::MagicNumberTypeMap
335
+ # - IO::MimeTypeMap
336
+ # - IO#magic_number_type
337
+ # - IO#mime_type
338
+ # - File.magic_number_type
339
+
340
+ def self.mime_type(file_name)
341
+ File.open(file_name,"rb"){|f| f.mime_type }
342
+ end
122
343
 
123
344
  end
124
345
 
@@ -8,41 +8,104 @@
8
8
 
9
9
  $LOAD_PATH << File.expand_path("#{File.dirname(__FILE__)}/../lib")
10
10
 
11
+ require 'rubygems'
11
12
  require 'minitest/autorun'
12
13
  require 'file_signature'
13
14
 
14
15
  describe File do
15
16
 
16
17
  FILE_TO_MAGIC_NUMBER_MAP = {
17
- 'sample.fit' => :fits,
18
- 'sample.gif' => :gif,
19
- 'sample.jpg' => :jpeg,
20
- 'sample.png' => :png,
21
- 'sample.ps' => :postscript,
22
- 'sample.ras' => :sun_rasterfile,
23
- 'sample.sgi' => :iris_rgb,
24
- 'sample.tiff' => :tiff,
25
- 'sample.xcf.bz2' => :bzip,
26
- 'sample.xcf.gz' => :gzip,
18
+ 'sample.fit' => [:fits, 'image/fits'],
19
+ 'sample.gif' => [:gif, 'image/gif'],
20
+ 'sample.jpg' => [:jpeg, 'image/jpeg'],
21
+ 'sample.png' => [:png, 'image/png'],
22
+ 'sample.jp2' => [:jpeg2000, 'image/jp2'],
23
+ 'sample.webp' => [:webp, 'image/webp'],
24
+ 'sample.mid' => [:midi, 'audio/midi'],
25
+ 'sample.ps' => [:postscript, 'application/postscript'],
26
+ 'sample.ras' => [:sun_rasterfile, 'image/x-cmu-raster'],
27
+ 'sample.sgi' => [:iris_rgb, 'application/octet-stream'],
28
+ 'sample.tiff' => [:tiff, 'image/tiff'],
29
+ 'sample.rar' => [:rar, 'application/x-rar-compressed'],
30
+ 'sample.xcf.bz2' => [:bzip2, 'application/x-bzip2'],
31
+ 'sample.xcf.gz' => [:gzip, 'application/x-gzip'],
32
+ 'sample.xcf.zip' => [:pkzip, 'application/zip'],
33
+ 'sample.xcf.7z' => [:p7zip, 'application/x-7z-compressed'],
34
+ 'sample.tar' => [:tar, 'application/x-tar'],
35
+ 'sample.tar.gz' => [:gzip, 'application/x-gzip'],
36
+ 'sample.xcf.Z' => [:compress, 'application/x-compress'],
37
+ 'sample.ppt' => [:ppt, 'application/vnd.ms-powerpoint'],
38
+ 'sample2.ppt' => [:ppt, 'application/vnd.ms-powerpoint'],
39
+ 'sample.pptx' => [:pptx, 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
40
+ 'sample.xls' => [:xls, 'application/vnd.ms-excel'],
41
+ 'sample2.xls' => [:xls, 'application/vnd.ms-excel'],
42
+ 'sample.xlsx' => [:xlsx, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
43
+ 'sample.ico' => [:ico, 'image/vnd.microsoft.icon'],
44
+ 'sample.mp3' => [:mp3, 'audio/mpeg'],
45
+ 'sample.mp4' => [:mp4, 'video/mp4'],
46
+ 'sample.m4a' => [:m4a, 'audio/mp4a-latm'],
47
+ 'sample.m4v' => [:m4v, 'video/x-m4v'],
48
+ 'sample.mov' => [:quicktime, 'video/quicktime'],
49
+ 'sample.ogg' => [:ogg, 'application/ogg'],
50
+ 'sample.spx' => [:ogg, 'application/ogg'],
51
+ 'sample.webm' => [:webm, 'video/webm'],
52
+ 'sample.avi' => [:avi, 'video/x-msvideo'],
53
+ 'sample.3gp' => [:video_3gpp, 'video/3gpp'],
54
+ 'sample.3g2' => [:video_3gpp2, 'video/3gpp2'],
55
+ 'sample.m3u8' => [:m3u8, 'application/vnd.apple.mpegURL'],
56
+ 'sample.fig' => [:xfig, 'application/x-fig'],
57
+ 'sample.xcf' => [:gimp_xcf, 'image/xcf'],
58
+ 'sample.exe' => [:exe, 'application/x-msdownload'],
59
+ 'sample.bc' => [:bitcode, 'application/octet-stream'],
60
+ 'sample.bmp' => [:bitmap, 'image/bmp'],
61
+ 'sample.xpm' => [:xpm, 'image/x-xpixmap'],
62
+ 'sample.doc' => [:docfile, 'application/msword'],
63
+ 'sample2.doc' => [:docfile, 'application/msword'],
64
+ 'sample.pdf' => [:pdf, 'application/pdf'],
65
+ 'sample.rtf' => [:rtf, 'text/rtf'],
66
+ 'sample.jar' => [:jar, 'application/java-archive'],
67
+ 'sample.wav' => [:wave, 'audio/wave'],
68
+ 'sample.flac' => [:flac, 'audio/flac'],
69
+ 'sample.aif' => [:aiff, 'audio/x-aiff'],
70
+ 'sample.elf' => [:unix_elf, 'application/octet-stream'],
71
+ 'sample.gpg' => [:pgp_encrypted_data, 'application/octet-stream'],
72
+ 'sample.pubring.gpg' => [:gnupg_public_ring, 'application/x-pgp-keyring'],
73
+ 'sample.skr' => [:pgp_secret_ring, 'application/x-pgp-keyring'],
74
+ 'sample.sh' => [:shebang, 'text/plain']
27
75
  }
28
76
 
29
- FILE_TO_MAGIC_NUMBER_MAP.each_pair do |file_name, type|
77
+ FILE_TO_MAGIC_NUMBER_MAP.each_pair do |file_name, v|
78
+ type = v[0]
79
+ mime = v[1]
30
80
  path = File.join("test","file_signature_test",file_name)
31
81
 
32
82
  it "guesses the expected magic number type by filename and path for #{type.to_s}" do
33
83
  File.magic_number_type(path).must_equal type
34
84
  end
35
85
 
86
+ it "guesses the expected mime type by filename and path for #{mime}" do
87
+ File.mime_type(path).must_equal mime
88
+ end
89
+
36
90
  f = File.open(path)
37
91
 
38
92
  it "when called from an IO object for #{type.to_s}" do
39
93
  f.magic_number_type.must_equal type
40
94
  end
41
95
 
96
+ it "when called from an IO object for #{mime}" do
97
+ f.mime_type.must_equal mime
98
+ end
99
+
42
100
  it "when called from an IO object...a second time for #{type.to_s}" do
43
101
  #test it twice for the memo
44
102
  f.magic_number_type.must_equal type
45
103
  end
46
104
 
105
+ it "when called from an IO object...a second time for #{mime}" do
106
+ #test it twice for the memo
107
+ f.mime_type.must_equal mime
108
+ end
109
+
47
110
  end
48
111
  end
@@ -0,0 +1,15 @@
1
+ #FIG 3.2
2
+ Portrait
3
+ Flush left
4
+ Metric
5
+ A4
6
+ 100.00
7
+ Single
8
+ 0
9
+ 1200 2
10
+ 0 32 #71928e
11
+ 0 33 #e7efef
12
+ 0 34 #d7e3df
13
+ 0 35 #203c38
14
+ 1 4 0 1 -1 31 50 0 20 0.000 1 0.0000 1125 675 225 225 900 675 1350 675
15
+ 4 1 -1 40 0 10 34 0.0000 4 135 90 1125 855 !\001
@@ -0,0 +1,25 @@
1
+ #EXTM3U
2
+ #EXT-X-TARGETDURATION:10
3
+ #EXT-X-MEDIA-SEQUENCE:0
4
+ #EXTINF:10,
5
+ sample-0.ts
6
+ #EXTINF:10,
7
+ sample-1.ts
8
+ #EXTINF:10,
9
+ sample-2.ts
10
+ #EXTINF:10,
11
+ sample-3.ts
12
+ #EXTINF:10,
13
+ sample-4.ts
14
+ #EXTINF:10,
15
+ sample-5.ts
16
+ #EXTINF:10,
17
+ sample-6.ts
18
+ #EXTINF:10,
19
+ sample-7.ts
20
+ #EXTINF:10,
21
+ sample-8.ts
22
+ #EXTINF:10,
23
+ sample-9.ts
24
+ #EXTINF:10,
25
+ sample-10.ts
@@ -0,0 +1,8 @@
1
+ %PDF-1.2
2
+ 3 0 obj <<
3
+ /Length 4 0 R
4
+ >>
5
+ stream
6
+ 1 0 0 1 216.04 718.08 cm
7
+ BT
8
+ /F25 17.22 Tf 0 0 Td[(X)]TJ 7.2 -2.96 Td[(Y)]TJ 9.57 2.96 Td[(-pic)-301(User's)-302(Guide)]TJ/F26 11.96 Tf -55.53 -28.89 Td[(Kristo er)-326(H.)-325(Rose)]TJ/F32 11.96 Tf 104.34 0 Td[(h)]TJ/F26 11.96 Tf 4.65 0 Td[(krisrose@ens-ly)28(on.fr)]TJ/F32 11.96 Tf 100.99 0 Td[(i)]TJ/F33 7.97 Tf 4.65 4.34 Td[()]TJ/F26 11.96 Tf -185.3 -27.79 Td[(V)82(ersion)-326(3.7,)-327(F)82(ebruary)-325(16,)-327(1999)]TJ/F35 8.97 Tf -68.76 -47.59 Td[(Abstract)]TJ/F23 8.97 Tf -95.12 -13.33 Td[(X)]TJ 4.15 -1.54 Td[(Y)]TJ 5.53 1.54 Td[(-pic)-411(is)-412(a)-411(pac)30(k)57(age)-411(for)-410(t)29(yp)-29(esetting)-410(graphs)-410(and)-411(diagrams)]TJ -8.76 -10.96 Td[(using)-284(Kn)29(uth's)-284(T)]TJ 63.31 -1.93 Td[(E)]TJ 5.12 1.93 Td[(X)-284(t)29(yp)-29(esetting)-283(system.)-335(X)]TJ 94.06 -1.54 Td[(Y)]TJ 5.53 1.54 Td[(-pic)-284(w)28(orks)-284(with)]TJ -168.02 -10.96 Td[(most)-584(of)-583(the)-583(man)29(y)-584(formats)-583(a)29(v)57(ailable;)]TJ/F36 8.97 Tf 162.16
@@ -0,0 +1,25 @@
1
+ #! /bin/sh
2
+ # Wrapper for compilers which do not understand `-c -o'.
3
+
4
+ scriptversion=2009-10-06.20; # UTC
5
+
6
+ # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009 Free Software
7
+ # Foundation, Inc.
8
+ # Written by Tom Tromey <tromey@cygnus.com>.
9
+ #
10
+ # This program is free software; you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation; either version 2, or (at your option)
13
+ # any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the GNU General Public License
21
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
22
+
23
+ # As a special exception to the GNU General Public License, if you
24
+ # distribute this file as part of a program that contains a
25
+ # configuration script generated by Auto
@@ -0,0 +1,39 @@
1
+ /* XPM */
2
+ static char * open_xpm[] = {
3
+ "16 22 14 1",
4
+ " c None",
5
+ ". c #848400",
6
+ "+ c #D6D67B",
7
+ "@ c #CECE7B",
8
+ "# c #CECE73",
9
+ "$ c #C6C66B",
10
+ "% c #BDBD5A",
11
+ "& c #BDBD52",
12
+ "* c #ADAD39",
13
+ "= c #ADAD42",
14
+ "- c #B5B54A",
15
+ "; c #C6C663",
16
+ "> c #CECE6B",
17
+ ", c #A5A5C6",
18
+ " ",
19
+ " ",
20
+ " ",
21
+ " ",
22
+ " ",
23
+ " ",
24
+ " .... ",
25
+ ".+@@#..... ",
26
+ ".@@##$$%%&. ",
27
+ ".@#.......... ",
28
+ ".#.*==--&%%;;. ",
29
+ ".#.==--&%%;;. ",
30
+ "..==--&%%;;$. ",
31
+ "..=--&%%;;$. ",
32
+ ".=--&%%;;$>. ",
33
+ "........... ",
34
+ " ",
35
+ " , ",
36
+ " ",
37
+ " , ",
38
+ " ",
39
+ " , "};
metadata CHANGED
@@ -1,25 +1,33 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: file_signature
3
- version: !ruby/object:Gem::Version
4
- version: 1.1.1
3
+ version: !ruby/object:Gem::Version
5
4
  prerelease:
5
+ version: 1.2.0
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
+ - distler
8
9
  - robacarp
9
- - SixArm
10
+ - Joel Parker Henderson @ SixArm
10
11
  autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 2012-05-31 00:00:00.000000000 Z
14
+
15
+ date: 2012-10-02 00:00:00 -06:00
16
+ default_executable:
14
17
  dependencies: []
15
- description: Monkeypatches File and IO to include a '''magic_number_type''' method
16
- which returns a symbol representing the mime type guessed based off of the first
17
- few bytes of a file.
18
- email: coder@robacarp.com
18
+
19
+ description: Monkeypatches File and IO to include a '''magic_number_type''' method which returns a symbol, and a '''mime_type''' method which returns a string, representing the mime type guessed.
20
+ email:
21
+ - distler@golem.ph.utexas.edu
22
+ - codemonkey@robacarp.com
23
+ - joel@sixarm.com
19
24
  executables: []
25
+
20
26
  extensions: []
27
+
21
28
  extra_rdoc_files: []
22
- files:
29
+
30
+ files:
23
31
  - .gemtest
24
32
  - Rakefile
25
33
  - README.md
@@ -30,46 +38,143 @@ files:
30
38
  - test/file_signature_test/sample.gif
31
39
  - test/file_signature_test/sample.jpg
32
40
  - test/file_signature_test/sample.png
41
+ - test/file_signature_test/sample.jp2
42
+ - test/file_signature_test/sample.webp
43
+ - test/file_signature_test/sample.mid
33
44
  - test/file_signature_test/sample.ps
34
45
  - test/file_signature_test/sample.ras
35
46
  - test/file_signature_test/sample.sgi
36
47
  - test/file_signature_test/sample.tiff
48
+ - test/file_signature_test/sample.rar
37
49
  - test/file_signature_test/sample.xcf.bz2
38
50
  - test/file_signature_test/sample.xcf.gz
51
+ - test/file_signature_test/sample.xcf.zip
52
+ - test/file_signature_test/sample.xcf.7z
53
+ - test/file_signature_test/sample.tar
54
+ - test/file_signature_test/sample.tar.gz
55
+ - test/file_signature_test/sample.xcf.Z
56
+ - test/file_signature_test/sample.ppt
57
+ - test/file_signature_test/sample2.ppt
58
+ - test/file_signature_test/sample.pptx
59
+ - test/file_signature_test/sample.xls
60
+ - test/file_signature_test/sample2.xls
61
+ - test/file_signature_test/sample.xlsx
62
+ - test/file_signature_test/sample.ico
63
+ - test/file_signature_test/sample.mp3
64
+ - test/file_signature_test/sample.mp4
65
+ - test/file_signature_test/sample.m4a
66
+ - test/file_signature_test/sample.m4v
67
+ - test/file_signature_test/sample.mov
68
+ - test/file_signature_test/sample.ogg
69
+ - test/file_signature_test/sample.spx
70
+ - test/file_signature_test/sample.webm
71
+ - test/file_signature_test/sample.avi
72
+ - test/file_signature_test/sample.3gp
73
+ - test/file_signature_test/sample.3g2
74
+ - test/file_signature_test/sample.m3u8
75
+ - test/file_signature_test/sample.fig
76
+ - test/file_signature_test/sample.xcf
77
+ - test/file_signature_test/sample.exe
78
+ - test/file_signature_test/sample.bc
79
+ - test/file_signature_test/sample.bmp
80
+ - test/file_signature_test/sample.xpm
81
+ - test/file_signature_test/sample.doc
82
+ - test/file_signature_test/sample2.doc
83
+ - test/file_signature_test/sample.pdf
84
+ - test/file_signature_test/sample.rtf
85
+ - test/file_signature_test/sample.jar
86
+ - test/file_signature_test/sample.wav
87
+ - test/file_signature_test/sample.flac
88
+ - test/file_signature_test/sample.aif
89
+ - test/file_signature_test/sample.elf
90
+ - test/file_signature_test/sample.gpg
91
+ - test/file_signature_test/sample.pubring.gpg
92
+ - test/file_signature_test/sample.skr
93
+ - test/file_signature_test/sample.sh
94
+ has_rdoc: true
39
95
  homepage: http://github.com/robacarp/file_signature
40
96
  licenses: []
97
+
41
98
  post_install_message:
42
99
  rdoc_options: []
43
- require_paths:
100
+
101
+ require_paths:
44
102
  - lib
45
- required_ruby_version: !ruby/object:Gem::Requirement
103
+ required_ruby_version: !ruby/object:Gem::Requirement
46
104
  none: false
47
- requirements:
48
- - - ! '>='
49
- - !ruby/object:Gem::Version
50
- version: '0'
51
- required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: "0"
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
110
  none: false
53
- requirements:
54
- - - ! '>='
55
- - !ruby/object:Gem::Version
56
- version: '0'
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: "0"
57
115
  requirements: []
116
+
58
117
  rubyforge_project:
59
- rubygems_version: 1.8.22
118
+ rubygems_version: 1.6.2
60
119
  signing_key:
61
120
  specification_version: 3
62
- summary: File signature adds the ability to inspect the first few bytes of a file
63
- to guess at mime-type.
64
- test_files:
121
+ summary: File signature adds the ability to inspect the first few bytes of a file to guess at mime-type.
122
+ test_files:
65
123
  - test/file_signature_test.rb
66
124
  - test/file_signature_test/sample.fit
67
125
  - test/file_signature_test/sample.gif
68
126
  - test/file_signature_test/sample.jpg
69
127
  - test/file_signature_test/sample.png
128
+ - test/file_signature_test/sample.jp2
129
+ - test/file_signature_test/sample.webp
130
+ - test/file_signature_test/sample.mid
70
131
  - test/file_signature_test/sample.ps
71
132
  - test/file_signature_test/sample.ras
72
133
  - test/file_signature_test/sample.sgi
73
134
  - test/file_signature_test/sample.tiff
135
+ - test/file_signature_test/sample.rar
74
136
  - test/file_signature_test/sample.xcf.bz2
75
137
  - test/file_signature_test/sample.xcf.gz
138
+ - test/file_signature_test/sample.xcf.zip
139
+ - test/file_signature_test/sample.xcf.7z
140
+ - test/file_signature_test/sample.tar
141
+ - test/file_signature_test/sample.tar.gz
142
+ - test/file_signature_test/sample.xcf.Z
143
+ - test/file_signature_test/sample.ppt
144
+ - test/file_signature_test/sample2.ppt
145
+ - test/file_signature_test/sample.pptx
146
+ - test/file_signature_test/sample.xls
147
+ - test/file_signature_test/sample2.xls
148
+ - test/file_signature_test/sample.xlsx
149
+ - test/file_signature_test/sample.ico
150
+ - test/file_signature_test/sample.mp3
151
+ - test/file_signature_test/sample.mp4
152
+ - test/file_signature_test/sample.m4a
153
+ - test/file_signature_test/sample.m4v
154
+ - test/file_signature_test/sample.mov
155
+ - test/file_signature_test/sample.ogg
156
+ - test/file_signature_test/sample.spx
157
+ - test/file_signature_test/sample.webm
158
+ - test/file_signature_test/sample.avi
159
+ - test/file_signature_test/sample.3gp
160
+ - test/file_signature_test/sample.3g2
161
+ - test/file_signature_test/sample.m3u8
162
+ - test/file_signature_test/sample.fig
163
+ - test/file_signature_test/sample.xcf
164
+ - test/file_signature_test/sample.exe
165
+ - test/file_signature_test/sample.bc
166
+ - test/file_signature_test/sample.bmp
167
+ - test/file_signature_test/sample.xpm
168
+ - test/file_signature_test/sample.doc
169
+ - test/file_signature_test/sample2.doc
170
+ - test/file_signature_test/sample.pdf
171
+ - test/file_signature_test/sample.rtf
172
+ - test/file_signature_test/sample.jar
173
+ - test/file_signature_test/sample.wav
174
+ - test/file_signature_test/sample.flac
175
+ - test/file_signature_test/sample.aif
176
+ - test/file_signature_test/sample.elf
177
+ - test/file_signature_test/sample.gpg
178
+ - test/file_signature_test/sample.pubring.gpg
179
+ - test/file_signature_test/sample.skr
180
+ - test/file_signature_test/sample.sh