Commit e0a7b70df059588150b7c9e6b9cd5b109262922c
1 parent
21eb6ccf
Exists in
master
and in
1 other branch
adding mime types and xml simple gems
Showing
16 changed files
with
5896 additions
and
1 deletions
Show diff stats
README.markdown
... | ... | @@ -20,7 +20,9 @@ This will create a Rails 2.3.2 app with Heroku-recommended code: |
20 | 20 | * jQuery for Javascript |
21 | 21 | * Clearance for authentication |
22 | 22 | * Cucumber, Shoulda, Factory Girl, & Mocha for testing |
23 | -* Evergreen for CSS framework | |
23 | +* Flutie for CSS framework | |
24 | +* Formtastic for form builders | |
25 | +* Inherited Resources for RESTful controllers | |
24 | 26 | * Blitz for features, model, controller, & helper generators |
25 | 27 | |
26 | 28 | If you don't have all the necessary gems, they will be installed. | ... | ... |
... | ... | @@ -0,0 +1,133 @@ |
1 | +--- !ruby/object:Gem::Specification | |
2 | +name: mime-types | |
3 | +version: !ruby/object:Gem::Version | |
4 | + version: "1.16" | |
5 | +platform: ruby | |
6 | +authors: | |
7 | +- Austin Ziegler | |
8 | +autorequire: | |
9 | +bindir: bin | |
10 | +cert_chain: | |
11 | +- | | |
12 | + -----BEGIN CERTIFICATE----- | |
13 | + MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMQ8wDQYDVQQDDAZhdXN0 | |
14 | + aW4xGTAXBgoJkiaJk/IsZAEZFglydWJ5Zm9yZ2UxEzARBgoJkiaJk/IsZAEZFgNv | |
15 | + cmcwHhcNMDcxMTMwMDE0OTAwWhcNMDgxMTI5MDE0OTAwWjBBMQ8wDQYDVQQDDAZh | |
16 | + dXN0aW4xGTAXBgoJkiaJk/IsZAEZFglydWJ5Zm9yZ2UxEzARBgoJkiaJk/IsZAEZ | |
17 | + FgNvcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOSg1riVV22ord | |
18 | + q0t4YVx57GDPMqdjlnQ5M7D9iBnnW0c8pifegbb0dm+mC9hJSuPtcJS53+YPTy9F | |
19 | + wlZbjI2cN+P0QLUUTOlZus2sHq7Pr9jz2nJf8hCT7t5Vlopv1N/xlKtXqpcyEkhJ | |
20 | + JHTrxe1avGwuq8DIAIN01moQJ+hJlgrnR2eRJRazTGiXKBLGAFXDl/Agn78MHx6w | |
21 | + pzZ2APydo6Nuk7Ktq1MvCHzLzCACbOlYawFk3/9dbsmHhVjsi6YW+CpEJ2BnTy8X | |
22 | + JBXlyNTk1JxDmcs3RzNr+9AmDQh3u4LcmJnWxtLJo9e7UBxH/bwVORJyf8dAOmOm | |
23 | + HO6bFTLvAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW | |
24 | + BBT9e1+pFfcV1LxVxILANqLtZzI/XTANBgkqhkiG9w0BAQUFAAOCAQEAhg42pvrL | |
25 | + uVlqAaHqV88KqgnW2ymCWm0ePohicFTcyiS5Yj5cN3OXLsPV2x12zqvLCFsfpA4u | |
26 | + D/85rngKFHITSW0h9e/CIT/pwQA6Uuqkbr0ypkoU6mlNIDS10PlK7aXXFTCP9X3f | |
27 | + IndAajiNRgKwb67nj+zpQwHa6dmooyRQIRRijrMKTgY6ebaCCrm7J3BLLTJAyxOW | |
28 | + +1nD0cuTkBEKIuSVK06E19Ml+xWt2bdtS9Wz/8jHivJ0SvUpbmhKVzh1rBslwm65 | |
29 | + JpQgg3SsV23vF4qkCa2dt1FL+FeWJyCdj23DV3598X72RYiK3D6muWURck16jqeA | |
30 | + BRvUFuFHOwa/yA== | |
31 | + -----END CERTIFICATE----- | |
32 | + | |
33 | +date: 2009-03-02 00:00:00 -05:00 | |
34 | +default_executable: | |
35 | +dependencies: | |
36 | +- !ruby/object:Gem::Dependency | |
37 | + name: archive-tar-minitar | |
38 | + type: :development | |
39 | + version_requirement: | |
40 | + version_requirements: !ruby/object:Gem::Requirement | |
41 | + requirements: | |
42 | + - - ~> | |
43 | + - !ruby/object:Gem::Version | |
44 | + version: "0.5" | |
45 | + version: | |
46 | +- !ruby/object:Gem::Dependency | |
47 | + name: nokogiri | |
48 | + type: :development | |
49 | + version_requirement: | |
50 | + version_requirements: !ruby/object:Gem::Requirement | |
51 | + requirements: | |
52 | + - - ~> | |
53 | + - !ruby/object:Gem::Version | |
54 | + version: "1.2" | |
55 | + version: | |
56 | +- !ruby/object:Gem::Dependency | |
57 | + name: rcov | |
58 | + type: :development | |
59 | + version_requirement: | |
60 | + version_requirements: !ruby/object:Gem::Requirement | |
61 | + requirements: | |
62 | + - - ~> | |
63 | + - !ruby/object:Gem::Version | |
64 | + version: "0.8" | |
65 | + version: | |
66 | +- !ruby/object:Gem::Dependency | |
67 | + name: hoe | |
68 | + type: :development | |
69 | + version_requirement: | |
70 | + version_requirements: !ruby/object:Gem::Requirement | |
71 | + requirements: | |
72 | + - - ">=" | |
73 | + - !ruby/object:Gem::Version | |
74 | + version: 1.8.3 | |
75 | + version: | |
76 | +description: MIME::Types for Ruby originally based on and synchronized with MIME::Types for Perl by Mark Overmeer, copyright 2001 - 2009. As of version 1.15, the data format for the MIME::Type list has changed and the synchronization will no longer happen. | |
77 | +email: | |
78 | +- austin@rubyforge.org | |
79 | +executables: [] | |
80 | + | |
81 | +extensions: [] | |
82 | + | |
83 | +extra_rdoc_files: | |
84 | +- History.txt | |
85 | +- Install.txt | |
86 | +- Licence.txt | |
87 | +- README.txt | |
88 | +files: | |
89 | +- History.txt | |
90 | +- Install.txt | |
91 | +- Licence.txt | |
92 | +- Manifest.txt | |
93 | +- README.txt | |
94 | +- Rakefile | |
95 | +- lib/mime/types.rb | |
96 | +- lib/mime/types.rb.data | |
97 | +- mime-types.gemspec | |
98 | +- setup.rb | |
99 | +- test/test_mime_type.rb | |
100 | +- test/test_mime_types.rb | |
101 | +has_rdoc: true | |
102 | +homepage: http://mime-types.rubyforge.org/ | |
103 | +licenses: [] | |
104 | + | |
105 | +post_install_message: | |
106 | +rdoc_options: | |
107 | +- --main | |
108 | +- README.txt | |
109 | +require_paths: | |
110 | +- bin | |
111 | +- lib | |
112 | +required_ruby_version: !ruby/object:Gem::Requirement | |
113 | + requirements: | |
114 | + - - ">=" | |
115 | + - !ruby/object:Gem::Version | |
116 | + version: "0" | |
117 | + version: | |
118 | +required_rubygems_version: !ruby/object:Gem::Requirement | |
119 | + requirements: | |
120 | + - - ">=" | |
121 | + - !ruby/object:Gem::Version | |
122 | + version: "0" | |
123 | + version: | |
124 | +requirements: [] | |
125 | + | |
126 | +rubyforge_project: mime-types | |
127 | +rubygems_version: 1.3.4 | |
128 | +signing_key: | |
129 | +specification_version: 2 | |
130 | +summary: Manages a MIME Content-Type database that will return the Content-Type for a given filename. | |
131 | +test_files: | |
132 | +- test/test_mime_type.rb | |
133 | +- test/test_mime_types.rb | ... | ... |
... | ... | @@ -0,0 +1,107 @@ |
1 | +== MIME::Types 1.16 | |
2 | +* Made compatible with Ruby 1.8.6, 1.8.7, and 1.9.1. | |
3 | +* Switched to the 'hoe' gem system and added a lot of build-time tools. | |
4 | +* Updated the MIME types to the list based on the values in the Perl library | |
5 | + version 1.27. Also updated based on external source information and bug | |
6 | + reports. | |
7 | +* This is the last planned version of MIME::Types 1.x. Work will be | |
8 | + starting soon on MIME::Types 2.x with richer data querying mechanisms | |
9 | + and support for external data sources. | |
10 | + | |
11 | +== MIME::Types 1.15 | |
12 | +* Removed lib/mime/type.rb to form a single MIME::Types database source. It | |
13 | + is unlikely that one will ever need MIME::Type without MIME::Types. | |
14 | +* Re-synchronized the MIME type list with the sources, focusing primarily on | |
15 | + the IANA list. | |
16 | +* Added more detailed source information for MIME::Type objects. | |
17 | +* Changed MIME::Types from a module to a class with a default instance. There | |
18 | + should be no difference in usage. | |
19 | +* Removed MIME::Types::DATA_VERSION; it is now an attribute on the | |
20 | + MIME::Types instance. | |
21 | +* NOTE: Synchronization with the Perl version of MIME::Types is no longer a | |
22 | + priority as of this release. The data format and information has changed. | |
23 | +* Removed MIME::Types.by_suffix and MIME::Types.by_mediatype. | |
24 | + | |
25 | +== MIME::Types 1.13.1 | |
26 | +* Fixed a problem with the installer running tests. This now works. | |
27 | +* Improved the implementation of MIME::Type.signature? | |
28 | +* Moved code around to use the class << self idiom instead of always | |
29 | + prepending the module/class name. | |
30 | +* Added two new best-guess implementations of functions found in Perl's | |
31 | + MIME::Types implementation (1.13). Do not rely on these until the purpose | |
32 | + and implementation is stabilised. | |
33 | +* Updated the MIME list to reflect changes noted by | |
34 | + Ville Skyttä <ville.skytta@iki.fi>. | |
35 | +* Added a new constant to MIME::Types, DATA_VERSION. This will allow the Ruby | |
36 | + version number to be updated separately from the Perl version while keeping | |
37 | + the MIME Type list version in sync. | |
38 | + | |
39 | +== MIME::Types 1.13 | |
40 | + ! WARNING: This version changes the API of MIME::Types ! | |
41 | + ! WARNING: This version is compatible with Ruby 1.8 and higher ONLY ! | |
42 | +* Removed dependency on InstallPackage; offering 1.13 as either .tar.gz or | |
43 | + .gem. | |
44 | +* Split into two files, mime/type.rb and mime/types.rb. This will make | |
45 | + maintaining the list of changes easier. | |
46 | +* Changed the MIME::Type construction API. Accepts only a single String | |
47 | + argument (but does no named type-checking) and yields self. | |
48 | +* Removed private methods #init_extensions, #init_encoding, and #init_system | |
49 | + and replaced with #extensions=, #encoding=, and #system=. | |
50 | +* Added #default_encoding to return 'quoted-printable' or 'base64' depending | |
51 | + on the media type of the MIME type. | |
52 | +* Added #raw_media_type and #raw_sub_type to provide the non-simplified | |
53 | + versions of the media type and subtype. | |
54 | +* Alternative constructors MIME::Type.from_array, MIME::Type.from_hash, and | |
55 | + MIME::Type.from_mime_type added to compensate for the removal of named type | |
56 | + checking in the original constructor. | |
57 | +* Added #to_str, #to_a, and #to_hash methods. The latter two will provide | |
58 | + output suitable for use in #from_array and #from_hash. | |
59 | +* Removed "binary" encoding and enforced the use of a valid encoding string. | |
60 | +* Added #system? returning true if the MIME::Type is an OS-specific | |
61 | + MIME::Type. | |
62 | +* Added #platform? returning true if the MIME::Type is an OS-specific | |
63 | + MIME::Type for the current RUBY_PLATFORM. | |
64 | +* Added #like? returning true if the simplified type matches the other value | |
65 | + provided. #<'application/x-excel'>.like?('application/excel') is true. | |
66 | +* Added #complete? returning true if the MIME::Type specifies an extension | |
67 | + list. | |
68 | +* Updated the MIME type list to reflect additions by Mark Overmeer for Perl's | |
69 | + MIME::Types 1.12 and the official IANA list as of 2004.04.06. A number of | |
70 | + formerly "registered" MIME types are now no longer registered (e.g., | |
71 | + application/excel is now application/x-excel). This ensures that the | |
72 | + simplified type still works with applications, but does not report an | |
73 | + unregistered type as registered. | |
74 | +* Restored MIME type list to Mark Overmeer's format to facilitate easy | |
75 | + exchange between the two projects. | |
76 | +* Added additional unit tests from Mark Overmeer's 1.12 version. | |
77 | + | |
78 | +== MIME::Types 1.07 | |
79 | +* Changed version numbering to match Perl MIME::Types 1.07. | |
80 | +* Re-synchronized with Mark Overmeer's list in Perl PMIME::Types 1.07. | |
81 | +* [NN Poster] updated the attributes for the PGP types. | |
82 | + | |
83 | +== MIME::Types 1.005 | |
84 | +* Changed to Phil Thomson's InstallPackage. | |
85 | +* Added several types from Perl MIME::Types 1.005. | |
86 | +* Cleaned up data format; some data formats will show up with proper data now. | |
87 | + | |
88 | +== MIME::Types 1.004 | |
89 | +* Updated to match Perl MIME::Types 1.004, links credited to Dan Puro. Adds | |
90 | + new reference list to http://www.indiana.edu/cgi-bin-local/mimetypes | |
91 | +* Removed InvalidType and replaced with TypeError. | |
92 | +* Changed instances of #type to #class. | |
93 | +* Cleaned up how simplified versions are created. | |
94 | + | |
95 | +== MIME::Types 1.003 | |
96 | +* Initial release based on Perl MIME::Types 1.003. | |
97 | + | |
98 | +== Copyright | |
99 | + MIME::Types | |
100 | + A Ruby implementation of a MIME Types information library. Based in spirit | |
101 | + on the Perl MIME::Types information library by Mark Overmeer. | |
102 | + http://rubyforge.org/projects/mime-types/ | |
103 | + | |
104 | + Licensed under the Ruby disjunctive licence with the GNU GPL or the Perl | |
105 | + Artistic licence. See Licence.txt for more information. | |
106 | + | |
107 | + Copyright 2003 - 2009 Austin Ziegler | ... | ... |
... | ... | @@ -0,0 +1,17 @@ |
1 | +Installing this package is as simple as: | |
2 | + | |
3 | + % ruby setup.rb | |
4 | + | |
5 | +Alternatively, you can use the Gem version of MIME::Types available as | |
6 | +mime-types-1.16.gem from the usual sources. | |
7 | + | |
8 | +== Copyright | |
9 | + MIME::Types | |
10 | + A Ruby implementation of a MIME Types information library. Based in spirit | |
11 | + on the Perl MIME::Types information library by Mark Overmeer. | |
12 | + http://rubyforge.org/projects/mime-types/ | |
13 | + | |
14 | + Licensed under the Ruby disjunctive licence with the GNU GPL or the Perl | |
15 | + Artistic licence. See Licence.txt for more information. | |
16 | + | |
17 | + Copyright 2003 - 2009 Austin Ziegler | ... | ... |
... | ... | @@ -0,0 +1,15 @@ |
1 | += MIME::Types for Ruby | |
2 | +Homepage:: http://rubyforge.org/projects/mime-types/ | |
3 | +Copyright:: Copyright (c) 2003 - 2006 Austin Ziegler. | |
4 | +Summary:: Ruby's licence, Perl Aristic Licence, | |
5 | + GNU GPL version 2 (or later) | |
6 | + | |
7 | +The text of the Ruby licence can be found at: | |
8 | +http://www.ruby-lang.org/en/LICENSE.txt | |
9 | + | |
10 | +The text of the Perl Artistic Licence can be found at: | |
11 | +http://www.perl.com/pub/a/language/misc/Artistic.html | |
12 | + | |
13 | +The text of the GNU GPL can be found at: http://www.gnu.org/copyleft/gpl.html | |
14 | + | |
15 | +If you do not accept one of these licences, you may not use this software. | ... | ... |
... | ... | @@ -0,0 +1,28 @@ |
1 | += README: Mime::Types for Ruby | |
2 | +This library allows for the identification of a file's likely MIME content | |
3 | +type. This is release 1.16. The identification of MIME content type is based | |
4 | +on a file's filename extensions. | |
5 | + | |
6 | +MIME::Types for Ruby originally based on and synchronized with MIME::Types | |
7 | +for Perl by Mark Overmeer, copyright 2001 - 2009. As of version 1.15, the | |
8 | +data format for the MIME::Type list has changed and the synchronization will | |
9 | +no longer happen. | |
10 | + | |
11 | +Homepage:: http://mime-types.rubyforge.org/ | |
12 | +Copyright:: 2002 - 2009, Austin Ziegler | |
13 | + Based in part on prior work copyright Mark Overmeer | |
14 | + | |
15 | +== Licensing | |
16 | +MIME::Types is available under three disjunctive licences, as detailed in the | |
17 | +Licence.txt file. | |
18 | + | |
19 | +== Copyright | |
20 | + MIME::Types | |
21 | + A Ruby implementation of a MIME Types information library. Based in spirit | |
22 | + on the Perl MIME::Types information library by Mark Overmeer. | |
23 | + http://rubyforge.org/projects/mime-types/ | |
24 | + | |
25 | + Licensed under the Ruby disjunctive licence with the GNU GPL or the Perl | |
26 | + Artistic licence. See Licence.txt for more information. | |
27 | + | |
28 | + Copyright 2003 - 2009 Austin Ziegler | ... | ... |
... | ... | @@ -0,0 +1,316 @@ |
1 | +#! /usr/bin/env rake | |
2 | +#-- | |
3 | +# MIME::Types | |
4 | +# A Ruby implementation of a MIME Types information library. Based in spirit | |
5 | +# on the Perl MIME::Types information library by Mark Overmeer. | |
6 | +# http://rubyforge.org/projects/mime-types/ | |
7 | +# | |
8 | +# Licensed under the Ruby disjunctive licence with the GNU GPL or the Perl | |
9 | +# Artistic licence. See Licence.txt for more information. | |
10 | +# | |
11 | +# Copyright 2003 - 2009 Austin Ziegler | |
12 | +#++ | |
13 | + | |
14 | +require 'rubygems' | |
15 | +require 'hoe' | |
16 | + | |
17 | +$LOAD_PATH.unshift('lib') | |
18 | + | |
19 | +require 'mime/types' | |
20 | + | |
21 | +PKG_NAME = 'mime-types' | |
22 | +PKG_VERSION = MIME::Types::VERSION | |
23 | +PKG_DIST = "#{PKG_NAME}-#{PKG_VERSION}" | |
24 | +PKG_TAR = "pkg/#{PKG_DIST}.tar.gz" | |
25 | +MANIFEST = File.read("Manifest.txt").split | |
26 | + | |
27 | +hoe = Hoe.new PKG_NAME, PKG_VERSION do |p| | |
28 | + p.rubyforge_name = PKG_NAME | |
29 | + # This is a lie because I will continue to use Archive::Tar::Minitar. | |
30 | + p.need_tar = false | |
31 | + # need_zip - Should package create a zipfile? [default: false] | |
32 | + | |
33 | + p.author = [ "Austin Ziegler" ] | |
34 | + p.email = %W(austin@rubyforge.org) | |
35 | + p.url = "http://mime-types.rubyforge.org/" | |
36 | + p.summary = %q{Manages a MIME Content-Type database that will return the Content-Type for a given filename.} | |
37 | + p.changes = p.paragraphs_of("History.txt", 0..0).join("\n\n") | |
38 | + p.description = p.paragraphs_of("README.txt", 1..1).join("\n\n") | |
39 | + | |
40 | + p.extra_dev_deps << %w(archive-tar-minitar ~>0.5) | |
41 | + p.extra_dev_deps << %w(nokogiri ~>1.2) | |
42 | + p.extra_dev_deps << %w(rcov ~>0.8) | |
43 | + | |
44 | + p.clean_globs << "coverage" | |
45 | + | |
46 | + p.spec_extras[:extra_rdoc_files] = MANIFEST.grep(/txt$/) - ["Manifest.txt"] | |
47 | +end | |
48 | + | |
49 | +begin | |
50 | + require 'rcov/rcovtask' | |
51 | + Rcov::RcovTask.new do |t| | |
52 | + t.libs << 'test' | |
53 | + t.test_files = hoe.test_files | |
54 | + t.verbose = true | |
55 | + end | |
56 | +rescue LoadError | |
57 | + puts "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov" | |
58 | +end | |
59 | + | |
60 | +=begin | |
61 | + require 'cucumber/rake/task' | |
62 | + Cucumber::Rake::Task.new(:features) | |
63 | +rescue LoadError | |
64 | + puts "Cucumber is not available. In order to run features, you must: sudo gem install cucumber" | |
65 | +=end | |
66 | + | |
67 | +desc "Build a MIME::Types .tar.gz distribution." | |
68 | +task :tar => [ PKG_TAR ] | |
69 | +file PKG_TAR => [ :test ] do |t| | |
70 | + require 'archive/tar/minitar' | |
71 | + require 'zlib' | |
72 | + files = MANIFEST.map { |f| | |
73 | + fn = File.join(PKG_DIST, f) | |
74 | + tm = File.stat(f).mtime | |
75 | + | |
76 | + if File.directory?(f) | |
77 | + { :name => fn, :mode => 0755, :dir => true, :mtime => tm } | |
78 | + else | |
79 | + mode = if f =~ %r{^bin} | |
80 | + 0755 | |
81 | + else | |
82 | + 0644 | |
83 | + end | |
84 | + data = File.read(f) | |
85 | + { :name => fn, :mode => mode, :data => data, :size => data.size, | |
86 | + :mtime => tm } | |
87 | + end | |
88 | + } | |
89 | + | |
90 | + begin | |
91 | + unless File.directory?(File.dirname(t.name)) | |
92 | + require 'fileutils' | |
93 | + FileUtils.mkdir_p File.dirname(t.name) | |
94 | + end | |
95 | + tf = File.open(t.name, 'wb') | |
96 | + gz = Zlib::GzipWriter.new(tf) | |
97 | + tw = Archive::Tar::Minitar::Writer.new(gz) | |
98 | + | |
99 | + files.each do |entry| | |
100 | + if entry[:dir] | |
101 | + tw.mkdir(entry[:name], entry) | |
102 | + else | |
103 | + tw.add_file_simple(entry[:name], entry) { |os| | |
104 | + os.write(entry[:data]) | |
105 | + } | |
106 | + end | |
107 | + end | |
108 | + ensure | |
109 | + tw.close if tw | |
110 | + gz.close if gz | |
111 | + end | |
112 | +end | |
113 | +task :package => [ PKG_TAR ] | |
114 | + | |
115 | +desc "Build the manifest file from the current set of files." | |
116 | +task :build_manifest do |t| | |
117 | + require 'find' | |
118 | + | |
119 | + hoerc = File.join(File.dirname(__FILE__), ".hoerc") | |
120 | + hoerc = File.open(hoerc, "rb") { |f| f.read } | |
121 | + hoerc = YAML::load(hoerc) | |
122 | + | |
123 | + paths = [] | |
124 | + Find.find(".") do |path| | |
125 | + next if File.directory?(path) || path =~ hoerc["exclude"] | |
126 | + paths << path.sub(%r{^\./}, '') | |
127 | + end | |
128 | + | |
129 | + paths = paths.sort.join("\n") | |
130 | + | |
131 | + File.open("Manifest.txt", "w") do |f| | |
132 | + f.puts paths | |
133 | + end | |
134 | + | |
135 | + puts paths | |
136 | +end | |
137 | + | |
138 | +desc "Download the current MIME type registrations from IANA." | |
139 | +task :iana, :save, :destination do |t, args| | |
140 | + save_type = args.save || :text | |
141 | + save_type = save_type.to_sym | |
142 | + | |
143 | + case save_type | |
144 | + when :text, :both, :html | |
145 | + nil | |
146 | + else | |
147 | + raise "Unknown save type provided. Must be one of text, both, or html." | |
148 | + end | |
149 | + | |
150 | + destination = args.destination || "type-lists" | |
151 | + | |
152 | + require 'open-uri' | |
153 | + require 'nokogiri' | |
154 | + require 'cgi' | |
155 | + | |
156 | + class IANAParser | |
157 | + include Comparable | |
158 | + | |
159 | + INDEX = %q(http://www.iana.org/assignments/media-types/) | |
160 | + CONTACT_PEOPLE = %r{http://www.iana.org/assignments/contact-people.html?#(.*)} | |
161 | + RFC_EDITOR = %r{http://www.rfc-editor.org/rfc/rfc(\d+).txt} | |
162 | + IETF_RFC = %r{http://www.ietf.org/rfc/rfc(\d+).txt} | |
163 | + IETF_RFC_TOOLS = %r{http://tools.ietf.org/html/rfc(\d+)} | |
164 | + | |
165 | + class << self | |
166 | + def load_index | |
167 | + @types ||= {} | |
168 | + | |
169 | + Nokogiri::HTML(open(INDEX) { |f| f.read }).xpath('//p/a').each do |tag| | |
170 | + href_match = %r{^/assignments/media-types/(.+)/$}.match(tag['href']) | |
171 | + next if href_match.nil? | |
172 | + type = href_match.captures[0] | |
173 | + @types[tag.content] = IANAParser.new(tag.content, type) | |
174 | + end | |
175 | + end | |
176 | + | |
177 | + attr_reader :types | |
178 | + end | |
179 | + | |
180 | + def initialize(name, type) | |
181 | + @name = name | |
182 | + @type = type | |
183 | + @url = File.join(INDEX, @type) | |
184 | + end | |
185 | + | |
186 | + attr_reader :name | |
187 | + attr_reader :type | |
188 | + attr_reader :url | |
189 | + attr_reader :html | |
190 | + | |
191 | + def download(name = nil) | |
192 | + @html = Nokogiri::HTML(open(name || @url) { |f| f.read }) | |
193 | + end | |
194 | + | |
195 | + def save_html | |
196 | + File.open("#@name.html", "wb") { |w| w.write @html } | |
197 | + end | |
198 | + | |
199 | + def <=>(o) | |
200 | + self.name <=> o.name | |
201 | + end | |
202 | + | |
203 | + def parse | |
204 | + nodes = html.xpath("//table//table//tr") | |
205 | + | |
206 | + # How many <td> children does the first node have? | |
207 | + node_count = nodes.first.children.select { |node| node.elem? }.size | |
208 | + | |
209 | + @mime_types = nodes.map do |node| | |
210 | + next if node == nodes.first | |
211 | + elems = node.children.select { |n| n.elem? } | |
212 | + next if elems.size.zero? | |
213 | + raise "size mismatch #{elems.size} != #{node_count}" if node_count != elems.size | |
214 | + | |
215 | + case elems.size | |
216 | + when 3 | |
217 | + subtype_index = 1 | |
218 | + refnode_index = 2 | |
219 | + when 4 | |
220 | + subtype_index = 1 | |
221 | + refnode_index = 3 | |
222 | + else | |
223 | + raise "Unknown element size." | |
224 | + end | |
225 | + | |
226 | + subtype = elems[subtype_index].content.chomp.strip | |
227 | + refnodes = elems[refnode_index].children.select { |n| n.elem? }.map { |ref| | |
228 | + case ref['href'] | |
229 | + when CONTACT_PEOPLE | |
230 | + tag = CGI::unescape($1).chomp.strip | |
231 | + if tag == ref.content | |
232 | + "[#{ref.content}]" | |
233 | + else | |
234 | + "[#{ref.content}=#{tag}]" | |
235 | + end | |
236 | + when RFC_EDITOR, IETF_RFC, IETF_RFC_TOOLS | |
237 | + "RFC#$1" | |
238 | + when %r{(https?://.*)} | |
239 | + "{#{ref.content}=#$1}" | |
240 | + else | |
241 | + ref | |
242 | + end | |
243 | + } | |
244 | + refs = refnodes.join(',') | |
245 | + | |
246 | + "#@type/#{subtype} 'IANA,#{refs}" | |
247 | + end.compact | |
248 | + | |
249 | + @mime_types | |
250 | + end | |
251 | + | |
252 | + def save_text | |
253 | + File.open("#@name.txt", "wb") { |w| w.write @mime_types.join("\n") } | |
254 | + end | |
255 | + end | |
256 | + | |
257 | + puts "Downloading index of MIME types from #{IANAParser::INDEX}." | |
258 | + IANAParser.load_index | |
259 | + | |
260 | + require 'fileutils' | |
261 | + FileUtils.mkdir_p destination | |
262 | + Dir.chdir destination do | |
263 | + IANAParser.types.values.sort.each do |parser| | |
264 | + next if parser.name == "example" or parser.name == "mime" | |
265 | + puts "Downloading #{parser.name} from #{parser.url}" | |
266 | + parser.download | |
267 | + | |
268 | + if :html == save_type || :both == save_type | |
269 | + puts "Saving #{parser.name}.html" | |
270 | + parser.save_html | |
271 | + end | |
272 | + | |
273 | + puts "Parsing #{parser.name} HTML" | |
274 | + parser.parse | |
275 | + | |
276 | + if :text == save_type || :both == save_type | |
277 | + puts "Saving #{parser.name}.txt" | |
278 | + parser.save_text | |
279 | + end | |
280 | + end | |
281 | + end | |
282 | +end | |
283 | + | |
284 | +desc "Shows known MIME type sources." | |
285 | +task :mime_type_sources do | |
286 | + puts <<-EOS | |
287 | +http://www.ltsw.se/knbase/internet/mime.htp | |
288 | +http://www.webmaster-toolkit.com/mime-types.shtml | |
289 | +http://plugindoc.mozdev.org/winmime.php | |
290 | +http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html | |
291 | +http://www.feedforall.com/mime-types.htm | |
292 | +http://www.iana.org/assignments/media-types/ | |
293 | + EOS | |
294 | +end | |
295 | + | |
296 | +desc "Validate the RubyGem spec for GitHub." | |
297 | +task :github_validate_spec do |t| | |
298 | + require 'yaml' | |
299 | + | |
300 | + require 'rubygems/specification' | |
301 | + data = File.read("#{PKG_NAME}.gemspec") | |
302 | + spec = nil | |
303 | + | |
304 | + if data !~ %r{!ruby/object:Gem::Specification} | |
305 | + code = "$SAFE = 3\n#{data}" | |
306 | + p code.split($/)[44] | |
307 | + Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join | |
308 | + else | |
309 | + spec = YAML.load(data) | |
310 | + end | |
311 | + | |
312 | + spec.validate | |
313 | + | |
314 | + puts spec | |
315 | + puts "OK" | |
316 | +end | ... | ... |
... | ... | @@ -0,0 +1,751 @@ |
1 | +# vim: ft=ruby encoding=utf-8 | |
2 | +#-- | |
3 | +# MIME::Types | |
4 | +# A Ruby implementation of a MIME Types information library. Based in spirit | |
5 | +# on the Perl MIME::Types information library by Mark Overmeer. | |
6 | +# http://rubyforge.org/projects/mime-types/ | |
7 | +# | |
8 | +# Licensed under the Ruby disjunctive licence with the GNU GPL or the Perl | |
9 | +# Artistic licence. See Licence.txt for more information. | |
10 | +# | |
11 | +# Copyright 2003 - 2009 Austin Ziegler | |
12 | +#++ | |
13 | + | |
14 | +# The namespace for MIME applications, tools, and libraries. | |
15 | +module MIME | |
16 | + # Reflects a MIME Content-Type which is in invalid format (e.g., it isn't | |
17 | + # in the form of type/subtype). | |
18 | + class InvalidContentType < RuntimeError; end | |
19 | + | |
20 | + # The definition of one MIME content-type. | |
21 | + # | |
22 | + # == Usage | |
23 | + # require 'mime/types' | |
24 | + # | |
25 | + # plaintext = MIME::Types['text/plain'] | |
26 | + # print plaintext.media_type # => 'text' | |
27 | + # print plaintext.sub_type # => 'plain' | |
28 | + # | |
29 | + # puts plaintext.extensions.join(" ") # => 'asc txt c cc h hh cpp' | |
30 | + # | |
31 | + # puts plaintext.encoding # => 8bit | |
32 | + # puts plaintext.binary? # => false | |
33 | + # puts plaintext.ascii? # => true | |
34 | + # puts plaintext == 'text/plain' # => true | |
35 | + # puts MIME::Type.simplified('x-appl/x-zip') # => 'appl/zip' | |
36 | + # | |
37 | + class Type | |
38 | + VERSION = '1.16' | |
39 | + | |
40 | + include Comparable | |
41 | + | |
42 | + MEDIA_TYPE_RE = %r{([-\w.+]+)/([-\w.+]*)}o | |
43 | + UNREG_RE = %r{[Xx]-}o | |
44 | + ENCODING_RE = %r{(?:base64|7bit|8bit|quoted\-printable)}o | |
45 | + PLATFORM_RE = %r|#{RUBY_PLATFORM}|o | |
46 | + | |
47 | + SIGNATURES = %w(application/pgp-keys application/pgp | |
48 | + application/pgp-signature application/pkcs10 | |
49 | + application/pkcs7-mime application/pkcs7-signature | |
50 | + text/vcard) | |
51 | + | |
52 | + IANA_URL = "http://www.iana.org/assignments/media-types/%s/%s" | |
53 | + RFC_URL = "http://rfc-editor.org/rfc/rfc%s.txt" | |
54 | + DRAFT_URL = "http://datatracker.ietf.org/public/idindex.cgi?command=id_details&filename=%s" | |
55 | + LTSW_URL = "http://www.ltsw.se/knbase/internet/%s.htp" | |
56 | + CONTACT_URL = "http://www.iana.org/assignments/contact-people.htm#%s" | |
57 | + | |
58 | + # Returns +true+ if the simplified type matches the current | |
59 | + def like?(other) | |
60 | + if other.respond_to?(:simplified) | |
61 | + @simplified == other.simplified | |
62 | + else | |
63 | + @simplified == Type.simplified(other) | |
64 | + end | |
65 | + end | |
66 | + | |
67 | + # Compares the MIME::Type against the exact content type or the | |
68 | + # simplified type (the simplified type will be used if comparing against | |
69 | + # something that can be treated as a String with #to_s). In comparisons, | |
70 | + # this is done against the lowercase version of the MIME::Type. | |
71 | + def <=>(other) | |
72 | + if other.respond_to?(:content_type) | |
73 | + @content_type.downcase <=> other.content_type.downcase | |
74 | + elsif other.respond_to?(:to_s) | |
75 | + @simplified <=> Type.simplified(other.to_s) | |
76 | + else | |
77 | + @content_type.downcase <=> other.downcase | |
78 | + end | |
79 | + end | |
80 | + | |
81 | + # Compares the MIME::Type based on how reliable it is before doing a | |
82 | + # normal <=> comparison. Used by MIME::Types#[] to sort types. The | |
83 | + # comparisons involved are: | |
84 | + # | |
85 | + # 1. self.simplified <=> other.simplified (ensures that we | |
86 | + # don't try to compare different types) | |
87 | + # 2. IANA-registered definitions > other definitions. | |
88 | + # 3. Generic definitions > platform definitions. | |
89 | + # 3. Complete definitions > incomplete definitions. | |
90 | + # 4. Current definitions > obsolete definitions. | |
91 | + # 5. Obselete with use-instead references > obsolete without. | |
92 | + # 6. Obsolete use-instead definitions are compared. | |
93 | + def priority_compare(other) | |
94 | + pc = simplified <=> other.simplified | |
95 | + | |
96 | + if pc.zero? and registered? != other.registered? | |
97 | + pc = registered? ? -1 : 1 | |
98 | + end | |
99 | + | |
100 | + if pc.zero? and platform? != other.platform? | |
101 | + pc = platform? ? 1 : -1 | |
102 | + end | |
103 | + | |
104 | + if pc.zero? and complete? != other.complete? | |
105 | + pc = complete? ? -1 : 1 | |
106 | + end | |
107 | + | |
108 | + if pc.zero? and obsolete? != other.obsolete? | |
109 | + pc = obsolete? ? 1 : -1 | |
110 | + end | |
111 | + | |
112 | + if pc.zero? and obsolete? and (use_instead != other.use_instead) | |
113 | + pc = if use_instead.nil? | |
114 | + -1 | |
115 | + elsif other.use_instead.nil? | |
116 | + 1 | |
117 | + else | |
118 | + use_instead <=> other.use_instead | |
119 | + end | |
120 | + end | |
121 | + | |
122 | + pc | |
123 | + end | |
124 | + | |
125 | + # Returns +true+ if the other object is a MIME::Type and the content | |
126 | + # types match. | |
127 | + def eql?(other) | |
128 | + other.kind_of?(MIME::Type) and self == other | |
129 | + end | |
130 | + | |
131 | + # Returns the whole MIME content-type string. | |
132 | + # | |
133 | + # text/plain => text/plain | |
134 | + # x-chemical/x-pdb => x-chemical/x-pdb | |
135 | + attr_reader :content_type | |
136 | + # Returns the media type of the simplified MIME type. | |
137 | + # | |
138 | + # text/plain => text | |
139 | + # x-chemical/x-pdb => chemical | |
140 | + attr_reader :media_type | |
141 | + # Returns the media type of the unmodified MIME type. | |
142 | + # | |
143 | + # text/plain => text | |
144 | + # x-chemical/x-pdb => x-chemical | |
145 | + attr_reader :raw_media_type | |
146 | + # Returns the sub-type of the simplified MIME type. | |
147 | + # | |
148 | + # text/plain => plain | |
149 | + # x-chemical/x-pdb => pdb | |
150 | + attr_reader :sub_type | |
151 | + # Returns the media type of the unmodified MIME type. | |
152 | + # | |
153 | + # text/plain => plain | |
154 | + # x-chemical/x-pdb => x-pdb | |
155 | + attr_reader :raw_sub_type | |
156 | + # The MIME types main- and sub-label can both start with <tt>x-</tt>, | |
157 | + # which indicates that it is a non-registered name. Of course, after | |
158 | + # registration this flag can disappear, adds to the confusing | |
159 | + # proliferation of MIME types. The simplified string has the <tt>x-</tt> | |
160 | + # removed and are translated to lowercase. | |
161 | + # | |
162 | + # text/plain => text/plain | |
163 | + # x-chemical/x-pdb => chemical/pdb | |
164 | + attr_reader :simplified | |
165 | + # The list of extensions which are known to be used for this MIME::Type. | |
166 | + # Non-array values will be coerced into an array with #to_a. Array | |
167 | + # values will be flattened and +nil+ values removed. | |
168 | + attr_accessor :extensions | |
169 | + remove_method :extensions= ; | |
170 | + def extensions=(ext) #:nodoc: | |
171 | + @extensions = [ext].flatten.compact | |
172 | + end | |
173 | + | |
174 | + # The encoding (7bit, 8bit, quoted-printable, or base64) required to | |
175 | + # transport the data of this content type safely across a network, which | |
176 | + # roughly corresponds to Content-Transfer-Encoding. A value of +nil+ or | |
177 | + # <tt>:default</tt> will reset the #encoding to the #default_encoding | |
178 | + # for the MIME::Type. Raises ArgumentError if the encoding provided is | |
179 | + # invalid. | |
180 | + # | |
181 | + # If the encoding is not provided on construction, this will be either | |
182 | + # 'quoted-printable' (for text/* media types) and 'base64' for eveything | |
183 | + # else. | |
184 | + attr_accessor :encoding | |
185 | + remove_method :encoding= ; | |
186 | + def encoding=(enc) #:nodoc: | |
187 | + if enc.nil? or enc == :default | |
188 | + @encoding = self.default_encoding | |
189 | + elsif enc =~ ENCODING_RE | |
190 | + @encoding = enc | |
191 | + else | |
192 | + raise ArgumentError, "The encoding must be nil, :default, base64, 7bit, 8bit, or quoted-printable." | |
193 | + end | |
194 | + end | |
195 | + | |
196 | + # The regexp for the operating system that this MIME::Type is specific | |
197 | + # to. | |
198 | + attr_accessor :system | |
199 | + remove_method :system= ; | |
200 | + def system=(os) #:nodoc: | |
201 | + if os.nil? or os.kind_of?(Regexp) | |
202 | + @system = os | |
203 | + else | |
204 | + @system = %r|#{os}| | |
205 | + end | |
206 | + end | |
207 | + # Returns the default encoding for the MIME::Type based on the media | |
208 | + # type. | |
209 | + attr_reader :default_encoding | |
210 | + remove_method :default_encoding | |
211 | + def default_encoding | |
212 | + (@media_type == 'text') ? 'quoted-printable' : 'base64' | |
213 | + end | |
214 | + | |
215 | + # Returns the media type or types that should be used instead of this | |
216 | + # media type, if it is obsolete. If there is no replacement media type, | |
217 | + # or it is not obsolete, +nil+ will be returned. | |
218 | + attr_reader :use_instead | |
219 | + remove_method :use_instead | |
220 | + def use_instead | |
221 | + return nil unless @obsolete | |
222 | + @use_instead | |
223 | + end | |
224 | + | |
225 | + # Returns +true+ if the media type is obsolete. | |
226 | + def obsolete? | |
227 | + @obsolete ? true : false | |
228 | + end | |
229 | + # Sets the obsolescence indicator for this media type. | |
230 | + attr_writer :obsolete | |
231 | + | |
232 | + # The documentation for this MIME::Type. Documentation about media | |
233 | + # types will be found on a media type definition as a comment. | |
234 | + # Documentation will be found through #docs. | |
235 | + attr_accessor :docs | |
236 | + remove_method :docs= ; | |
237 | + def docs=(d) | |
238 | + if d | |
239 | + a = d.scan(%r{use-instead:#{MEDIA_TYPE_RE}}) | |
240 | + | |
241 | + if a.empty? | |
242 | + @use_instead = nil | |
243 | + else | |
244 | + @use_instead = a.map { |el| "#{el[0]}/#{el[1]}" } | |
245 | + end | |
246 | + end | |
247 | + @docs = d | |
248 | + end | |
249 | + | |
250 | + # The encoded URL list for this MIME::Type. See #urls for more | |
251 | + # information. | |
252 | + attr_accessor :url | |
253 | + # The decoded URL list for this MIME::Type. | |
254 | + # The special URL value IANA will be translated into: | |
255 | + # http://www.iana.org/assignments/media-types/<mediatype>/<subtype> | |
256 | + # | |
257 | + # The special URL value RFC### will be translated into: | |
258 | + # http://www.rfc-editor.org/rfc/rfc###.txt | |
259 | + # | |
260 | + # The special URL value DRAFT:name will be translated into: | |
261 | + # https://datatracker.ietf.org/public/idindex.cgi? | |
262 | + # command=id_detail&filename=<name> | |
263 | + # | |
264 | + # The special URL value LTSW will be translated into: | |
265 | + # http://www.ltsw.se/knbase/internet/<mediatype>.htp | |
266 | + # | |
267 | + # The special URL value [token] will be translated into: | |
268 | + # http://www.iana.org/assignments/contact-people.htm#<token> | |
269 | + # | |
270 | + # These values will be accessible through #urls, which always returns an | |
271 | + # array. | |
272 | + def urls | |
273 | + @url.map do |el| | |
274 | + case el | |
275 | + when %r{^IANA$} | |
276 | + IANA_URL % [ @media_type, @sub_type ] | |
277 | + when %r{^RFC(\d+)$} | |
278 | + RFC_URL % $1 | |
279 | + when %r{^DRAFT:(.+)$} | |
280 | + DRAFT_URL % $1 | |
281 | + when %r{^LTSW$} | |
282 | + LTSW_URL % @media_type | |
283 | + when %r<^\{([^=]+)=([^\]]+)\}> | |
284 | + [$1, $2] | |
285 | + when %r{^\[([^=]+)=([^\]]+)\]} | |
286 | + [$1, CONTACT_URL % $2] | |
287 | + when %r{^\[([^\]]+)\]} | |
288 | + CONTACT_URL % $1 | |
289 | + else | |
290 | + el | |
291 | + end | |
292 | + end | |
293 | + end | |
294 | + | |
295 | + class << self | |
296 | + # The MIME types main- and sub-label can both start with <tt>x-</tt>, | |
297 | + # which indicates that it is a non-registered name. Of course, after | |
298 | + # registration this flag can disappear, adds to the confusing | |
299 | + # proliferation of MIME types. The simplified string has the | |
300 | + # <tt>x-</tt> removed and are translated to lowercase. | |
301 | + def simplified(content_type) | |
302 | + matchdata = MEDIA_TYPE_RE.match(content_type) | |
303 | + | |
304 | + if matchdata.nil? | |
305 | + simplified = nil | |
306 | + else | |
307 | + media_type = matchdata.captures[0].downcase.gsub(UNREG_RE, '') | |
308 | + subtype = matchdata.captures[1].downcase.gsub(UNREG_RE, '') | |
309 | + simplified = "#{media_type}/#{subtype}" | |
310 | + end | |
311 | + simplified | |
312 | + end | |
313 | + | |
314 | + # Creates a MIME::Type from an array in the form of: | |
315 | + # [type-name, [extensions], encoding, system] | |
316 | + # | |
317 | + # +extensions+, +encoding+, and +system+ are optional. | |
318 | + # | |
319 | + # MIME::Type.from_array("application/x-ruby", ['rb'], '8bit') | |
320 | + # MIME::Type.from_array(["application/x-ruby", ['rb'], '8bit']) | |
321 | + # | |
322 | + # These are equivalent to: | |
323 | + # | |
324 | + # MIME::Type.new('application/x-ruby') do |t| | |
325 | + # t.extensions = %w(rb) | |
326 | + # t.encoding = '8bit' | |
327 | + # end | |
328 | + def from_array(*args) #:yields MIME::Type.new: | |
329 | + # Dereferences the array one level, if necessary. | |
330 | + args = args[0] if args[0].kind_of?(Array) | |
331 | + | |
332 | + if args.size.between?(1, 8) | |
333 | + m = MIME::Type.new(args[0]) do |t| | |
334 | + t.extensions = args[1] if args.size > 1 | |
335 | + t.encoding = args[2] if args.size > 2 | |
336 | + t.system = args[3] if args.size > 3 | |
337 | + t.obsolete = args[4] if args.size > 4 | |
338 | + t.docs = args[5] if args.size > 5 | |
339 | + t.url = args[6] if args.size > 6 | |
340 | + t.registered = args[7] if args.size > 7 | |
341 | + end | |
342 | + yield m if block_given? | |
343 | + else | |
344 | + raise ArgumentError, "Array provided must contain between one and eight elements." | |
345 | + end | |
346 | + m | |
347 | + end | |
348 | + | |
349 | + # Creates a MIME::Type from a hash. Keys are case-insensitive, | |
350 | + # dashes may be replaced with underscores, and the internal Symbol | |
351 | + # of the lowercase-underscore version can be used as well. That is, | |
352 | + # Content-Type can be provided as content-type, Content_Type, | |
353 | + # content_type, or :content_type. | |
354 | + # | |
355 | + # Known keys are <tt>Content-Type</tt>, | |
356 | + # <tt>Content-Transfer-Encoding</tt>, <tt>Extensions</tt>, and | |
357 | + # <tt>System</tt>. | |
358 | + # | |
359 | + # MIME::Type.from_hash('Content-Type' => 'text/x-yaml', | |
360 | + # 'Content-Transfer-Encoding' => '8bit', | |
361 | + # 'System' => 'linux', | |
362 | + # 'Extensions' => ['yaml', 'yml']) | |
363 | + # | |
364 | + # This is equivalent to: | |
365 | + # | |
366 | + # MIME::Type.new('text/x-yaml') do |t| | |
367 | + # t.encoding = '8bit' | |
368 | + # t.system = 'linux' | |
369 | + # t.extensions = ['yaml', 'yml'] | |
370 | + # end | |
371 | + def from_hash(hash) #:yields MIME::Type.new: | |
372 | + type = {} | |
373 | + hash.each_pair do |k, v| | |
374 | + type[k.to_s.tr('A-Z', 'a-z').gsub(/-/, '_').to_sym] = v | |
375 | + end | |
376 | + | |
377 | + m = MIME::Type.new(type[:content_type]) do |t| | |
378 | + t.extensions = type[:extensions] | |
379 | + t.encoding = type[:content_transfer_encoding] | |
380 | + t.system = type[:system] | |
381 | + t.obsolete = type[:obsolete] | |
382 | + t.docs = type[:docs] | |
383 | + t.url = type[:url] | |
384 | + t.registered = type[:registered] | |
385 | + end | |
386 | + | |
387 | + yield m if block_given? | |
388 | + m | |
389 | + end | |
390 | + | |
391 | + # Essentially a copy constructor. | |
392 | + # | |
393 | + # MIME::Type.from_mime_type(plaintext) | |
394 | + # | |
395 | + # is equivalent to: | |
396 | + # | |
397 | + # MIME::Type.new(plaintext.content_type.dup) do |t| | |
398 | + # t.extensions = plaintext.extensions.dup | |
399 | + # t.system = plaintext.system.dup | |
400 | + # t.encoding = plaintext.encoding.dup | |
401 | + # end | |
402 | + def from_mime_type(mime_type) #:yields the new MIME::Type: | |
403 | + m = MIME::Type.new(mime_type.content_type.dup) do |t| | |
404 | + t.extensions = mime_type.extensions.map { |e| e.dup } | |
405 | + t.url = mime_type.url && mime_type.url.map { |e| e.dup } | |
406 | + | |
407 | + mime_type.system && t.system = mime_type.system.dup | |
408 | + mime_type.encoding && t.encoding = mime_type.encoding.dup | |
409 | + | |
410 | + t.obsolete = mime_type.obsolete? | |
411 | + t.registered = mime_type.registered? | |
412 | + | |
413 | + mime_type.docs && t.docs = mime_type.docs.dup | |
414 | + | |
415 | + end | |
416 | + | |
417 | + yield m if block_given? | |
418 | + end | |
419 | + end | |
420 | + | |
421 | + # Builds a MIME::Type object from the provided MIME Content Type value | |
422 | + # (e.g., 'text/plain' or 'applicaton/x-eruby'). The constructed object | |
423 | + # is yielded to an optional block for additional configuration, such as | |
424 | + # associating extensions and encoding information. | |
425 | + def initialize(content_type) #:yields self: | |
426 | + matchdata = MEDIA_TYPE_RE.match(content_type) | |
427 | + | |
428 | + if matchdata.nil? | |
429 | + raise InvalidContentType, "Invalid Content-Type provided ('#{content_type}')" | |
430 | + end | |
431 | + | |
432 | + @content_type = content_type | |
433 | + @raw_media_type = matchdata.captures[0] | |
434 | + @raw_sub_type = matchdata.captures[1] | |
435 | + | |
436 | + @simplified = MIME::Type.simplified(@content_type) | |
437 | + matchdata = MEDIA_TYPE_RE.match(@simplified) | |
438 | + @media_type = matchdata.captures[0] | |
439 | + @sub_type = matchdata.captures[1] | |
440 | + | |
441 | + self.extensions = nil | |
442 | + self.encoding = :default | |
443 | + self.system = nil | |
444 | + self.registered = true | |
445 | + self.url = nil | |
446 | + self.obsolete = nil | |
447 | + self.docs = nil | |
448 | + | |
449 | + yield self if block_given? | |
450 | + end | |
451 | + | |
452 | + # MIME content-types which are not regestered by IANA nor defined in | |
453 | + # RFCs are required to start with <tt>x-</tt>. This counts as well for | |
454 | + # a new media type as well as a new sub-type of an existing media | |
455 | + # type. If either the media-type or the content-type begins with | |
456 | + # <tt>x-</tt>, this method will return +false+. | |
457 | + def registered? | |
458 | + if (@raw_media_type =~ UNREG_RE) || (@raw_sub_type =~ UNREG_RE) | |
459 | + false | |
460 | + else | |
461 | + @registered | |
462 | + end | |
463 | + end | |
464 | + attr_writer :registered #:nodoc: | |
465 | + | |
466 | + # MIME types can be specified to be sent across a network in particular | |
467 | + # formats. This method returns +true+ when the MIME type encoding is set | |
468 | + # to <tt>base64</tt>. | |
469 | + def binary? | |
470 | + @encoding == 'base64' | |
471 | + end | |
472 | + | |
473 | + # MIME types can be specified to be sent across a network in particular | |
474 | + # formats. This method returns +false+ when the MIME type encoding is | |
475 | + # set to <tt>base64</tt>. | |
476 | + def ascii? | |
477 | + not binary? | |
478 | + end | |
479 | + | |
480 | + # Returns +true+ when the simplified MIME type is in the list of known | |
481 | + # digital signatures. | |
482 | + def signature? | |
483 | + SIGNATURES.include?(@simplified.downcase) | |
484 | + end | |
485 | + | |
486 | + # Returns +true+ if the MIME::Type is specific to an operating system. | |
487 | + def system? | |
488 | + not @system.nil? | |
489 | + end | |
490 | + | |
491 | + # Returns +true+ if the MIME::Type is specific to the current operating | |
492 | + # system as represented by RUBY_PLATFORM. | |
493 | + def platform? | |
494 | + system? and (RUBY_PLATFORM =~ @system) | |
495 | + end | |
496 | + | |
497 | + # Returns +true+ if the MIME::Type specifies an extension list, | |
498 | + # indicating that it is a complete MIME::Type. | |
499 | + def complete? | |
500 | + not @extensions.empty? | |
501 | + end | |
502 | + | |
503 | + # Returns the MIME type as a string. | |
504 | + def to_s | |
505 | + @content_type | |
506 | + end | |
507 | + | |
508 | + # Returns the MIME type as a string for implicit conversions. | |
509 | + def to_str | |
510 | + @content_type | |
511 | + end | |
512 | + | |
513 | + # Returns the MIME type as an array suitable for use with | |
514 | + # MIME::Type.from_array. | |
515 | + def to_a | |
516 | + [ @content_type, @extensions, @encoding, @system, @obsolete, @docs, | |
517 | + @url, registered? ] | |
518 | + end | |
519 | + | |
520 | + # Returns the MIME type as an array suitable for use with | |
521 | + # MIME::Type.from_hash. | |
522 | + def to_hash | |
523 | + { 'Content-Type' => @content_type, | |
524 | + 'Content-Transfer-Encoding' => @encoding, | |
525 | + 'Extensions' => @extensions, | |
526 | + 'System' => @system, | |
527 | + 'Obsolete' => @obsolete, | |
528 | + 'Docs' => @docs, | |
529 | + 'URL' => @url, | |
530 | + 'Registered' => registered?, | |
531 | + } | |
532 | + end | |
533 | + end | |
534 | + | |
535 | + # = MIME::Types | |
536 | + # MIME types are used in MIME-compliant communications, as in e-mail or | |
537 | + # HTTP traffic, to indicate the type of content which is transmitted. | |
538 | + # MIME::Types provides the ability for detailed information about MIME | |
539 | + # entities (provided as a set of MIME::Type objects) to be determined and | |
540 | + # used programmatically. There are many types defined by RFCs and vendors, | |
541 | + # so the list is long but not complete; don't hesitate to ask to add | |
542 | + # additional information. This library follows the IANA collection of MIME | |
543 | + # types (see below for reference). | |
544 | + # | |
545 | + # == Description | |
546 | + # MIME types are used in MIME entities, as in email or HTTP traffic. It is | |
547 | + # useful at times to have information available about MIME types (or, | |
548 | + # inversely, about files). A MIME::Type stores the known information about | |
549 | + # one MIME type. | |
550 | + # | |
551 | + # == Usage | |
552 | + # require 'mime/types' | |
553 | + # | |
554 | + # plaintext = MIME::Types['text/plain'] | |
555 | + # print plaintext.media_type # => 'text' | |
556 | + # print plaintext.sub_type # => 'plain' | |
557 | + # | |
558 | + # puts plaintext.extensions.join(" ") # => 'asc txt c cc h hh cpp' | |
559 | + # | |
560 | + # puts plaintext.encoding # => 8bit | |
561 | + # puts plaintext.binary? # => false | |
562 | + # puts plaintext.ascii? # => true | |
563 | + # puts plaintext.obsolete? # => false | |
564 | + # puts plaintext.registered? # => true | |
565 | + # puts plaintext == 'text/plain' # => true | |
566 | + # puts MIME::Type.simplified('x-appl/x-zip') # => 'appl/zip' | |
567 | + # | |
568 | + # This module is built to conform to the MIME types of RFCs 2045 and 2231. | |
569 | + # It follows the official IANA registry at | |
570 | + # http://www.iana.org/assignments/media-types/ and | |
571 | + # ftp://ftp.iana.org/assignments/media-types with some unofficial types | |
572 | + # added from the the collection at | |
573 | + # http://www.ltsw.se/knbase/internet/mime.htp | |
574 | + # | |
575 | + # This is originally based on Perl MIME::Types by Mark Overmeer. | |
576 | + # | |
577 | + # = Author | |
578 | + # Copyright:: Copyright (c) 2002 - 2009 by Austin Ziegler | |
579 | + # <austin@rubyforge.org> | |
580 | + # Version:: 1.16 | |
581 | + # Based On:: Perl | |
582 | + # MIME::Types[http://search.cpan.org/author/MARKOV/MIME-Types-1.27/MIME/Types.pm], | |
583 | + # Copyright (c) 2001 - 2009 by Mark Overmeer | |
584 | + # <mimetypes@overmeer.net>. | |
585 | + # Licence:: Ruby's, Perl Artistic, or GPL version 2 (or later) | |
586 | + # See Also:: http://www.iana.org/assignments/media-types/ | |
587 | + # http://www.ltsw.se/knbase/internet/mime.htp | |
588 | + # | |
589 | + class Types | |
590 | + # The released version of Ruby MIME::Types | |
591 | + VERSION = '1.16' | |
592 | + | |
593 | + # The data version. | |
594 | + attr_reader :data_version | |
595 | + | |
596 | + def initialize(data_version = nil) | |
597 | + @type_variants = Hash.new { |h, k| h[k] = [] } | |
598 | + @extension_index = Hash.new { |h, k| h[k] = [] } | |
599 | + end | |
600 | + | |
601 | + def add_type_variant(mime_type) #:nodoc: | |
602 | + @type_variants[mime_type.simplified] << mime_type | |
603 | + end | |
604 | + | |
605 | + def index_extensions(mime_type) #:nodoc: | |
606 | + mime_type.extensions.each { |ext| @extension_index[ext] << mime_type } | |
607 | + end | |
608 | + | |
609 | + @__types__ = self.new(VERSION) | |
610 | + | |
611 | + # Returns a list of MIME::Type objects, which may be empty. The optional | |
612 | + # flag parameters are :complete (finds only complete MIME::Type objects) | |
613 | + # and :platform (finds only MIME::Types for the current platform). It is | |
614 | + # possible for multiple matches to be returned for either type (in the | |
615 | + # example below, 'text/plain' returns two values -- one for the general | |
616 | + # case, and one for VMS systems. | |
617 | + # | |
618 | + # puts "\nMIME::Types['text/plain']" | |
619 | + # MIME::Types['text/plain'].each { |t| puts t.to_a.join(", ") } | |
620 | + # | |
621 | + # puts "\nMIME::Types[/^image/, :complete => true]" | |
622 | + # MIME::Types[/^image/, :complete => true].each do |t| | |
623 | + # puts t.to_a.join(", ") | |
624 | + # end | |
625 | + # | |
626 | + # If multiple type definitions are returned, returns them sorted as | |
627 | + # follows: | |
628 | + # 1. Complete definitions sort before incomplete ones; | |
629 | + # 2. IANA-registered definitions sort before LTSW-recorded | |
630 | + # definitions. | |
631 | + # 3. Generic definitions sort before platform-specific ones; | |
632 | + # 4. Current definitions sort before obsolete ones; | |
633 | + # 5. Obsolete definitions with use-instead clauses sort before those | |
634 | + # without; | |
635 | + # 6. Obsolete definitions use-instead clauses are compared. | |
636 | + # 7. Sort on name. | |
637 | + def [](type_id, flags = {}) | |
638 | + if type_id.kind_of?(Regexp) | |
639 | + matches = [] | |
640 | + @type_variants.each_key do |k| | |
641 | + matches << @type_variants[k] if k =~ type_id | |
642 | + end | |
643 | + matches.flatten! | |
644 | + elsif type_id.kind_of?(MIME::Type) | |
645 | + matches = [type_id] | |
646 | + else | |
647 | + matches = @type_variants[MIME::Type.simplified(type_id)] | |
648 | + end | |
649 | + | |
650 | + matches.delete_if { |e| not e.complete? } if flags[:complete] | |
651 | + matches.delete_if { |e| not e.platform? } if flags[:platform] | |
652 | + | |
653 | + matches.sort { |a, b| a.priority_compare(b) } | |
654 | + end | |
655 | + | |
656 | + # Return the list of MIME::Types which belongs to the file based on its | |
657 | + # filename extension. If +platform+ is +true+, then only file types that | |
658 | + # are specific to the current platform will be returned. | |
659 | + # | |
660 | + # puts "MIME::Types.type_for('citydesk.xml') | |
661 | + # => "#{MIME::Types.type_for('citydesk.xml')}" | |
662 | + # puts "MIME::Types.type_for('citydesk.gif') | |
663 | + # => "#{MIME::Types.type_for('citydesk.gif')}" | |
664 | + def type_for(filename, platform = false) | |
665 | + ext = filename.chomp.downcase.gsub(/.*\./o, '') | |
666 | + list = @extension_index[ext] | |
667 | + list.delete_if { |e| not e.platform? } if platform | |
668 | + list | |
669 | + end | |
670 | + | |
671 | + # A synonym for MIME::Types.type_for | |
672 | + def of(filename, platform = false) | |
673 | + type_for(filename, platform) | |
674 | + end | |
675 | + | |
676 | + # Add one or more MIME::Type objects to the set of known types. Each | |
677 | + # type should be experimental (e.g., 'application/x-ruby'). If the type | |
678 | + # is already known, a warning will be displayed. | |
679 | + # | |
680 | + # <b>Please inform the maintainer of this module when registered types | |
681 | + # are missing.</b> | |
682 | + def add(*types) | |
683 | + types.each do |mime_type| | |
684 | + if @type_variants.include?(mime_type.simplified) | |
685 | + if @type_variants[mime_type.simplified].include?(mime_type) | |
686 | + warn "Type #{mime_type} already registered as a variant of #{mime_type.simplified}." | |
687 | + end | |
688 | + end | |
689 | + add_type_variant(mime_type) | |
690 | + index_extensions(mime_type) | |
691 | + end | |
692 | + end | |
693 | + | |
694 | + class << self | |
695 | + def add_type_variant(mime_type) #:nodoc: | |
696 | + @__types__.add_type_variant(mime_type) | |
697 | + end | |
698 | + | |
699 | + def index_extensions(mime_type) #:nodoc: | |
700 | + @__types__.index_extensions(mime_type) | |
701 | + end | |
702 | + | |
703 | + # Returns a list of MIME::Type objects, which may be empty. The | |
704 | + # optional flag parameters are :complete (finds only complete | |
705 | + # MIME::Type objects) and :platform (finds only MIME::Types for the | |
706 | + # current platform). It is possible for multiple matches to be | |
707 | + # returned for either type (in the example below, 'text/plain' returns | |
708 | + # two values -- one for the general case, and one for VMS systems. | |
709 | + # | |
710 | + # puts "\nMIME::Types['text/plain']" | |
711 | + # MIME::Types['text/plain'].each { |t| puts t.to_a.join(", ") } | |
712 | + # | |
713 | + # puts "\nMIME::Types[/^image/, :complete => true]" | |
714 | + # MIME::Types[/^image/, :complete => true].each do |t| | |
715 | + # puts t.to_a.join(", ") | |
716 | + # end | |
717 | + def [](type_id, flags = {}) | |
718 | + @__types__[type_id, flags] | |
719 | + end | |
720 | + | |
721 | + # Return the list of MIME::Types which belongs to the file based on | |
722 | + # its filename extension. If +platform+ is +true+, then only file | |
723 | + # types that are specific to the current platform will be returned. | |
724 | + # | |
725 | + # puts "MIME::Types.type_for('citydesk.xml') | |
726 | + # => "#{MIME::Types.type_for('citydesk.xml')}" | |
727 | + # puts "MIME::Types.type_for('citydesk.gif') | |
728 | + # => "#{MIME::Types.type_for('citydesk.gif')}" | |
729 | + def type_for(filename, platform = false) | |
730 | + @__types__.type_for(filename, platform) | |
731 | + end | |
732 | + | |
733 | + # A synonym for MIME::Types.type_for | |
734 | + def of(filename, platform = false) | |
735 | + @__types__.type_for(filename, platform) | |
736 | + end | |
737 | + | |
738 | + # Add one or more MIME::Type objects to the set of known types. Each | |
739 | + # type should be experimental (e.g., 'application/x-ruby'). If the | |
740 | + # type is already known, a warning will be displayed. | |
741 | + # | |
742 | + # <b>Please inform the maintainer of this module when registered types | |
743 | + # are missing.</b> | |
744 | + def add(*types) | |
745 | + @__types__.add(*types) | |
746 | + end | |
747 | + end | |
748 | + end | |
749 | +end | |
750 | + | |
751 | +load File.join(File.dirname(__FILE__), 'types.rb.data') | ... | ... |
... | ... | @@ -0,0 +1,1324 @@ |
1 | +# vim: ft=ruby encoding=utf-8 | |
2 | +#-- | |
3 | +# MIME::Types | |
4 | +# A Ruby implementation of a MIME Types information library. Based in spirit | |
5 | +# on the Perl MIME::Types information library by Mark Overmeer. | |
6 | +# http://rubyforge.org/projects/mime-types/ | |
7 | +# | |
8 | +# Licensed under the Ruby disjunctive licence with the GNU GPL or the Perl | |
9 | +# Artistic licence. See Licence.txt for more information. | |
10 | +# | |
11 | +# Copyright 2003 - 2009 Austin Ziegler | |
12 | +#++ | |
13 | + | |
14 | +# Build the type list from the string below. | |
15 | +# | |
16 | +# [*][!][os:]mt/st[<ws>@ext][<ws>:enc][<ws>'url-list][<ws>=docs] | |
17 | +# | |
18 | +# == * | |
19 | +# An unofficial MIME type. This should be used if and only if the MIME type | |
20 | +# is not properly specified (that is, not under either x-type or | |
21 | +# vnd.name.type). | |
22 | +# | |
23 | +# == ! | |
24 | +# An obsolete MIME type. May be used with an unofficial MIME type. | |
25 | +# | |
26 | +# == os: | |
27 | +# Platform-specific MIME type definition. | |
28 | +# | |
29 | +# == mt | |
30 | +# The media type. | |
31 | +# | |
32 | +# == st | |
33 | +# The media subtype. | |
34 | +# | |
35 | +# == <ws>@ext | |
36 | +# The list of comma-separated extensions. | |
37 | +# | |
38 | +# == <ws>:enc | |
39 | +# The encoding. | |
40 | +# | |
41 | +# == <ws>'url-list | |
42 | +# The list of comma-separated URLs. | |
43 | +# | |
44 | +# == <ws>=docs | |
45 | +# The documentation string. | |
46 | +# | |
47 | +# That is, everything except the media type and the subtype is optional. The | |
48 | +# more information that's available, though, the richer the values that can | |
49 | +# be provided. | |
50 | + | |
51 | +data_mime_type_first_line = __LINE__ + 2 | |
52 | +data_mime_type = <<MIME_TYPES | |
53 | + # application/* | |
54 | +application/activemessage 'IANA,[Shapiro] | |
55 | +application/andrew-inset 'IANA,[Borenstein] | |
56 | +application/applefile :base64 'IANA,[Faltstrom] | |
57 | +application/atom+xml @atom :8bit 'IANA,RFC4287,RFC5023 | |
58 | +application/atomcat+xml :8bit 'IANA,RFC5023 | |
59 | +application/atomicmail 'IANA,[Borenstein] | |
60 | +application/atomsvc+xml :8bit 'IANA,RFC5023 | |
61 | +application/auth-policy+xml :8bit 'IANA,RFC4745 | |
62 | +application/batch-SMTP 'IANA,RFC2442 | |
63 | +application/beep+xml 'IANA,RFC3080 | |
64 | +application/cals-1840 'IANA,RFC1895 | |
65 | +application/ccxml+xml 'IANA,RFC4267 | |
66 | +application/cea-2018+xml 'IANA,[Zimmermann] | |
67 | +application/cellml+xml 'IANA,RFC4708 | |
68 | +application/cnrp+xml 'IANA,RFC3367 | |
69 | +application/commonground 'IANA,[Glazer] | |
70 | +application/conference-info+xml 'IANA,RFC4575 | |
71 | +application/cpl+xml 'IANA,RFC3880 | |
72 | +application/csta+xml 'IANA,[Ecma International Helpdesk] | |
73 | +application/CSTAdata+xml 'IANA,[Ecma International Helpdesk] | |
74 | +application/cybercash 'IANA,[Eastlake] | |
75 | +application/davmount+xml 'IANA,RFC4709 | |
76 | +application/dca-rft 'IANA,[Campbell] | |
77 | +application/dec-dx 'IANA,[Campbell] | |
78 | +application/dialog-info+xml 'IANA,RFC4235 | |
79 | +application/dicom 'IANA,RFC3240 | |
80 | +application/dns 'IANA,RFC4027 | |
81 | +application/dvcs 'IANA,RFC3029 | |
82 | +application/ecmascript 'IANA,RFC4329 | |
83 | +application/EDI-Consent 'IANA,RFC1767 | |
84 | +application/EDI-X12 'IANA,RFC1767 | |
85 | +application/EDIFACT 'IANA,RFC1767 | |
86 | +application/emma+xml 'IANA,[W3C] | |
87 | +application/epp+xml 'IANA,RFC3730 | |
88 | +application/eshop 'IANA,[Katz] | |
89 | +application/fastinfoset 'IANA,[ITU-T ASN.1 Rapporteur] | |
90 | +application/fastsoap 'IANA,[ITU-T ASN.1 Rapporteur] | |
91 | +application/fits 'IANA,RFC4047 | |
92 | +application/font-tdpfr @pfr 'IANA,RFC3073 | |
93 | +application/H224 'IANA,RFC4573 | |
94 | +application/http 'IANA,RFC2616 | |
95 | +application/hyperstudio @stk 'IANA,[Domino] | |
96 | +application/ibe-key-request+xml 'IANA,RFC5408 | |
97 | +application/ibe-pkg-reply+xml 'IANA,RFC5408 | |
98 | +application/ibe-pp-data 'IANA,RFC5408 | |
99 | +application/iges 'IANA,[Parks] | |
100 | +application/im-iscomposing+xml 'IANA,RFC3994 | |
101 | +application/index 'IANA,RFC2652 | |
102 | +application/index.cmd 'IANA,RFC2652 | |
103 | +application/index.obj 'IANA,RFC2652 | |
104 | +application/index.response 'IANA,RFC2652 | |
105 | +application/index.vnd 'IANA,RFC2652 | |
106 | +application/iotp 'IANA,RFC2935 | |
107 | +application/ipp 'IANA,RFC2910 | |
108 | +application/isup 'IANA,RFC3204 | |
109 | +application/javascript @js :8bit 'IANA,RFC4329 | |
110 | +application/json @json :8bit 'IANA,RFC4627 | |
111 | +application/kpml-request+xml 'IANA,RFC4730 | |
112 | +application/kpml-response+xml 'IANA,RFC4730 | |
113 | +application/lost+xml 'IANA,RFC5222 | |
114 | +application/mac-binhex40 @hqx :8bit 'IANA,[Faltstrom] | |
115 | +application/macwriteii 'IANA,[Lindner] | |
116 | +application/marc 'IANA,RFC2220 | |
117 | +application/mathematica 'IANA,[Wolfram] | |
118 | +application/mbms-associated-procedure-description+xml 'IANA,[3GPP] | |
119 | +application/mbms-deregister+xml 'IANA,[3GPP] | |
120 | +application/mbms-envelope+xml 'IANA,[3GPP] | |
121 | +application/mbms-msk+xml 'IANA,[3GPP] | |
122 | +application/mbms-msk-response+xml 'IANA,[3GPP] | |
123 | +application/mbms-protection-description+xml 'IANA,[3GPP] | |
124 | +application/mbms-reception-report+xml 'IANA,[3GPP] | |
125 | +application/mbms-register+xml 'IANA,[3GPP] | |
126 | +application/mbms-register-response+xml 'IANA,[3GPP] | |
127 | +application/mbms-user-service-description+xml 'IANA,[3GPP] | |
128 | +application/mbox 'IANA,RFC4155 | |
129 | +application/media_control+xml 'IANA,RFC5168 | |
130 | +application/mediaservercontrol+xml 'IANA,RFC5022 | |
131 | +application/mikey 'IANA,RFC3830 | |
132 | +application/moss-keys 'IANA,RFC1848 | |
133 | +application/moss-signature 'IANA,RFC1848 | |
134 | +application/mosskey-data 'IANA,RFC1848 | |
135 | +application/mosskey-request 'IANA,RFC1848 | |
136 | +application/mp4 'IANA,RFC4337 | |
137 | +application/mpeg4-generic 'IANA,RFC3640 | |
138 | +application/mpeg4-iod 'IANA,RFC4337 | |
139 | +application/mpeg4-iod-xmt 'IANA,RFC4337 | |
140 | +application/msword @doc,dot,wrd :base64 'IANA,[Lindner] | |
141 | +application/mxf 'IANA,RFC4539 | |
142 | +application/nasdata 'IANA,RFC4707 | |
143 | +application/news-transmission 'IANA,RFC1036,[Spencer] | |
144 | +application/nss 'IANA,[Hammer] | |
145 | +application/ocsp-request 'IANA,RFC2560 | |
146 | +application/ocsp-response 'IANA,RFC2560 | |
147 | +application/octet-stream @bin,dms,lha,lzh,exe,class,ani,pgp,so,dll,dmg,dylib :base64 'IANA,RFC2045,RFC2046 | |
148 | +application/oda @oda 'IANA,RFC2045,RFC2046 | |
149 | +application/oebps-package+xml 'IANA,RFC4839 | |
150 | +application/ogg @ogx 'IANA,RFC5334 | |
151 | +application/parityfec 'IANA,RFC5109 | |
152 | +application/patch-ops-error+xml 'IANA,RFC5261 | |
153 | +application/pdf @pdf :base64 'IANA,RFC3778 | |
154 | +application/pgp-encrypted :7bit 'IANA,RFC3156 | |
155 | +application/pgp-keys :7bit 'IANA,RFC3156 | |
156 | +application/pgp-signature @sig :base64 'IANA,RFC3156 | |
157 | +application/pidf+xml 'IANA,RFC3863 | |
158 | +application/pidf-diff+xml 'IANA,RFC5262 | |
159 | +application/pkcs10 @p10 'IANA,RFC2311 | |
160 | +application/pkcs7-mime @p7m,p7c 'IANA,RFC2311 | |
161 | +application/pkcs7-signature @p7s 'IANA,RFC2311 | |
162 | +application/pkix-cert @cer 'IANA,RFC2585 | |
163 | +application/pkix-crl @crl 'IANA,RFC2585 | |
164 | +application/pkix-pkipath @pkipath 'IANA,RFC4366 | |
165 | +application/pkixcmp @pki 'IANA,RFC2510 | |
166 | +application/pls+xml 'IANA,RFC4267 | |
167 | +application/poc-settings+xml 'IANA,RFC4354 | |
168 | +application/postscript @ai,eps,ps :8bit 'IANA,RFC2045,RFC2046 | |
169 | +application/prs.alvestrand.titrax-sheet 'IANA,[Alvestrand] | |
170 | +application/prs.cww @cw,cww 'IANA,[Rungchavalnont] | |
171 | +application/prs.nprend @rnd,rct 'IANA,[Doggett] | |
172 | +application/prs.plucker 'IANA,[Janssen] | |
173 | +application/qsig 'IANA,RFC3204 | |
174 | +application/rdf+xml @rdf :8bit 'IANA,RFC3870 | |
175 | +application/reginfo+xml 'IANA,RFC3680 | |
176 | +application/relax-ng-compact-syntax 'IANA,{ISO/IEC 1957-2:2003/FDAM-1=http://www.jtc1sc34.org/repository/0661.pdf} | |
177 | +application/remote-printing 'IANA,RFC1486,[Rose] | |
178 | +application/resource-lists+xml 'IANA,RFC4826 | |
179 | +application/resource-lists-diff+xml 'IANA,RFC5362 | |
180 | +application/riscos 'IANA,[Smith] | |
181 | +application/rlmi+xml 'IANA,RFC4662 | |
182 | +application/rls-services+xml 'IANA,RFC4826 | |
183 | +application/rtf @rtf 'IANA,[Lindner] | |
184 | +application/rtx 'IANA,RFC4588 | |
185 | +application/samlassertion+xml 'IANA,[OASIS Security Services Technical Committee (SSTC)] | |
186 | +application/samlmetadata+xml 'IANA,[OASIS Security Services Technical Committee (SSTC)] | |
187 | +application/sbml+xml 'IANA,RFC3823 | |
188 | +application/scvp-cv-request 'IANA,RFC5055 | |
189 | +application/scvp-cv-response 'IANA,RFC5055 | |
190 | +application/scvp-vp-request 'IANA,RFC5055 | |
191 | +application/scvp-vp-response 'IANA,RFC5055 | |
192 | +application/sdp 'IANA,RFC4566 | |
193 | +application/set-payment 'IANA,[Korver] | |
194 | +application/set-payment-initiation 'IANA,[Korver] | |
195 | +application/set-registration 'IANA,[Korver] | |
196 | +application/set-registration-initiation 'IANA,[Korver] | |
197 | +application/sgml @sgml 'IANA,RFC1874 | |
198 | +application/sgml-open-catalog @soc 'IANA,[Grosso] | |
199 | +application/shf+xml 'IANA,RFC4194 | |
200 | +application/sieve @siv 'IANA,RFC5228 | |
201 | +application/simple-filter+xml 'IANA,RFC4661 | |
202 | +application/simple-message-summary 'IANA,RFC3842 | |
203 | +application/simpleSymbolContainer 'IANA,[3GPP] | |
204 | +application/slate 'IANA,[Crowley] | |
205 | +application/smil+xml @smi,smil :8bit 'IANA,RFC4536 | |
206 | +application/soap+fastinfoset 'IANA,[ITU-T ASN.1 Rapporteur] | |
207 | +application/soap+xml 'IANA,RFC3902 | |
208 | +application/sparql-query 'IANA,[W3C] | |
209 | +application/sparql-results+xml 'IANA,[W3C] | |
210 | +application/spirits-event+xml 'IANA,RFC3910 | |
211 | +application/srgs 'IANA,RFC4267 | |
212 | +application/srgs+xml 'IANA,RFC4267 | |
213 | +application/ssml+xml 'IANA,RFC4267 | |
214 | +application/timestamp-query 'IANA,RFC3161 | |
215 | +application/timestamp-reply 'IANA,RFC3161 | |
216 | +application/tve-trigger 'IANA,[Welsh] | |
217 | +application/ulpfec 'IANA,RFC5109 | |
218 | +application/vemmi 'IANA,RFC2122 | |
219 | +application/vnd.3gpp.bsf+xml 'IANA,[Meredith] | |
220 | +application/vnd.3gpp.pic-bw-large @plb 'IANA,[Meredith] | |
221 | +application/vnd.3gpp.pic-bw-small @psb 'IANA,[Meredith] | |
222 | +application/vnd.3gpp.pic-bw-var @pvb 'IANA,[Meredith] | |
223 | +application/vnd.3gpp.sms @sms 'IANA,[Meredith] | |
224 | +application/vnd.3gpp2.bcmcsinfo+xml 'IANA,[Dryden] | |
225 | +application/vnd.3gpp2.sms 'IANA,[Mahendran] | |
226 | +application/vnd.3gpp2.tcap 'IANA,[Mahendran] | |
227 | +application/vnd.3M.Post-it-Notes 'IANA,[O'Brien] | |
228 | +application/vnd.accpac.simply.aso 'IANA,[Leow] | |
229 | +application/vnd.accpac.simply.imp 'IANA,[Leow] | |
230 | +application/vnd.acucobol 'IANA,[Lubin] | |
231 | +application/vnd.acucorp @atc,acutc :7bit 'IANA,[Lubin] | |
232 | +application/vnd.adobe.xdp+xml 'IANA,[Brinkman] | |
233 | +application/vnd.adobe.xfdf @xfdf 'IANA,[Perelman] | |
234 | +application/vnd.aether.imp 'IANA,[Moskowitz] | |
235 | +application/vnd.airzip.filesecure.azf 'IANA,[Mould],[Clueit] | |
236 | +application/vnd.airzip.filesecure.azs 'IANA,[Mould],[Clueit] | |
237 | +application/vnd.americandynamics.acc 'IANA,[Sands] | |
238 | +application/vnd.amiga.ami @ami 'IANA,[Blumberg] | |
239 | +application/vnd.anser-web-certificate-issue-initiation 'IANA,[Mori] | |
240 | +application/vnd.antix.game-component 'IANA,[Shelton] | |
241 | +application/vnd.apple.installer+xml 'IANA,[Bierman] | |
242 | +application/vnd.arastra.swi 'IANA,[Fenner] | |
243 | +application/vnd.audiograph 'IANA,[Slusanschi] | |
244 | +application/vnd.autopackage 'IANA,[Hearn] | |
245 | +application/vnd.avistar+xml 'IANA,[Vysotsky] | |
246 | +application/vnd.blueice.multipass @mpm 'IANA,[Holmstrom] | |
247 | +application/vnd.bluetooth.ep.oob 'IANA,[Foley] | |
248 | +application/vnd.bmi 'IANA,[Gotoh] | |
249 | +application/vnd.businessobjects 'IANA,[Imoucha] | |
250 | +application/vnd.cab-jscript 'IANA,[Falkenberg] | |
251 | +application/vnd.canon-cpdl 'IANA,[Muto] | |
252 | +application/vnd.canon-lips 'IANA,[Muto] | |
253 | +application/vnd.cendio.thinlinc.clientconf 'IANA,[Åstrand=Astrand] | |
254 | +application/vnd.chemdraw+xml 'IANA,[Howes] | |
255 | +application/vnd.chipnuts.karaoke-mmd 'IANA,[Xiong] | |
256 | +application/vnd.cinderella @cdy 'IANA,[Kortenkamp] | |
257 | +application/vnd.cirpack.isdn-ext 'IANA,[Mayeux] | |
258 | +application/vnd.claymore 'IANA,[Simpson] | |
259 | +application/vnd.clonk.c4group 'IANA,[Brammer] | |
260 | +application/vnd.commerce-battelle 'IANA,[Applebaum] | |
261 | +application/vnd.commonspace 'IANA,[Chandhok] | |
262 | +application/vnd.contact.cmsg 'IANA,[Patz] | |
263 | +application/vnd.cosmocaller @cmc 'IANA,[Dellutri] | |
264 | +application/vnd.crick.clicker 'IANA,[Burt] | |
265 | +application/vnd.crick.clicker.keyboard 'IANA,[Burt] | |
266 | +application/vnd.crick.clicker.palette 'IANA,[Burt] | |
267 | +application/vnd.crick.clicker.template 'IANA,[Burt] | |
268 | +application/vnd.crick.clicker.wordbank 'IANA,[Burt] | |
269 | +application/vnd.criticaltools.wbs+xml @wbs 'IANA,[Spiller] | |
270 | +application/vnd.ctc-posml 'IANA,[Kohlhepp] | |
271 | +application/vnd.ctct.ws+xml 'IANA,[Ancona] | |
272 | +application/vnd.cups-pdf 'IANA,[Sweet] | |
273 | +application/vnd.cups-postscript 'IANA,[Sweet] | |
274 | +application/vnd.cups-ppd 'IANA,[Sweet] | |
275 | +application/vnd.cups-raster 'IANA,[Sweet] | |
276 | +application/vnd.cups-raw 'IANA,[Sweet] | |
277 | +application/vnd.curl @curl 'IANA,[Byrnes] | |
278 | +application/vnd.cybank 'IANA,[Helmee] | |
279 | +application/vnd.data-vision.rdz @rdz 'IANA,[Fields] | |
280 | +application/vnd.denovo.fcselayout-link 'IANA,[Dixon] | |
281 | +application/vnd.dir-bi.plate-dl-nosuffix 'IANA,[Yamanaka] | |
282 | +application/vnd.dna 'IANA,[Searcy] | |
283 | +application/vnd.dpgraph 'IANA,[Parker] | |
284 | +application/vnd.dreamfactory @dfac 'IANA,[Appleton] | |
285 | +application/vnd.dvb.esgcontainer 'IANA,[Heuer] | |
286 | +application/vnd.dvb.ipdcesgaccess 'IANA,[Heuer] | |
287 | +application/vnd.dvb.iptv.alfec-base 'IANA,[Henry] | |
288 | +application/vnd.dvb.iptv.alfec-enhancement 'IANA,[Henry] | |
289 | +application/vnd.dvb.notif-container+xml 'IANA,[Yue] | |
290 | +application/vnd.dvb.notif-generic+xml 'IANA,[Yue] | |
291 | +application/vnd.dvb.notif-ia-msglist+xml 'IANA,[Yue] | |
292 | +application/vnd.dvb.notif-ia-registration-request+xml 'IANA,[Yue] | |
293 | +application/vnd.dvb.notif-ia-registration-response+xml 'IANA,[Yue] | |
294 | +application/vnd.dxr 'IANA,[Duffy] | |
295 | +application/vnd.ecdis-update 'IANA,[Buettgenbach] | |
296 | +application/vnd.ecowin.chart 'IANA,[Olsson] | |
297 | +application/vnd.ecowin.filerequest 'IANA,[Olsson] | |
298 | +application/vnd.ecowin.fileupdate 'IANA,[Olsson] | |
299 | +application/vnd.ecowin.series 'IANA,[Olsson] | |
300 | +application/vnd.ecowin.seriesrequest 'IANA,[Olsson] | |
301 | +application/vnd.ecowin.seriesupdate 'IANA,[Olsson] | |
302 | +application/vnd.emclient.accessrequest+xml 'IANA,[Navara] | |
303 | +application/vnd.enliven 'IANA,[Santinelli] | |
304 | +application/vnd.epson.esf 'IANA,[Hoshina] | |
305 | +application/vnd.epson.msf 'IANA,[Hoshina] | |
306 | +application/vnd.epson.quickanime 'IANA,[Gu] | |
307 | +application/vnd.epson.salt 'IANA,[Nagatomo] | |
308 | +application/vnd.epson.ssf 'IANA,[Hoshina] | |
309 | +application/vnd.ericsson.quickcall 'IANA,[Tidwell] | |
310 | +application/vnd.eszigno3+xml 'IANA,[Tóth=Toth] | |
311 | +application/vnd.eudora.data 'IANA,[Resnick] | |
312 | +application/vnd.ezpix-album 'IANA,[Electronic Zombie, Corp.=ElectronicZombieCorp] | |
313 | +application/vnd.ezpix-package 'IANA,[Electronic Zombie, Corp.=ElectronicZombieCorp] | |
314 | +application/vnd.f-secure.mobile 'IANA,[Sarivaara] | |
315 | +application/vnd.fdf 'IANA,[Zilles] | |
316 | +application/vnd.fdsn.mseed 'IANA,[Ratzesberger] | |
317 | +application/vnd.ffsns 'IANA,[Holstage] | |
318 | +application/vnd.fints 'IANA,[Hammann] | |
319 | +application/vnd.FloGraphIt 'IANA,[Floersch] | |
320 | +application/vnd.fluxtime.clip 'IANA,[Winter] | |
321 | +application/vnd.font-fontforge-sfd 'IANA,[Williams] | |
322 | +application/vnd.framemaker @frm,maker,frame,fm,fb,book,fbdoc 'IANA,[Wexler] | |
323 | +application/vnd.frogans.fnc 'IANA,[Tamas] | |
324 | +application/vnd.frogans.ltf 'IANA,[Tamas] | |
325 | +application/vnd.fsc.weblaunch @fsc :7bit 'IANA,[D.Smith] | |
326 | +application/vnd.fujitsu.oasys 'IANA,[Togashi] | |
327 | +application/vnd.fujitsu.oasys2 'IANA,[Togashi] | |
328 | +application/vnd.fujitsu.oasys3 'IANA,[Okudaira] | |
329 | +application/vnd.fujitsu.oasysgp 'IANA,[Sugimoto] | |
330 | +application/vnd.fujitsu.oasysprs 'IANA,[Ogita] | |
331 | +application/vnd.fujixerox.ART-EX 'IANA,[Tanabe] | |
332 | +application/vnd.fujixerox.ART4 'IANA,[Tanabe] | |
333 | +application/vnd.fujixerox.ddd 'IANA,[Onda] | |
334 | +application/vnd.fujixerox.docuworks 'IANA,[Taguchi] | |
335 | +application/vnd.fujixerox.docuworks.binder 'IANA,[Matsumoto] | |
336 | +application/vnd.fujixerox.HBPL 'IANA,[Tanabe] | |
337 | +application/vnd.fut-misnet 'IANA,[Pruulmann] | |
338 | +application/vnd.fuzzysheet 'IANA,[Birtwistle] | |
339 | +application/vnd.genomatix.tuxedo @txd 'IANA,[Frey] | |
340 | +application/vnd.geogebra.file 'IANA,[GeoGebra],[Kreis] | |
341 | +application/vnd.gmx 'IANA,[Sciberras] | |
342 | +application/vnd.google-earth.kml+xml @kml :8bit 'IANA,[Ashbridge] | |
343 | +application/vnd.google-earth.kmz @kmz :8bit 'IANA,[Ashbridge] | |
344 | +application/vnd.grafeq 'IANA,[Tupper] | |
345 | +application/vnd.gridmp 'IANA,[Lawson] | |
346 | +application/vnd.groove-account 'IANA,[Joseph] | |
347 | +application/vnd.groove-help 'IANA,[Joseph] | |
348 | +application/vnd.groove-identity-message 'IANA,[Joseph] | |
349 | +application/vnd.groove-injector 'IANA,[Joseph] | |
350 | +application/vnd.groove-tool-message 'IANA,[Joseph] | |
351 | +application/vnd.groove-tool-template 'IANA,[Joseph] | |
352 | +application/vnd.groove-vcard 'IANA,[Joseph] | |
353 | +application/vnd.HandHeld-Entertainment+xml 'IANA,[Hamilton] | |
354 | +application/vnd.hbci @hbci,hbc,kom,upa,pkd,bpd 'IANA,[Hammann] | |
355 | +application/vnd.hcl-bireports 'IANA,[Serres] | |
356 | +application/vnd.hhe.lesson-player @les 'IANA,[Jones] | |
357 | +application/vnd.hp-HPGL @plt,hpgl 'IANA,[Pentecost] | |
358 | +application/vnd.hp-hpid 'IANA,[Gupta] | |
359 | +application/vnd.hp-hps 'IANA,[Aubrey] | |
360 | +application/vnd.hp-jlyt 'IANA,[Gaash] | |
361 | +application/vnd.hp-PCL 'IANA,[Pentecost] | |
362 | +application/vnd.hp-PCLXL 'IANA,[Pentecost] | |
363 | +application/vnd.httphone 'IANA,[Lefevre] | |
364 | +application/vnd.hydrostatix.sof-data 'IANA,[Gillam] | |
365 | +application/vnd.hzn-3d-crossword 'IANA,[Minnis] | |
366 | +application/vnd.ibm.afplinedata 'IANA,[Buis] | |
367 | +application/vnd.ibm.electronic-media @emm 'IANA,[Tantlinger] | |
368 | +application/vnd.ibm.MiniPay 'IANA,[Herzberg] | |
369 | +application/vnd.ibm.modcap 'IANA,[Hohensee] | |
370 | +application/vnd.ibm.rights-management @irm 'IANA,[Tantlinger] | |
371 | +application/vnd.ibm.secure-container @sc 'IANA,[Tantlinger] | |
372 | +application/vnd.iccprofile 'IANA,[Green] | |
373 | +application/vnd.igloader 'IANA,[Fisher] | |
374 | +application/vnd.immervision-ivp 'IANA,[Villegas] | |
375 | +application/vnd.immervision-ivu 'IANA,[Villegas] | |
376 | +application/vnd.informedcontrol.rms+xml 'IANA,[Wahl] | |
377 | +application/vnd.informix-visionary 'IANA,[Gales] | |
378 | +application/vnd.intercon.formnet 'IANA,[Gurak] | |
379 | +application/vnd.intertrust.digibox 'IANA,[Tomasello] | |
380 | +application/vnd.intertrust.nncp 'IANA,[Tomasello] | |
381 | +application/vnd.intu.qbo 'IANA,[Scratchley] | |
382 | +application/vnd.intu.qfx 'IANA,[Scratchley] | |
383 | +application/vnd.iptc.g2.conceptitem+xml 'IANA,[Steidl] | |
384 | +application/vnd.iptc.g2.knowledgeitem+xml 'IANA,[Steidl] | |
385 | +application/vnd.iptc.g2.newsitem+xml 'IANA,[Steidl] | |
386 | +application/vnd.iptc.g2.packageitem+xml 'IANA,[Steidl] | |
387 | +application/vnd.ipunplugged.rcprofile @rcprofile 'IANA,[Ersson] | |
388 | +application/vnd.irepository.package+xml @irp 'IANA,[Knowles] | |
389 | +application/vnd.is-xpr 'IANA,[Natarajan] | |
390 | +application/vnd.jam 'IANA,[B.Kumar] | |
391 | +application/vnd.japannet-directory-service 'IANA,[Fujii] | |
392 | +application/vnd.japannet-jpnstore-wakeup 'IANA,[Yoshitake] | |
393 | +application/vnd.japannet-payment-wakeup 'IANA,[Fujii] | |
394 | +application/vnd.japannet-registration 'IANA,[Yoshitake] | |
395 | +application/vnd.japannet-registration-wakeup 'IANA,[Fujii] | |
396 | +application/vnd.japannet-setstore-wakeup 'IANA,[Yoshitake] | |
397 | +application/vnd.japannet-verification 'IANA,[Yoshitake] | |
398 | +application/vnd.japannet-verification-wakeup 'IANA,[Fujii] | |
399 | +application/vnd.jcp.javame.midlet-rms 'IANA,[Gorshenev] | |
400 | +application/vnd.jisp @jisp 'IANA,[Deckers] | |
401 | +application/vnd.joost.joda-archive 'IANA,[Joost] | |
402 | +application/vnd.kahootz 'IANA,[Macdonald] | |
403 | +application/vnd.kde.karbon @karbon 'IANA,[Faure] | |
404 | +application/vnd.kde.kchart @chrt 'IANA,[Faure] | |
405 | +application/vnd.kde.kformula @kfo 'IANA,[Faure] | |
406 | +application/vnd.kde.kivio @flw 'IANA,[Faure] | |
407 | +application/vnd.kde.kontour @kon 'IANA,[Faure] | |
408 | +application/vnd.kde.kpresenter @kpr,kpt 'IANA,[Faure] | |
409 | +application/vnd.kde.kspread @ksp 'IANA,[Faure] | |
410 | +application/vnd.kde.kword @kwd,kwt 'IANA,[Faure] | |
411 | +application/vnd.kenameaapp @htke 'IANA,[DiGiorgio-Haag] | |
412 | +application/vnd.kidspiration @kia 'IANA,[Bennett] | |
413 | +application/vnd.Kinar @kne,knp,sdf 'IANA,[Thakkar] | |
414 | +application/vnd.koan 'IANA,[Cole] | |
415 | +application/vnd.kodak-descriptor 'IANA,[Donahue] | |
416 | +application/vnd.liberty-request+xml 'IANA,[McDowell] | |
417 | +application/vnd.llamagraphics.life-balance.desktop @lbd 'IANA,[White] | |
418 | +application/vnd.llamagraphics.life-balance.exchange+xml @lbe 'IANA,[White] | |
419 | +application/vnd.lotus-1-2-3 @wks,123 'IANA,[Wattenberger] | |
420 | +application/vnd.lotus-approach 'IANA,[Wattenberger] | |
421 | +application/vnd.lotus-freelance 'IANA,[Wattenberger] | |
422 | +application/vnd.lotus-notes 'IANA,[Laramie] | |
423 | +application/vnd.lotus-organizer 'IANA,[Wattenberger] | |
424 | +application/vnd.lotus-screencam 'IANA,[Wattenberger] | |
425 | +application/vnd.lotus-wordpro 'IANA,[Wattenberger] | |
426 | +application/vnd.macports.portpkg 'IANA,[Berry] | |
427 | +application/vnd.marlin.drm.actiontoken+xml 'IANA,[Ellison] | |
428 | +application/vnd.marlin.drm.conftoken+xml 'IANA,[Ellison] | |
429 | +application/vnd.marlin.drm.license+xml 'IANA,[Ellison] | |
430 | +application/vnd.marlin.drm.mdcf 'IANA,[Ellison] | |
431 | +application/vnd.mcd @mcd 'IANA,[Gotoh] | |
432 | +application/vnd.medcalcdata 'IANA,[Schoonjans] | |
433 | +application/vnd.mediastation.cdkey 'IANA,[Flurry] | |
434 | +application/vnd.meridian-slingshot 'IANA,[Wedel] | |
435 | +application/vnd.MFER 'IANA,[Hirai] | |
436 | +application/vnd.mfmp @mfm 'IANA,[Ikeda] | |
437 | +application/vnd.micrografx.flo @flo 'IANA,[Prevo] | |
438 | +application/vnd.micrografx.igx @igx 'IANA,[Prevo] | |
439 | +application/vnd.mif @mif 'IANA,[Wexler] | |
440 | +application/vnd.minisoft-hp3000-save 'IANA,[Bartram] | |
441 | +application/vnd.mitsubishi.misty-guard.trustweb 'IANA,[Tanaka] | |
442 | +application/vnd.Mobius.DAF 'IANA,[Kabayama] | |
443 | +application/vnd.Mobius.DIS 'IANA,[Kabayama] | |
444 | +application/vnd.Mobius.MBK 'IANA,[Devasia] | |
445 | +application/vnd.Mobius.MQY 'IANA,[Devasia] | |
446 | +application/vnd.Mobius.MSL 'IANA,[Kabayama] | |
447 | +application/vnd.Mobius.PLC 'IANA,[Kabayama] | |
448 | +application/vnd.Mobius.TXF 'IANA,[Kabayama] | |
449 | +application/vnd.mophun.application @mpn 'IANA,[Wennerstrom] | |
450 | +application/vnd.mophun.certificate @mpc 'IANA,[Wennerstrom] | |
451 | +application/vnd.motorola.flexsuite 'IANA,[Patton] | |
452 | +application/vnd.motorola.flexsuite.adsi 'IANA,[Patton] | |
453 | +application/vnd.motorola.flexsuite.fis 'IANA,[Patton] | |
454 | +application/vnd.motorola.flexsuite.gotap 'IANA,[Patton] | |
455 | +application/vnd.motorola.flexsuite.kmr 'IANA,[Patton] | |
456 | +application/vnd.motorola.flexsuite.ttc 'IANA,[Patton] | |
457 | +application/vnd.motorola.flexsuite.wem 'IANA,[Patton] | |
458 | +application/vnd.motorola.iprm 'IANA,[Shamsaasef] | |
459 | +application/vnd.mozilla.xul+xml @xul 'IANA,[McDaniel] | |
460 | +application/vnd.ms-artgalry @cil 'IANA,[Slawson] | |
461 | +application/vnd.ms-asf @asf 'IANA,[Fleischman] | |
462 | +application/vnd.ms-cab-compressed @cab 'IANA,[Scarborough] | |
463 | +application/vnd.ms-excel @xls,xlt :base64 'IANA,[Gill] | |
464 | +application/vnd.ms-fontobject 'IANA,[Scarborough] | |
465 | +application/vnd.ms-ims 'IANA,[Ledoux] | |
466 | +application/vnd.ms-lrm @lrm 'IANA,[Ledoux] | |
467 | +application/vnd.ms-playready.initiator+xml 'IANA,[Schneider] | |
468 | +application/vnd.ms-powerpoint @ppt,pps,pot :base64 'IANA,[Gill] | |
469 | +application/vnd.ms-project @mpp :base64 'IANA,[Gill] | |
470 | +application/vnd.ms-tnef :base64 'IANA,[Gill] | |
471 | +application/vnd.ms-wmdrm.lic-chlg-req 'IANA,[Lau] | |
472 | +application/vnd.ms-wmdrm.lic-resp 'IANA,[Lau] | |
473 | +application/vnd.ms-wmdrm.meter-chlg-req 'IANA,[Lau] | |
474 | +application/vnd.ms-wmdrm.meter-resp 'IANA,[Lau] | |
475 | +application/vnd.ms-works :base64 'IANA,[Gill] | |
476 | +application/vnd.ms-wpl @wpl :base64 'IANA,[Plastina] | |
477 | +application/vnd.ms-xpsdocument @xps :8bit 'IANA,[McGatha] | |
478 | +application/vnd.mseq @mseq 'IANA,[Le Bodic] | |
479 | +application/vnd.msign 'IANA,[Borcherding] | |
480 | +application/vnd.multiad.creator 'IANA,[Mills] | |
481 | +application/vnd.multiad.creator.cif 'IANA,[Mills] | |
482 | +application/vnd.music-niff 'IANA,[Butler] | |
483 | +application/vnd.musician 'IANA,[Adams] | |
484 | +application/vnd.muvee.style 'IANA,[Anantharamu] | |
485 | +application/vnd.ncd.control 'IANA,[Tarkkala] | |
486 | +application/vnd.ncd.reference 'IANA,[Tarkkala] | |
487 | +application/vnd.nervana @ent,entity,req,request,bkm,kcm 'IANA,[Judkins] | |
488 | +application/vnd.netfpx 'IANA,[Mutz] | |
489 | +application/vnd.neurolanguage.nlu 'IANA,[DuFeu] | |
490 | +application/vnd.noblenet-directory 'IANA,[Solomon] | |
491 | +application/vnd.noblenet-sealer 'IANA,[Solomon] | |
492 | +application/vnd.noblenet-web 'IANA,[Solomon] | |
493 | +application/vnd.nokia.catalogs 'IANA,[Nokia] | |
494 | +application/vnd.nokia.conml+wbxml 'IANA,[Nokia] | |
495 | +application/vnd.nokia.conml+xml 'IANA,[Nokia] | |
496 | +application/vnd.nokia.iptv.config+xml 'IANA,[Nokia] | |
497 | +application/vnd.nokia.iSDS-radio-presets 'IANA,[Nokia] | |
498 | +application/vnd.nokia.landmark+wbxml 'IANA,[Nokia] | |
499 | +application/vnd.nokia.landmark+xml 'IANA,[Nokia] | |
500 | +application/vnd.nokia.landmarkcollection+xml 'IANA,[Nokia] | |
501 | +application/vnd.nokia.n-gage.ac+xml 'IANA,[Nokia] | |
502 | +application/vnd.nokia.n-gage.data 'IANA,[Nokia] | |
503 | +application/vnd.nokia.n-gage.symbian.install 'IANA,[Nokia] | |
504 | +application/vnd.nokia.ncd+xml 'IANA,[Nokia] | |
505 | +application/vnd.nokia.pcd+wbxml 'IANA,[Nokia] | |
506 | +application/vnd.nokia.pcd+xml 'IANA,[Nokia] | |
507 | +application/vnd.nokia.radio-preset @rpst 'IANA,[Nokia] | |
508 | +application/vnd.nokia.radio-presets @rpss 'IANA,[Nokia] | |
509 | +application/vnd.novadigm.EDM 'IANA,[Swenson] | |
510 | +application/vnd.novadigm.EDX 'IANA,[Swenson] | |
511 | +application/vnd.novadigm.EXT 'IANA,[Swenson] | |
512 | +application/vnd.oasis.opendocument.chart @odc 'IANA,[Oppermann] | |
513 | +application/vnd.oasis.opendocument.chart-template @odc 'IANA,[Oppermann] | |
514 | +application/vnd.oasis.opendocument.database @odb 'IANA,[Schubert],[Oasis OpenDocument TC=OASIS OpenDocumentTC] | |
515 | +application/vnd.oasis.opendocument.formula @odf 'IANA,[Oppermann] | |
516 | +application/vnd.oasis.opendocument.formula-template @odf 'IANA,[Oppermann] | |
517 | +application/vnd.oasis.opendocument.graphics @odg 'IANA,[Oppermann] | |
518 | +application/vnd.oasis.opendocument.graphics-template @otg 'IANA,[Oppermann] | |
519 | +application/vnd.oasis.opendocument.image @odi 'IANA,[Oppermann] | |
520 | +application/vnd.oasis.opendocument.image-template @odi 'IANA,[Oppermann] | |
521 | +application/vnd.oasis.opendocument.presentation @odp 'IANA,[Oppermann] | |
522 | +application/vnd.oasis.opendocument.presentation-template @otp 'IANA,[Oppermann] | |
523 | +application/vnd.oasis.opendocument.spreadsheet @ods 'IANA,[Oppermann] | |
524 | +application/vnd.oasis.opendocument.spreadsheet-template @ots 'IANA,[Oppermann] | |
525 | +application/vnd.oasis.opendocument.text @odt 'IANA,[Oppermann] | |
526 | +application/vnd.oasis.opendocument.text-master @odm 'IANA,[Oppermann] | |
527 | +application/vnd.oasis.opendocument.text-template @ott 'IANA,[Oppermann] | |
528 | +application/vnd.oasis.opendocument.text-web @oth 'IANA,[Oppermann] | |
529 | +application/vnd.obn 'IANA,[Hessling] | |
530 | +application/vnd.olpc-sugar 'IANA,[Palmieri] | |
531 | +application/vnd.oma-scws-config 'IANA,[Mahalal] | |
532 | +application/vnd.oma-scws-http-request 'IANA,[Mahalal] | |
533 | +application/vnd.oma-scws-http-response 'IANA,[Mahalal] | |
534 | +application/vnd.oma.bcast.associated-procedure-parameter+xml 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
535 | +application/vnd.oma.bcast.drm-trigger+xml 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
536 | +application/vnd.oma.bcast.imd+xml 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
537 | +application/vnd.oma.bcast.ltkm 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
538 | +application/vnd.oma.bcast.notification+xml 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
539 | +application/vnd.oma.bcast.provisioningtrigger 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
540 | +application/vnd.oma.bcast.sgboot 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
541 | +application/vnd.oma.bcast.sgdd+xml 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
542 | +application/vnd.oma.bcast.sgdu 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
543 | +application/vnd.oma.bcast.simple-symbol-container 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
544 | +application/vnd.oma.bcast.smartcard-trigger+xml 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
545 | +application/vnd.oma.bcast.sprov+xml 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
546 | +application/vnd.oma.bcast.stkm 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
547 | +application/vnd.oma.dcd 'IANA,[Primo],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
548 | +application/vnd.oma.dcdc 'IANA,[Primo],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
549 | +application/vnd.oma.dd2+xml 'IANA,[Sato],[Open Mobile Alliance's BAC DLDRM Working Group] | |
550 | +application/vnd.oma.drm.risd+xml 'IANA,[Rauschenbach],[OMNA - Open Mobile Naming Authority=OMNA-OpenMobileNamingAuthority] | |
551 | +application/vnd.oma.group-usage-list+xml 'IANA,[Kelley],[OMA Presence and Availability (PAG) Working Group] | |
552 | +application/vnd.oma.poc.detailed-progress-report+xml 'IANA,[OMA Push to Talk over Cellular (POC) Working Group] | |
553 | +application/vnd.oma.poc.final-report+xml 'IANA,[OMA Push to Talk over Cellular (POC) Working Group] | |
554 | +application/vnd.oma.poc.groups+xml 'IANA,[Kelley],[OMA Push to Talk over Cellular (POC) Working Group] | |
555 | +application/vnd.oma.poc.invocation-descriptor+xml 'IANA,[OMA Push to Talk over Cellular (POC) Working Group] | |
556 | +application/vnd.oma.poc.optimized-progress-report+xml 'IANA,[OMA Push to Talk over Cellular (POC) Working Group] | |
557 | +application/vnd.oma.xcap-directory+xml 'IANA,[Kelley],[OMA Presence and Availability (PAG) Working Group] | |
558 | +application/vnd.omads-email+xml 'IANA,[OMA Data Synchronization Working Group] | |
559 | +application/vnd.omads-file+xml 'IANA,[OMA Data Synchronization Working Group] | |
560 | +application/vnd.omads-folder+xml 'IANA,[OMA Data Synchronization Working Group] | |
561 | +application/vnd.omaloc-supl-init 'IANA,[Grange] | |
562 | +application/vnd.openofficeorg.extension 'IANA,[Lingner] | |
563 | +application/vnd.osa.netdeploy 'IANA,[Klos] | |
564 | +application/vnd.osgi.bundle 'IANA,[Kriens] | |
565 | +application/vnd.osgi.dp 'IANA,[Kriens] | |
566 | +application/vnd.otps.ct-kip+xml 'IANA,[Nyström=Nystrom] | |
567 | +application/vnd.palm @prc,pdb,pqa,oprc :base64 'IANA,[Peacock] | |
568 | +application/vnd.paos.xml 'IANA,[Kemp] | |
569 | +application/vnd.pg.format 'IANA,[Gandert] | |
570 | +application/vnd.pg.osasli 'IANA,[Gandert] | |
571 | +application/vnd.piaccess.application-licence 'IANA,[Maneos] | |
572 | +application/vnd.picsel @efif 'IANA,[Naccarato] | |
573 | +application/vnd.poc.group-advertisement+xml 'IANA,[Kelley],[OMA Push to Talk over Cellular (POC) Working Group] | |
574 | +application/vnd.pocketlearn 'IANA,[Pando] | |
575 | +application/vnd.powerbuilder6 'IANA,[Guy] | |
576 | +application/vnd.powerbuilder6-s 'IANA,[Guy] | |
577 | +application/vnd.powerbuilder7 'IANA,[Shilts] | |
578 | +application/vnd.powerbuilder7-s 'IANA,[Shilts] | |
579 | +application/vnd.powerbuilder75 'IANA,[Shilts] | |
580 | +application/vnd.powerbuilder75-s 'IANA,[Shilts] | |
581 | +application/vnd.preminet 'IANA,[Tenhunen] | |
582 | +application/vnd.previewsystems.box 'IANA,[Smolgovsky] | |
583 | +application/vnd.proteus.magazine 'IANA,[Hoch] | |
584 | +application/vnd.publishare-delta-tree 'IANA,[Ben-Kiki] | |
585 | +application/vnd.pvi.ptid1 @pti,ptid 'IANA,[Lamb] | |
586 | +application/vnd.pwg-multiplexed 'IANA,RFC3391 | |
587 | +application/vnd.pwg-xhtml-print+xml 'IANA,[Wright] | |
588 | +application/vnd.qualcomm.brew-app-res 'IANA,[Forrester] | |
589 | +application/vnd.Quark.QuarkXPress @qxd,qxt,qwd,qwt,qxl,qxb :8bit 'IANA,[Scheidler] | |
590 | +application/vnd.rapid 'IANA,[Szekely] | |
591 | +application/vnd.recordare.musicxml 'IANA,[Good] | |
592 | +application/vnd.recordare.musicxml+xml 'IANA,[Good] | |
593 | +application/vnd.RenLearn.rlprint 'IANA,[Wick] | |
594 | +application/vnd.route66.link66+xml 'IANA,[Kikstra] | |
595 | +application/vnd.ruckus.download 'IANA,[Harris] | |
596 | +application/vnd.s3sms 'IANA,[Tarkkala] | |
597 | +application/vnd.sbm.cid 'IANA,[Kusakari] | |
598 | +application/vnd.sbm.mid2 'IANA,[Murai] | |
599 | +application/vnd.scribus 'IANA,[Bradney] | |
600 | +application/vnd.sealed.3df 'IANA,[Kwan] | |
601 | +application/vnd.sealed.csf 'IANA,[Kwan] | |
602 | +application/vnd.sealed.doc @sdoc,sdo,s1w 'IANA,[Petersen] | |
603 | +application/vnd.sealed.eml @seml,sem 'IANA,[Petersen] | |
604 | +application/vnd.sealed.mht @smht,smh 'IANA,[Petersen] | |
605 | +application/vnd.sealed.net 'IANA,[Lambert] | |
606 | +application/vnd.sealed.ppt @sppt,spp,s1p 'IANA,[Petersen] | |
607 | +application/vnd.sealed.tiff 'IANA,[Kwan],[Lambert] | |
608 | +application/vnd.sealed.xls @sxls,sxl,s1e 'IANA,[Petersen] | |
609 | +application/vnd.sealedmedia.softseal.html @stml,stm,s1h 'IANA,[Petersen] | |
610 | +application/vnd.sealedmedia.softseal.pdf @spdf,spd,s1a 'IANA,[Petersen] | |
611 | +application/vnd.seemail @see 'IANA,[Webb] | |
612 | +application/vnd.sema 'IANA,[Hansson] | |
613 | +application/vnd.semd 'IANA,[Hansson] | |
614 | +application/vnd.semf 'IANA,[Hansson] | |
615 | +application/vnd.shana.informed.formdata 'IANA,[Selzler] | |
616 | +application/vnd.shana.informed.formtemplate 'IANA,[Selzler] | |
617 | +application/vnd.shana.informed.interchange 'IANA,[Selzler] | |
618 | +application/vnd.shana.informed.package 'IANA,[Selzler] | |
619 | +application/vnd.SimTech-MindMapper 'IANA,[Koh] | |
620 | +application/vnd.smaf @mmf 'IANA,[Takahashi] | |
621 | +application/vnd.smart.teacher 'IANA,[Boyle] | |
622 | +application/vnd.software602.filler.form+xml 'IANA,[Hytka],[Vondrous] | |
623 | +application/vnd.software602.filler.form-xml-zip 'IANA,[Hytka],[Vondrous] | |
624 | +application/vnd.solent.sdkm+xml 'IANA,[Gauntlett] | |
625 | +application/vnd.spotfire.dxp 'IANA,[Jernberg] | |
626 | +application/vnd.spotfire.sfs 'IANA,[Jernberg] | |
627 | +application/vnd.sss-cod 'IANA,[Dani] | |
628 | +application/vnd.sss-dtf 'IANA,[Bruno] | |
629 | +application/vnd.sss-ntf 'IANA,[Bruno] | |
630 | +application/vnd.street-stream 'IANA,[Levitt] | |
631 | +application/vnd.sun.wadl+xml 'IANA,[Hadley] | |
632 | +application/vnd.sus-calendar @sus,susp 'IANA,[Niedfeldt] | |
633 | +application/vnd.svd 'IANA,[Becker] | |
634 | +application/vnd.swiftview-ics 'IANA,[Widener] | |
635 | +application/vnd.syncml+xml 'IANA,[OMA Data Synchronization Working Group] | |
636 | +application/vnd.syncml.dm+wbxml 'IANA,[OMA-DM Work Group] | |
637 | +application/vnd.syncml.dm+xml 'IANA,[Rao],[OMA-DM Work Group] | |
638 | +application/vnd.syncml.ds.notification 'IANA,[OMA Data Synchronization Working Group] | |
639 | +application/vnd.tao.intent-module-archive 'IANA,[Shelton] | |
640 | +application/vnd.tmobile-livetv 'IANA,[Helin] | |
641 | +application/vnd.trid.tpt 'IANA,[Cusack] | |
642 | +application/vnd.triscape.mxs 'IANA,[Simonoff] | |
643 | +application/vnd.trueapp 'IANA,[Hepler] | |
644 | +application/vnd.truedoc 'IANA,[Chase] | |
645 | +application/vnd.ufdl 'IANA,[Manning] | |
646 | +application/vnd.uiq.theme 'IANA,[Ocock] | |
647 | +application/vnd.umajin 'IANA,[Riden] | |
648 | +application/vnd.unity 'IANA,[Unity3d] | |
649 | +application/vnd.uoml+xml 'IANA,[Gerdes] | |
650 | +application/vnd.uplanet.alert 'IANA,[Martin] | |
651 | +application/vnd.uplanet.alert-wbxml 'IANA,[Martin] | |
652 | +application/vnd.uplanet.bearer-choice 'IANA,[Martin] | |
653 | +application/vnd.uplanet.bearer-choice-wbxml 'IANA,[Martin] | |
654 | +application/vnd.uplanet.cacheop 'IANA,[Martin] | |
655 | +application/vnd.uplanet.cacheop-wbxml 'IANA,[Martin] | |
656 | +application/vnd.uplanet.channel 'IANA,[Martin] | |
657 | +application/vnd.uplanet.channel-wbxml 'IANA,[Martin] | |
658 | +application/vnd.uplanet.list 'IANA,[Martin] | |
659 | +application/vnd.uplanet.list-wbxml 'IANA,[Martin] | |
660 | +application/vnd.uplanet.listcmd 'IANA,[Martin] | |
661 | +application/vnd.uplanet.listcmd-wbxml 'IANA,[Martin] | |
662 | +application/vnd.uplanet.signal 'IANA,[Martin] | |
663 | +application/vnd.vcx 'IANA,[T.Sugimoto] | |
664 | +application/vnd.vd-study 'IANA,[Rogge] | |
665 | +application/vnd.vectorworks 'IANA,[Ferguson],[Sarkar] | |
666 | +application/vnd.vidsoft.vidconference @vsc :8bit 'IANA,[Hess] | |
667 | +application/vnd.visio @vsd,vst,vsw,vss 'IANA,[Sandal] | |
668 | +application/vnd.visionary @vis 'IANA,[Aravindakumar] | |
669 | +application/vnd.vividence.scriptfile 'IANA,[Risher] | |
670 | +application/vnd.vsf 'IANA,[Rowe] | |
671 | +application/vnd.wap.sic @sic 'IANA,[WAP-Forum] | |
672 | +application/vnd.wap.slc @slc 'IANA,[WAP-Forum] | |
673 | +application/vnd.wap.wbxml @wbxml 'IANA,[Stark] | |
674 | +application/vnd.wap.wmlc @wmlc 'IANA,[Stark] | |
675 | +application/vnd.wap.wmlscriptc @wmlsc 'IANA,[Stark] | |
676 | +application/vnd.webturbo @wtb 'IANA,[Rehem] | |
677 | +application/vnd.wfa.wsc 'IANA,[Wi-Fi Alliance] | |
678 | +application/vnd.wmc 'IANA,[Kjørnes=Kjornes] | |
679 | +application/vnd.wmf.bootstrap 'IANA,[Nguyenphu],[Iyer] | |
680 | +application/vnd.wordperfect @wpd 'IANA,[Scarborough] | |
681 | +application/vnd.wqd @wqd 'IANA,[Bostrom] | |
682 | +application/vnd.wrq-hp3000-labelled 'IANA,[Bartram] | |
683 | +application/vnd.wt.stf 'IANA,[Wohler] | |
684 | +application/vnd.wv.csp+wbxml @wv 'IANA,[Salmi] | |
685 | +application/vnd.wv.csp+xml :8bit 'IANA,[Ingimundarson] | |
686 | +application/vnd.wv.ssp+xml :8bit 'IANA,[Ingimundarson] | |
687 | +application/vnd.xara 'IANA,[Matthewman] | |
688 | +application/vnd.xfdl 'IANA,[Manning] | |
689 | +application/vnd.xfdl.webform 'IANA,[Mansell] | |
690 | +application/vnd.xmi+xml 'IANA,[Waskiewicz] | |
691 | +application/vnd.xmpie.cpkg 'IANA,[Sherwin] | |
692 | +application/vnd.xmpie.dpkg 'IANA,[Sherwin] | |
693 | +application/vnd.xmpie.plan 'IANA,[Sherwin] | |
694 | +application/vnd.xmpie.ppkg 'IANA,[Sherwin] | |
695 | +application/vnd.xmpie.xlim 'IANA,[Sherwin] | |
696 | +application/vnd.yamaha.hv-dic @hvd 'IANA,[Yamamoto] | |
697 | +application/vnd.yamaha.hv-script @hvs 'IANA,[Yamamoto] | |
698 | +application/vnd.yamaha.hv-voice @hvp 'IANA,[Yamamoto] | |
699 | +application/vnd.yamaha.smaf-audio @saf 'IANA,[Shinoda] | |
700 | +application/vnd.yamaha.smaf-phrase @spf 'IANA,[Shinoda] | |
701 | +application/vnd.yellowriver-custom-menu 'IANA,[Yellow] | |
702 | +application/vnd.zul 'IANA,[Grothmann] | |
703 | +application/vnd.zzazz.deck+xml 'IANA,[Hewett] | |
704 | +application/voicexml+xml 'IANA,RFC4267 | |
705 | +application/watcherinfo+xml @wif 'IANA,RFC3858 | |
706 | +application/whoispp-query 'IANA,RFC2957 | |
707 | +application/whoispp-response 'IANA,RFC2958 | |
708 | +application/wita 'IANA,[Campbell] | |
709 | +application/wordperfect5.1 @wp5,wp 'IANA,[Lindner] | |
710 | +application/wsdl+xml 'IANA,[W3C] | |
711 | +application/wspolicy+xml 'IANA,[W3C] | |
712 | +application/x400-bp 'IANA,RFC1494 | |
713 | +application/xcap-att+xml 'IANA,RFC4825 | |
714 | +application/xcap-caps+xml 'IANA,RFC4825 | |
715 | +application/xcap-el+xml 'IANA,RFC4825 | |
716 | +application/xcap-error+xml 'IANA,RFC4825 | |
717 | +application/xcap-ns+xml 'IANA,RFC4825 | |
718 | +application/xenc+xml 'IANA,[Reagle],[XENC Working Group] | |
719 | +application/xhtml+xml @xhtml :8bit 'IANA,RFC3236 | |
720 | +application/xml @xml,xsl :8bit 'IANA,RFC3023 | |
721 | +application/xml-dtd @dtd :8bit 'IANA,RFC3023 | |
722 | +application/xml-external-parsed-entity 'IANA,RFC3023 | |
723 | +application/xmpp+xml 'IANA,RFC3923 | |
724 | +application/xop+xml 'IANA,[Nottingham] | |
725 | +application/xv+xml 'IANA,RFC4374 | |
726 | +application/zip @zip :base64 'IANA,[Lindner] | |
727 | + | |
728 | +*mac:application/x-mac @bin :base64 | |
729 | +*mac:application/x-macbase64 @bin :base64 | |
730 | + | |
731 | +!application/smil @smi,smil :8bit 'IANA,RFC4536 =use-instead:application/smil+xml | |
732 | +!application/xhtml-voice+xml 'IANA,{RFC-mccobb-xplusv-media-type-04.txt=https://datatracker.ietf.org/public/idindex.cgi?command=id_detail&filename=draft-mccobb-xplusv-media-type} | |
733 | +*!application/VMSBACKUP @bck :base64 =use-instead:application/x-VMSBACKUP | |
734 | +*!application/access @mdf,mda,mdb,mde =use-instead:application/x-msaccess | |
735 | +*!application/bleeper @bleep :base64 =use-instead:application/x-bleeper | |
736 | +*!application/cals1840 'LTSW =use-instead:application/cals-1840 | |
737 | +*!application/futuresplash @spl =use-instead:application/x-futuresplash | |
738 | +*!application/ghostview =use-instead:application/x-ghostview | |
739 | +*!application/hep @hep =use-instead:application/x-hep | |
740 | +*!application/imagemap @imagemap,imap :8bit =use-instead:application/x-imagemap | |
741 | +*!application/lotus-123 @wks =use-instead:application/vnd.lotus-1-2-3 | |
742 | +*!application/mac-compactpro @cpt =use-instead:application/x-mac-compactpro | |
743 | +*!application/mathcad @mcd :base64 =use-instead:application/vnd.mcd | |
744 | +*!application/mathematica-old =use-instead:application/x-mathematica-old | |
745 | +*!application/news-message-id 'IANA,RFC1036,[Spencer] | |
746 | +*!application/quicktimeplayer @qtl =use-instead:application/x-quicktimeplayer | |
747 | +*!application/remote_printing 'LTSW =use-instead:application/remote-printing | |
748 | +*!application/toolbook @tbk =use-instead:application/x-toolbook | |
749 | +*!application/vnd.ms-excel.sheet.binary.macroEnabled.12 @xlsb | |
750 | +*!application/vnd.ms-excel.sheet.macroEnabled.12 @xlsm | |
751 | +*!application/vnd.ms-word.document.macroEnabled.12 @docm | |
752 | +*!application/vnd.ms-word.template.macroEnabled.12 @dotm | |
753 | +*!application/wordperfect @wp =use-instead:application/vnd.wordperfect | |
754 | +*!application/wordperfect6.1 @wp6 =use-instead:application/x-wordperfect6.1 | |
755 | +*!application/wordperfectd @wpd =use-instead:application/vnd.wordperfect | |
756 | +*!application/x-123 @wk =use-instead:application/vnd.lotus-1-2-3 | |
757 | +*!application/x-access @mdf,mda,mdb,mde =use-instead:application/x-msaccess | |
758 | +*!application/x-compress @z,Z :base64 =use-instead:application/x-compressed | |
759 | +*!application/x-javascript @js :8bit =use-instead:application/javascript | |
760 | +*!application/x-lotus-123 @wks =use-instead:application/vnd.lotus-1-2-3 | |
761 | +*!application/x-mathcad @mcd :base64 =use-instead:application/vnd.mcd | |
762 | +*!application/x-msword @doc,dot,wrd :base64 =use-instead:application/msword | |
763 | +*!application/x-rtf @rtf :base64 'LTSW =use-instead:application/rtf | |
764 | +*!application/x-troff 'LTSW =use-instead:text/troff | |
765 | +*!application/x-u-star 'LTSW =use-instead:application/x-ustar | |
766 | +*!application/x-word @doc,dot :base64 =use-instead:application/msword | |
767 | +*!application/x-wordperfect @wp =use-instead:application/vnd.wordperfect | |
768 | +*!application/x-wordperfectd @wpd =use-instead:application/vnd.wordperfect | |
769 | +*!application/x400.bp 'LTSW =use-instead:application/x400-bp | |
770 | +*application/SLA 'LTSW | |
771 | +*application/STEP 'LTSW | |
772 | +*application/acad 'LTSW | |
773 | +*application/appledouble :base64 | |
774 | +*application/clariscad 'LTSW | |
775 | +*application/drafting 'LTSW | |
776 | +*application/dxf 'LTSW | |
777 | +*application/excel @xls,xlt 'LTSW | |
778 | +*application/fractals 'LTSW | |
779 | +*application/i-deas 'LTSW | |
780 | +*application/macbinary 'LTSW | |
781 | +*application/netcdf @nc,cdf 'LTSW | |
782 | +*application/powerpoint @ppt,pps,pot :base64 'LTSW | |
783 | +*application/pro_eng 'LTSW | |
784 | +*application/set 'LTSW | |
785 | +*application/solids 'LTSW | |
786 | +*application/vda 'LTSW | |
787 | +*application/vnd.openxmlformats-officedocument.presentationml.presentation @pptx | |
788 | +*application/vnd.openxmlformats-officedocument.presentationml.slideshow @ppsx | |
789 | +*application/vnd.openxmlformats-officedocument.spreadsheetml.sheet @xlsx :quoted-printable | |
790 | +*application/vnd.openxmlformats-officedocument.wordprocessingml.document @docx | |
791 | +*application/vnd.openxmlformats-officedocument.wordprocessingml.template @dotx | |
792 | +*application/vnd.stardivision.calc @sdc | |
793 | +*application/vnd.stardivision.chart @sds | |
794 | +*application/vnd.stardivision.draw @sda | |
795 | +*application/vnd.stardivision.impress @sdd | |
796 | +*application/vnd.stardivision.math @sdf | |
797 | +*application/vnd.stardivision.writer @sdw | |
798 | +*application/vnd.stardivision.writer-global @sgl | |
799 | +*application/vnd.street-stream 'IANA,[Levitt] | |
800 | +*application/vnd.sun.wadl+xml 'IANA,[Hadley] | |
801 | +*application/vnd.sun.xml.calc @sxc | |
802 | +*application/vnd.sun.xml.calc.template @stc | |
803 | +*application/vnd.sun.xml.draw @sxd | |
804 | +*application/vnd.sun.xml.draw.template @std | |
805 | +*application/vnd.sun.xml.impress @sxi | |
806 | +*application/vnd.sun.xml.impress.template @sti | |
807 | +*application/vnd.sun.xml.math @sxm | |
808 | +*application/vnd.sun.xml.writer @sxw | |
809 | +*application/vnd.sun.xml.writer.global @sxg | |
810 | +*application/vnd.sun.xml.writer.template @stw | |
811 | +*application/word @doc,dot 'LTSW | |
812 | +*application/x-SLA | |
813 | +*application/x-STEP | |
814 | +*application/x-VMSBACKUP @bck :base64 | |
815 | +*application/x-Wingz @wz | |
816 | +*application/x-bcpio @bcpio 'LTSW | |
817 | +*application/x-bleeper @bleep :base64 | |
818 | +*application/x-bzip2 @bz2 | |
819 | +*application/x-cdlink @vcd | |
820 | +*application/x-chess-pgn @pgn | |
821 | +*application/x-clariscad | |
822 | +*application/x-compressed @z,Z :base64 'LTSW | |
823 | +*application/x-cpio @cpio :base64 'LTSW | |
824 | +*application/x-csh @csh :8bit 'LTSW | |
825 | +*application/x-cu-seeme @csm,cu | |
826 | +*application/x-debian-package @deb | |
827 | +*application/x-director @dcr,@dir,@dxr | |
828 | +*application/x-drafting | |
829 | +*application/x-dvi @dvi :base64 'LTSW | |
830 | +*application/x-dxf | |
831 | +*application/x-excel | |
832 | +*application/x-fractals | |
833 | +*application/x-futuresplash @spl | |
834 | +*application/x-ghostview | |
835 | +*application/x-gtar @gtar,tgz,tbz2,tbz :base64 'LTSW | |
836 | +*application/x-gzip @gz :base64 'LTSW | |
837 | +*application/x-hdf @hdf 'LTSW | |
838 | +*application/x-hep @hep | |
839 | +*application/x-html+ruby @rhtml :8bit | |
840 | +*application/x-httpd-php @phtml,pht,php :8bit | |
841 | +*application/x-ica @ica | |
842 | +*application/x-ideas | |
843 | +*application/x-imagemap @imagemap,imap :8bit | |
844 | +*application/x-java-archive @jar 'LTSW | |
845 | +*application/x-java-jnlp-file @jnlp 'LTSW | |
846 | +*application/x-java-serialized-object @ser 'LTSW | |
847 | +*application/x-java-vm @class 'LTSW | |
848 | +*application/x-koan @skp,skd,skt,skm | |
849 | +*application/x-latex @ltx,latex :8bit 'LTSW | |
850 | +*application/x-mac-compactpro @cpt | |
851 | +*application/x-macbinary | |
852 | +*application/x-maker @frm,maker,frame,fm,fb,book,fbdoc =use-instead:application/vnd.framemaker | |
853 | +*application/x-mathematica-old | |
854 | +*application/x-mif @mif 'LTSW | |
855 | +*application/x-msaccess @mda,mdb,mde,mdf | |
856 | +*application/x-msdos-program @cmd,bat :8bit | |
857 | +*application/x-msdos-program @com,exe :base64 | |
858 | +*application/x-msdownload @exe,com :base64 | |
859 | +*application/x-netcdf @nc,cdf | |
860 | +*application/x-ns-proxy-autoconfig @pac | |
861 | +*application/x-pagemaker @pm,pm5,pt5 | |
862 | +*application/x-perl @pl,pm :8bit | |
863 | +*application/x-pgp | |
864 | +*application/x-python @py :8bit | |
865 | +*application/x-quicktimeplayer @qtl | |
866 | +*application/x-rar-compressed @rar :base64 | |
867 | +*application/x-remote_printing | |
868 | +*application/x-ruby @rb,rbw :8bit | |
869 | +*application/x-set | |
870 | +*application/x-sh @sh :8bit 'LTSW | |
871 | +*application/x-shar @shar :8bit 'LTSW | |
872 | +*application/x-shockwave-flash @swf | |
873 | +*application/x-solids | |
874 | +*application/x-spss @sav,sbs,sps,spo,spp | |
875 | +*application/x-stuffit @sit :base64 'LTSW | |
876 | +*application/x-sv4cpio @sv4cpio :base64 'LTSW | |
877 | +*application/x-sv4crc @sv4crc :base64 'LTSW | |
878 | +*application/x-tar @tar :base64 'LTSW | |
879 | +*application/x-tcl @tcl :8bit 'LTSW | |
880 | +*application/x-tex @tex :8bit | |
881 | +*application/x-texinfo @texinfo,texi :8bit | |
882 | +*application/x-toolbook @tbk | |
883 | +*application/x-troff @t,tr,roff :8bit | |
884 | +*application/x-troff-man @man :8bit 'LTSW | |
885 | +*application/x-troff-me @me 'LTSW | |
886 | +*application/x-troff-ms @ms 'LTSW | |
887 | +*application/x-ustar @ustar :base64 'LTSW | |
888 | +*application/x-wais-source @src 'LTSW | |
889 | +*application/x-wordperfect6.1 @wp6 | |
890 | +*application/x-x509-ca-cert @crt :base64 | |
891 | +*application/xslt+xml @xslt :8bit | |
892 | + | |
893 | + # audio/* | |
894 | +audio/32kadpcm 'IANA,RFC2421,RFC2422 | |
895 | +audio/3gpp @3gpp 'IANA,RFC4281,RFC3839 | |
896 | +audio/3gpp2 'IANA,RFC4393,RFC4281 | |
897 | +audio/ac3 'IANA,RFC4184 | |
898 | +audio/AMR @amr :base64 'RFC4867 | |
899 | +audio/AMR-WB @awb :base64 'RFC4867 | |
900 | +audio/amr-wb+ 'IANA,RFC4352 | |
901 | +audio/asc 'IANA,RFC4695 | |
902 | +audio/basic @au,snd :base64 'IANA,RFC2045,RFC2046 | |
903 | +audio/BV16 'IANA,RFC4298 | |
904 | +audio/BV32 'IANA,RFC4298 | |
905 | +audio/clearmode 'IANA,RFC4040 | |
906 | +audio/CN 'IANA,RFC3389 | |
907 | +audio/DAT12 'IANA,RFC3190 | |
908 | +audio/dls 'IANA,RFC4613 | |
909 | +audio/dsr-es201108 'IANA,RFC3557 | |
910 | +audio/dsr-es202050 'IANA,RFC4060 | |
911 | +audio/dsr-es202211 'IANA,RFC4060 | |
912 | +audio/dsr-es202212 'IANA,RFC4060 | |
913 | +audio/DVI4 'IANA,RFC4856 | |
914 | +audio/eac3 'IANA,RFC4598 | |
915 | +audio/EVRC @evc 'IANA,RFC4788 | |
916 | +audio/EVRC-QCP 'IANA,RFC3625 | |
917 | +audio/EVRC0 'IANA,RFC4788 | |
918 | +audio/EVRC1 'IANA,RFC4788 | |
919 | +audio/EVRCB 'IANA,RFC5188 | |
920 | +audio/EVRCB0 'IANA,RFC5188 | |
921 | +audio/EVRCB1 'IANA,RFC4788 | |
922 | +audio/EVRCWB 'IANA,RFC5188 | |
923 | +audio/EVRCWB0 'IANA,RFC5188 | |
924 | +audio/EVRCWB1 'IANA,RFC5188 | |
925 | +audio/G719 'IANA,RFC5404 | |
926 | +audio/G722 'IANA,RFC4856 | |
927 | +audio/G7221 'IANA,RFC3047 | |
928 | +audio/G723 'IANA,RFC4856 | |
929 | +audio/G726-16 'IANA,RFC4856 | |
930 | +audio/G726-24 'IANA,RFC4856 | |
931 | +audio/G726-32 'IANA,RFC4856 | |
932 | +audio/G726-40 'IANA,RFC4856 | |
933 | +audio/G728 'IANA,RFC4856 | |
934 | +audio/G729 'IANA,RFC4856 | |
935 | +audio/G7291 'IANA,RFC4749,RFC5459 | |
936 | +audio/G729D 'IANA,RFC4856 | |
937 | +audio/G729E 'IANA,RFC4856 | |
938 | +audio/GSM 'IANA,RFC4856 | |
939 | +audio/GSM-EFR 'IANA,RFC4856 | |
940 | +audio/iLBC 'IANA,RFC3952 | |
941 | +audio/L16 @l16 'IANA,RFC4856 | |
942 | +audio/L20 'IANA,RFC3190 | |
943 | +audio/L24 'IANA,RFC3190 | |
944 | +audio/L8 'IANA,RFC4856 | |
945 | +audio/LPC 'IANA,RFC4856 | |
946 | +audio/mobile-xmf 'IANA,RFC4723 | |
947 | +audio/mp4 'IANA,RFC4337 | |
948 | +audio/MP4A-LATM 'IANA,RFC3016 | |
949 | +audio/MPA 'IANA,RFC3555 | |
950 | +audio/mpa-robust 'IANA,RFC5219 | |
951 | +audio/mpeg @mpga,mp2,mp3 :base64 'IANA,RFC3003 | |
952 | +audio/mpeg4-generic 'IANA,RFC3640 | |
953 | +audio/ogg 'IANA,RFC5334 | |
954 | +audio/parityfec 'IANA,RFC5109 | |
955 | +audio/PCMA 'IANA,RFC4856 | |
956 | +audio/PCMA-WB 'IANA,RFC5391 | |
957 | +audio/PCMU 'IANA,RFC4856 | |
958 | +audio/PCMU-WB 'IANA,RFC5391 | |
959 | +audio/prs.sid 'IANA,[Walleij] | |
960 | +audio/QCELP 'IANA,RFC3555,RFC3625 | |
961 | +audio/RED 'IANA,RFC3555 | |
962 | +audio/rtp-enc-aescm128 'IANA,[3GPP] | |
963 | +audio/rtp-midi 'IANA,RFC4695 | |
964 | +audio/rtx 'IANA,RFC4588 | |
965 | +audio/SMV @smv 'IANA,RFC3558 | |
966 | +audio/SMV-QCP 'IANA,RFC3625 | |
967 | +audio/SMV0 'IANA,RFC3558 | |
968 | +audio/sp-midi 'IANA,[Kosonen],[T. White=T.White] | |
969 | +audio/t140c 'IANA,RFC4351 | |
970 | +audio/t38 'IANA,RFC4612 | |
971 | +audio/telephone-event 'IANA,RFC4733 | |
972 | +audio/tone 'IANA,RFC4733 | |
973 | +audio/ulpfec 'IANA,RFC5109 | |
974 | +audio/VDVI 'IANA,RFC4856 | |
975 | +audio/VMR-WB 'IANA,RFC4348,RFC4424 | |
976 | +audio/vnd.3gpp.iufp 'IANA,[Belling] | |
977 | +audio/vnd.4SB 'IANA,[De Jaham] | |
978 | +audio/vnd.audiokoz 'IANA,[DeBarros] | |
979 | +audio/vnd.CELP 'IANA,[De Jaham] | |
980 | +audio/vnd.cisco.nse 'IANA,[Kumar] | |
981 | +audio/vnd.cmles.radio-events 'IANA,[Goulet] | |
982 | +audio/vnd.cns.anp1 'IANA,[McLaughlin] | |
983 | +audio/vnd.cns.inf1 'IANA,[McLaughlin] | |
984 | +audio/vnd.digital-winds @eol :7bit 'IANA,[Strazds] | |
985 | +audio/vnd.dlna.adts 'IANA,[Heredia] | |
986 | +audio/vnd.dolby.mlp 'IANA,[Ward] | |
987 | +audio/vnd.dolby.mps 'IANA,[Hattersley] | |
988 | +audio/vnd.dts 'IANA,[Zou] | |
989 | +audio/vnd.dts.hd 'IANA,[Zou] | |
990 | +audio/vnd.everad.plj @plj 'IANA,[Cicelsky] | |
991 | +audio/vnd.hns.audio 'IANA,[Swaminathan] | |
992 | +audio/vnd.lucent.voice @lvp 'IANA,[Vaudreuil] | |
993 | +audio/vnd.ms-playready.media.pya 'IANA,[DiAcetis] | |
994 | +audio/vnd.nokia.mobile-xmf @mxmf 'IANA,[Nokia Corporation=Nokia] | |
995 | +audio/vnd.nortel.vbk @vbk 'IANA,[Parsons] | |
996 | +audio/vnd.nuera.ecelp4800 @ecelp4800 'IANA,[Fox] | |
997 | +audio/vnd.nuera.ecelp7470 @ecelp7470 'IANA,[Fox] | |
998 | +audio/vnd.nuera.ecelp9600 @ecelp9600 'IANA,[Fox] | |
999 | +audio/vnd.octel.sbc 'IANA,[Vaudreuil] | |
1000 | +audio/vnd.rhetorex.32kadpcm 'IANA,[Vaudreuil] | |
1001 | +audio/vnd.sealedmedia.softseal.mpeg @smp3,smp,s1m 'IANA,[Petersen] | |
1002 | +audio/vnd.vmx.cvsd 'IANA,[Vaudreuil] | |
1003 | +audio/vorbis 'IANA,RFC5215 | |
1004 | +audio/vorbis-config 'IANA,RFC5215 | |
1005 | + | |
1006 | +audio/x-aiff @aif,aifc,aiff :base64 | |
1007 | +audio/x-midi @mid,midi,kar :base64 | |
1008 | +audio/x-pn-realaudio @rm,ram :base64 | |
1009 | +audio/x-pn-realaudio-plugin @rpm | |
1010 | +audio/x-realaudio @ra :base64 | |
1011 | +audio/x-wav @wav :base64 | |
1012 | + | |
1013 | +!audio/vnd.qcelp @qcp 'IANA,RFC3625 =use-instead:audio/QCELP | |
1014 | + | |
1015 | + # image/* | |
1016 | +image/cgm 'IANA,[Francis] | |
1017 | +image/fits 'IANA,RFC4047 | |
1018 | +image/g3fax 'IANA,RFC1494 | |
1019 | +image/gif @gif :base64 'IANA,RFC2045,RFC2046 | |
1020 | +image/ief @ief :base64 'IANA,RFC1314 | |
1021 | +image/jp2 @jp2,jpg2 :base64 'IANA,RFC3745 | |
1022 | +image/jpeg @jpeg,jpg,jpe :base64 'IANA,RFC2045,RFC2046 | |
1023 | +image/jpm @jpm,jpgm :base64 'IANA,RFC3745 | |
1024 | +image/jpx @jpx,jpf :base64 'IANA,RFC3745 | |
1025 | +image/naplps 'IANA,[Ferber] | |
1026 | +image/png @png :base64 'IANA,[Randers-Pehrson] | |
1027 | +image/prs.btif 'IANA,[Simon] | |
1028 | +image/prs.pti 'IANA,[Laun] | |
1029 | +image/t38 'IANA,RFC3362 | |
1030 | +image/tiff @tiff,tif :base64 'IANA,RFC2302 | |
1031 | +image/tiff-fx 'IANA,RFC3950 | |
1032 | +image/vnd.adobe.photoshop 'IANA,[Scarborough] | |
1033 | +image/vnd.cns.inf2 'IANA,[McLaughlin] | |
1034 | +image/vnd.djvu @djvu,djv 'IANA,[Bottou] | |
1035 | +image/vnd.dwg @dwg 'IANA,[Moline] | |
1036 | +image/vnd.dxf 'IANA,[Moline] | |
1037 | +image/vnd.fastbidsheet 'IANA,[Becker] | |
1038 | +image/vnd.fpx 'IANA,[Spencer] | |
1039 | +image/vnd.fst 'IANA,[Fuldseth] | |
1040 | +image/vnd.fujixerox.edmics-mmr 'IANA,[Onda] | |
1041 | +image/vnd.fujixerox.edmics-rlc 'IANA,[Onda] | |
1042 | +image/vnd.globalgraphics.pgb @pgb 'IANA,[Bailey] | |
1043 | +image/vnd.microsoft.icon @ico 'IANA,[Butcher] | |
1044 | +image/vnd.mix 'IANA,[Reddy] | |
1045 | +image/vnd.ms-modi @mdi 'IANA,[Vaughan] | |
1046 | +image/vnd.net-fpx 'IANA,[Spencer] | |
1047 | +image/vnd.sealed.png @spng,spn,s1n 'IANA,[Petersen] | |
1048 | +image/vnd.sealedmedia.softseal.gif @sgif,sgi,s1g 'IANA,[Petersen] | |
1049 | +image/vnd.sealedmedia.softseal.jpg @sjpg,sjp,s1j 'IANA,[Petersen] | |
1050 | +image/vnd.svf 'IANA,[Moline] | |
1051 | +image/vnd.wap.wbmp @wbmp 'IANA,[Stark] | |
1052 | +image/vnd.xiff 'IANA,[S.Martin] | |
1053 | + | |
1054 | +*!image/bmp @bmp =use-instead:image/x-bmp | |
1055 | +*!image/cmu-raster =use-instead:image/x-cmu-raster | |
1056 | +*!image/targa @tga =use-instead:image/x-targa | |
1057 | +*!image/vnd.dgn @dgn =use-instead:image/x-vnd.dgn | |
1058 | +*!image/vnd.net.fpx =use-instead:image/vnd.net-fpx | |
1059 | +*image/pjpeg :base64 =Fixes a bug with IE6 and progressive JPEGs | |
1060 | +*image/svg+xml @svg :8bit | |
1061 | +*image/x-bmp @bmp | |
1062 | +*image/x-cmu-raster @ras | |
1063 | +*image/x-paintshoppro @psp,pspimage :base64 | |
1064 | +*image/x-pict | |
1065 | +*image/x-portable-anymap @pnm :base64 | |
1066 | +*image/x-portable-bitmap @pbm :base64 | |
1067 | +*image/x-portable-graymap @pgm :base64 | |
1068 | +*image/x-portable-pixmap @ppm :base64 | |
1069 | +*image/x-rgb @rgb :base64 | |
1070 | +*image/x-targa @tga | |
1071 | +*image/x-vnd.dgn @dgn | |
1072 | +*image/x-win-bmp | |
1073 | +*image/x-xbitmap @xbm :7bit | |
1074 | +*image/x-xbm @xbm :7bit | |
1075 | +*image/x-xpixmap @xpm :8bit | |
1076 | +*image/x-xwindowdump @xwd :base64 | |
1077 | + | |
1078 | + # message/* | |
1079 | +message/CPIM 'IANA,RFC3862 | |
1080 | +message/delivery-status 'IANA,RFC1894 | |
1081 | +message/disposition-notification 'IANA,RFC2298 | |
1082 | +message/external-body :8bit 'IANA,RFC2045,RFC2046 | |
1083 | +message/global 'IANA,RFC5335 | |
1084 | +message/global-delivery-status 'IANA,RFC5337 | |
1085 | +message/global-disposition-notification 'IANA,RFC5337 | |
1086 | +message/global-headers 'IANA,RFC5337 | |
1087 | +message/http 'IANA,RFC2616 | |
1088 | +message/imdn+xml 'IANA,RFC5438 | |
1089 | +message/news :8bit 'IANA,RFC1036,[H.Spencer] | |
1090 | +message/partial :8bit 'IANA,RFC2045,RFC2046 | |
1091 | +message/rfc822 @eml :8bit 'IANA,RFC2045,RFC2046 | |
1092 | +message/s-http 'IANA,RFC2660 | |
1093 | +message/sip 'IANA,RFC3261 | |
1094 | +message/sipfrag 'IANA,RFC3420 | |
1095 | +message/tracking-status 'IANA,RFC3886 | |
1096 | +message/vnd.si.simp 'IANA,[Parks Young=ParksYoung] | |
1097 | + | |
1098 | + # model/* | |
1099 | +model/iges @igs,iges 'IANA,[Parks] | |
1100 | +model/mesh @msh,mesh,silo 'IANA,RFC2077 | |
1101 | +model/vnd.dwf 'IANA,[Pratt] | |
1102 | +model/vnd.flatland.3dml 'IANA,[Powers] | |
1103 | +model/vnd.gdl 'IANA,[Babits] | |
1104 | +model/vnd.gs-gdl 'IANA,[Babits] | |
1105 | +model/vnd.gtw 'IANA,[Ozaki] | |
1106 | +model/vnd.moml+xml 'IANA,[Brooks] | |
1107 | +model/vnd.mts 'IANA,[Rabinovitch] | |
1108 | +model/vnd.parasolid.transmit.binary @x_b,xmt_bin 'IANA,[Parasolid] | |
1109 | +model/vnd.parasolid.transmit.text @x_t,xmt_txt :quoted-printable 'IANA,[Parasolid] | |
1110 | +model/vnd.vtu 'IANA,[Rabinovitch] | |
1111 | +model/vrml @wrl,vrml 'IANA,RFC2077 | |
1112 | + | |
1113 | + # multipart/* | |
1114 | +multipart/alternative :8bit 'IANA,RFC2045,RFC2046 | |
1115 | +multipart/appledouble :8bit 'IANA,[Faltstrom] | |
1116 | +multipart/byteranges 'IANA,RFC2068 | |
1117 | +multipart/digest :8bit 'IANA,RFC2045,RFC2046 | |
1118 | +multipart/encrypted 'IANA,RFC1847 | |
1119 | +multipart/form-data 'IANA,RFC2388 | |
1120 | +multipart/header-set 'IANA,[Crocker] | |
1121 | +multipart/mixed :8bit 'IANA,RFC2045,RFC2046 | |
1122 | +multipart/parallel :8bit 'IANA,RFC2045,RFC2046 | |
1123 | +multipart/related 'IANA,RFC2387 | |
1124 | +multipart/report 'IANA,RFC3462 | |
1125 | +multipart/signed 'IANA,RFC1847 | |
1126 | +multipart/voice-message 'IANA,RFC2421,RFC2423 | |
1127 | +*multipart/x-gzip | |
1128 | +*multipart/x-mixed-replace | |
1129 | +*multipart/x-tar | |
1130 | +*multipart/x-ustar | |
1131 | +*multipart/x-www-form-urlencoded | |
1132 | +*multipart/x-zip | |
1133 | +*!multipart/x-parallel =use-instead:multipart/parallel | |
1134 | + | |
1135 | + # text/* | |
1136 | +text/calendar 'IANA,RFC2445 | |
1137 | +text/css @css :8bit 'IANA,RFC2318 | |
1138 | +text/csv @csv :8bit 'IANA,RFC4180 | |
1139 | +text/directory 'IANA,RFC2425 | |
1140 | +text/dns 'IANA,RFC4027 | |
1141 | +text/enriched 'IANA,RFC1896 | |
1142 | +text/html @html,htm,htmlx,shtml,htx :8bit 'IANA,RFC2854 | |
1143 | +text/parityfec 'IANA,RFC5109 | |
1144 | +text/plain @txt,asc,c,cc,h,hh,cpp,hpp,dat,hlp 'IANA,RFC2046,RFC3676,RFC5147 | |
1145 | +text/prs.fallenstein.rst @rst 'IANA,[Fallenstein] | |
1146 | +text/prs.lines.tag 'IANA,[Lines] | |
1147 | +text/RED 'IANA,RFC4102 | |
1148 | +text/rfc822-headers 'IANA,RFC3462 | |
1149 | +text/richtext @rtx :8bit 'IANA,RFC2045,RFC2046 | |
1150 | +text/rtf @rtf :8bit 'IANA,[Lindner] | |
1151 | +text/rtp-enc-aescm128 'IANA,[3GPP] | |
1152 | +text/rtx 'IANA,RFC4588 | |
1153 | +text/sgml @sgml,sgm 'IANA,RFC1874 | |
1154 | +text/t140 'IANA,RFC4103 | |
1155 | +text/tab-separated-values @tsv 'IANA,[Lindner] | |
1156 | +text/troff @t,tr,roff,troff :8bit 'IANA,RFC4263 | |
1157 | +text/ulpfec 'IANA,RFC5109 | |
1158 | +text/uri-list 'IANA,RFC2483 | |
1159 | +text/vnd.abc 'IANA,[Allen] | |
1160 | +text/vnd.curl 'IANA,[Byrnes] | |
1161 | +text/vnd.DMClientScript 'IANA,[Bradley] | |
1162 | +text/vnd.esmertec.theme-descriptor 'IANA,[Eilemann] | |
1163 | +text/vnd.fly 'IANA,[Gurney] | |
1164 | +text/vnd.fmi.flexstor 'IANA,[Hurtta] | |
1165 | +text/vnd.graphviz 'IANA,[Ellson] | |
1166 | +text/vnd.in3d.3dml 'IANA,[Powers] | |
1167 | +text/vnd.in3d.spot 'IANA,[Powers] | |
1168 | +text/vnd.IPTC.NewsML 'IANA,[IPTC] | |
1169 | +text/vnd.IPTC.NITF 'IANA,[IPTC] | |
1170 | +text/vnd.latex-z 'IANA,[Lubos] | |
1171 | +text/vnd.motorola.reflex 'IANA,[Patton] | |
1172 | +text/vnd.ms-mediapackage 'IANA,[Nelson] | |
1173 | +text/vnd.net2phone.commcenter.command @ccc 'IANA,[Xie] | |
1174 | +text/vnd.si.uricatalogue 'IANA,[Parks Young=ParksYoung] | |
1175 | +text/vnd.sun.j2me.app-descriptor @jad :8bit 'IANA,[G.Adams] | |
1176 | +text/vnd.trolltech.linguist 'IANA,[D.Lambert] | |
1177 | +text/vnd.wap.si @si 'IANA,[WAP-Forum] | |
1178 | +text/vnd.wap.sl @sl 'IANA,[WAP-Forum] | |
1179 | +text/vnd.wap.wml @wml 'IANA,[Stark] | |
1180 | +text/vnd.wap.wmlscript @wmls 'IANA,[Stark] | |
1181 | +text/xml @xml,dtd :8bit 'IANA,RFC3023 | |
1182 | +text/xml-external-parsed-entity 'IANA,RFC3023 | |
1183 | + | |
1184 | +vms:text/plain @doc :8bit | |
1185 | + | |
1186 | +!text/ecmascript 'IANA,RFC4329 | |
1187 | +!text/javascript 'IANA,RFC4329 | |
1188 | +*!text/comma-separated-values @csv :8bit =use-instead:text/csv | |
1189 | +*!text/vnd.flatland.3dml =use-instead:model/vnd.flatland.3dml | |
1190 | +*!text/x-rtf @rtf :8bit =use-instead:text/rtf | |
1191 | +*!text/x-vnd.flatland.3dml =use-instead:model/vnd.flatland.3dml | |
1192 | +*text/x-component @htc :8bit | |
1193 | +*text/x-setext @etx | |
1194 | +*text/x-vcalendar @vcs :8bit | |
1195 | +*text/x-vcard @vcf :8bit | |
1196 | +*text/x-yaml @yaml,yml :8bit | |
1197 | + | |
1198 | + # Registered: video/* | |
1199 | +video/3gpp @3gp,3gpp 'IANA,RFC3839,RFC4281 | |
1200 | +video/3gpp-tt 'IANA,RFC4396 | |
1201 | +video/3gpp2 'IANA,RFC4393,RFC4281 | |
1202 | +video/BMPEG 'IANA,RFC3555 | |
1203 | +video/BT656 'IANA,RFC3555 | |
1204 | +video/CelB 'IANA,RFC3555 | |
1205 | +video/DV 'IANA,RFC3189 | |
1206 | +video/H261 'IANA,RFC4587 | |
1207 | +video/H263 'IANA,RFC3555 | |
1208 | +video/H263-1998 'IANA,RFC4629 | |
1209 | +video/H263-2000 'IANA,RFC4629 | |
1210 | +video/H264 'IANA,RFC3984 | |
1211 | +video/JPEG 'IANA,RFC3555 | |
1212 | +video/jpeg2000 'IANA,RFC5371,RFC5372 | |
1213 | +video/MJ2 @mj2,mjp2 'IANA,RFC3745 | |
1214 | +video/MP1S 'IANA,RFC3555 | |
1215 | +video/MP2P 'IANA,RFC3555 | |
1216 | +video/MP2T 'IANA,RFC3555 | |
1217 | +video/mp4 'IANA,RFC4337 | |
1218 | +video/MP4V-ES 'IANA,RFC3016 | |
1219 | +video/mpeg @mp2,mpe,mp3g,mpg :base64 'IANA,RFC2045,RFC2046 | |
1220 | +video/mpeg4-generic 'IANA,RFC3640 | |
1221 | +video/MPV 'IANA,RFC3555 | |
1222 | +video/nv 'IANA,RFC4856 | |
1223 | +video/ogg @ogv 'IANA,RFC5334 | |
1224 | +video/parityfec 'IANA,RFC5109 | |
1225 | +video/pointer 'IANA,RFC2862 | |
1226 | +video/quicktime @qt,mov :base64 'IANA,[Lindner] | |
1227 | +video/raw 'IANA,RFC4175 | |
1228 | +video/rtp-enc-aescm128 'IANA,[3GPP] | |
1229 | +video/rtx 'IANA,RFC4588 | |
1230 | +video/SMPTE292M 'IANA,RFC3497 | |
1231 | +video/ulpfec 'IANA,RFC5109 | |
1232 | +video/vc1 'IANA,RFC4425 | |
1233 | +video/vnd.CCTV 'IANA,[Rottmann] | |
1234 | +video/vnd.fvt 'IANA,[Fuldseth] | |
1235 | +video/vnd.hns.video 'IANA,[Swaminathan] | |
1236 | +video/vnd.iptvforum.1dparityfec-1010 'IANA,[Nakamura] | |
1237 | +video/vnd.iptvforum.1dparityfec-2005 'IANA,[Nakamura] | |
1238 | +video/vnd.iptvforum.2dparityfec-1010 'IANA,[Nakamura] | |
1239 | +video/vnd.iptvforum.2dparityfec-2005 'IANA,[Nakamura] | |
1240 | +video/vnd.iptvforum.ttsavc 'IANA,[Nakamura] | |
1241 | +video/vnd.iptvforum.ttsmpeg2 'IANA,[Nakamura] | |
1242 | +video/vnd.motorola.video 'IANA,[McGinty] | |
1243 | +video/vnd.motorola.videop 'IANA,[McGinty] | |
1244 | +video/vnd.mpegurl @mxu,m4u :8bit 'IANA,[Recktenwald] | |
1245 | +video/vnd.ms-playready.media.pyv 'IANA,[DiAcetis] | |
1246 | +video/vnd.nokia.interleaved-multimedia @nim 'IANA,[Kangaslampi] | |
1247 | +video/vnd.objectvideo @mp4 'IANA,[Clark] | |
1248 | +video/vnd.sealed.mpeg1 @s11 'IANA,[Petersen] | |
1249 | +video/vnd.sealed.mpeg4 @smpg,s14 'IANA,[Petersen] | |
1250 | +video/vnd.sealed.swf @sswf,ssw 'IANA,[Petersen] | |
1251 | +video/vnd.sealedmedia.softseal.mov @smov,smo,s1q 'IANA,[Petersen] | |
1252 | +video/vnd.vivo @viv,vivo 'IANA,[Wolfe] | |
1253 | + | |
1254 | +*!video/dl @dl :base64 =use-instead:video/x-dl | |
1255 | +*!video/gl @gl :base64 =use-instead:video/x-gl | |
1256 | +*!video/vnd.dlna.mpeg-tts 'IANA,[Heredia] | |
1257 | +*video/x-dl @dl :base64 | |
1258 | +*video/x-fli @fli :base64 | |
1259 | +*video/x-flv @flv :base64 | |
1260 | +*video/x-gl @gl :base64 | |
1261 | +*video/x-ms-asf @asf,asx | |
1262 | +*video/x-ms-wmv @wmv | |
1263 | +*video/x-msvideo @avi :base64 | |
1264 | +*video/x-sgi-movie @movie :base64 | |
1265 | + | |
1266 | + # Unregistered: other/* | |
1267 | +*!chemical/x-pdb @pdb =use-instead:x-chemical/x-pdb | |
1268 | +*!chemical/x-xyz @xyz =use-instead:x-chemical/x-xyz | |
1269 | +*!drawing/dwf @dwf =use-instead:x-drawing/dwf | |
1270 | +x-chemical/x-pdb @pdb | |
1271 | +x-chemical/x-xyz @xyz | |
1272 | +x-conference/x-cooltalk @ice | |
1273 | +x-drawing/dwf @dwf | |
1274 | +x-world/x-vrml @wrl,vrml | |
1275 | +MIME_TYPES | |
1276 | + | |
1277 | +_re = %r{ | |
1278 | + ^ | |
1279 | + ([*])? # 0: Unregistered? | |
1280 | + (!)? # 1: Obsolete? | |
1281 | + (?:(\w+):)? # 2: Platform marker | |
1282 | + #{MIME::Type::MEDIA_TYPE_RE} # 3,4: Media type | |
1283 | + (?:\s@([^\s]+))? # 5: Extensions | |
1284 | + (?:\s:(#{MIME::Type::ENCODING_RE}))? # 6: Encoding | |
1285 | + (?:\s'(.+))? # 7: URL list | |
1286 | + (?:\s=(.+))? # 8: Documentation | |
1287 | + $ | |
1288 | +}x | |
1289 | + | |
1290 | +data_mime_type.split($/).each_with_index do |i, x| | |
1291 | + item = i.chomp.strip.gsub(%r{#.*}o, '') | |
1292 | + next if item.empty? | |
1293 | + | |
1294 | + begin | |
1295 | + m = _re.match(item).captures | |
1296 | + rescue Exception => ex | |
1297 | + puts <<-"ERROR" | |
1298 | +#{__FILE__}:#{x + data_mime_type_first_line}: Parsing error in MIME type definitions. | |
1299 | +=> "#{item}" | |
1300 | + ERROR | |
1301 | + raise | |
1302 | + end | |
1303 | + | |
1304 | + unregistered, obsolete, platform, mediatype, subtype, extensions, | |
1305 | + encoding, urls, docs = *m | |
1306 | + | |
1307 | + extensions &&= extensions.split(/,/) | |
1308 | + urls &&= urls.split(/,/) | |
1309 | + | |
1310 | + mime_type = MIME::Type.new("#{mediatype}/#{subtype}") do |t| | |
1311 | + t.extensions = extensions | |
1312 | + t.encoding = encoding | |
1313 | + t.system = platform | |
1314 | + t.obsolete = obsolete | |
1315 | + t.registered = false if unregistered | |
1316 | + t.docs = docs | |
1317 | + t.url = urls | |
1318 | + end | |
1319 | + | |
1320 | + MIME::Types.add_type_variant(mime_type) | |
1321 | + MIME::Types.index_extensions(mime_type) | |
1322 | +end | |
1323 | + | |
1324 | +_re = data_mime_type = data_mime_type_first_line = nil | ... | ... |
... | ... | @@ -0,0 +1,43 @@ |
1 | +# -*- encoding: utf-8 -*- | |
2 | + | |
3 | +Gem::Specification.new do |s| | |
4 | + s.name = %q{mime-types} | |
5 | + s.version = "1.16" | |
6 | + | |
7 | + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= | |
8 | + s.authors = ["Austin Ziegler"] | |
9 | + s.cert_chain = ["/Users/austin/.gem/gem-public_cert.pem"] | |
10 | + s.date = %q{2009-03-01} | |
11 | + s.description = %q{MIME::Types for Ruby originally based on and synchronized with MIME::Types for Perl by Mark Overmeer, copyright 2001 - 2009. As of version 1.15, the data format for the MIME::Type list has changed and the synchronization will no longer happen.} | |
12 | + s.email = ["austin@rubyforge.org"] | |
13 | + s.extra_rdoc_files = ["History.txt", "Install.txt", "Licence.txt", "README.txt"] | |
14 | + s.files = ["History.txt", "Install.txt", "Licence.txt", "Manifest.txt", "README.txt", "Rakefile", "lib/mime/types.rb", "lib/mime/types.rb.data", "setup.rb", "test/test_mime_type.rb", "test/test_mime_types.rb"] | |
15 | + s.has_rdoc = true | |
16 | + s.homepage = %q{http://mime-types.rubyforge.org/} | |
17 | + s.rdoc_options = ["--main", "README.txt"] | |
18 | + s.require_paths = ["lib"] | |
19 | + s.rubyforge_project = %q{mime-types} | |
20 | + s.rubygems_version = %q{1.3.1} | |
21 | + s.signing_key = %q{/Users/austin/.gem/gem-private_key.pem} | |
22 | + s.summary = %q{Manages a MIME Content-Type database that will return the Content-Type for a given filename.} | |
23 | + s.test_files = ["test/test_mime_type.rb", "test/test_mime_types.rb"] | |
24 | + | |
25 | + if s.respond_to? :specification_version then | |
26 | + current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION | |
27 | + s.specification_version = 2 | |
28 | + | |
29 | + if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then | |
30 | + s.add_development_dependency(%q<archive-tar-minitar>, ["~> 0.5.1"]) | |
31 | + s.add_development_dependency(%q<nokogiri>, ["~> 1.2.1"]) | |
32 | + s.add_development_dependency(%q<hoe>, [">= 1.8.3"]) | |
33 | + else | |
34 | + s.add_dependency(%q<archive-tar-minitar>, ["~> 0.5.1"]) | |
35 | + s.add_dependency(%q<nokogiri>, ["~> 1.2.1"]) | |
36 | + s.add_dependency(%q<hoe>, [">= 1.8.3"]) | |
37 | + end | |
38 | + else | |
39 | + s.add_dependency(%q<archive-tar-minitar>, ["~> 0.5.1"]) | |
40 | + s.add_dependency(%q<nokogiri>, ["~> 1.2.1"]) | |
41 | + s.add_dependency(%q<hoe>, [">= 1.8.3"]) | |
42 | + end | |
43 | +end | ... | ... |
... | ... | @@ -0,0 +1,1585 @@ |
1 | +# | |
2 | +# setup.rb | |
3 | +# | |
4 | +# Copyright (c) 2000-2005 Minero Aoki | |
5 | +# | |
6 | +# This program is free software. | |
7 | +# You can distribute/modify this program under the terms of | |
8 | +# the GNU LGPL, Lesser General Public License version 2.1. | |
9 | +# | |
10 | + | |
11 | +unless Enumerable.method_defined?(:map) # Ruby 1.4.6 | |
12 | + module Enumerable | |
13 | + alias map collect | |
14 | + end | |
15 | +end | |
16 | + | |
17 | +unless File.respond_to?(:read) # Ruby 1.6 | |
18 | + def File.read(fname) | |
19 | + open(fname) {|f| | |
20 | + return f.read | |
21 | + } | |
22 | + end | |
23 | +end | |
24 | + | |
25 | +unless Errno.const_defined?(:ENOTEMPTY) # Windows? | |
26 | + module Errno | |
27 | + class ENOTEMPTY | |
28 | + # We do not raise this exception, implementation is not needed. | |
29 | + end | |
30 | + end | |
31 | +end | |
32 | + | |
33 | +def File.binread(fname) | |
34 | + open(fname, 'rb') {|f| | |
35 | + return f.read | |
36 | + } | |
37 | +end | |
38 | + | |
39 | +# for corrupted Windows' stat(2) | |
40 | +def File.dir?(path) | |
41 | + File.directory?((path[-1,1] == '/') ? path : path + '/') | |
42 | +end | |
43 | + | |
44 | + | |
45 | +class ConfigTable | |
46 | + | |
47 | + include Enumerable | |
48 | + | |
49 | + def initialize(rbconfig) | |
50 | + @rbconfig = rbconfig | |
51 | + @items = [] | |
52 | + @table = {} | |
53 | + # options | |
54 | + @install_prefix = nil | |
55 | + @config_opt = nil | |
56 | + @verbose = true | |
57 | + @no_harm = false | |
58 | + end | |
59 | + | |
60 | + attr_accessor :install_prefix | |
61 | + attr_accessor :config_opt | |
62 | + | |
63 | + attr_writer :verbose | |
64 | + | |
65 | + def verbose? | |
66 | + @verbose | |
67 | + end | |
68 | + | |
69 | + attr_writer :no_harm | |
70 | + | |
71 | + def no_harm? | |
72 | + @no_harm | |
73 | + end | |
74 | + | |
75 | + def [](key) | |
76 | + lookup(key).resolve(self) | |
77 | + end | |
78 | + | |
79 | + def []=(key, val) | |
80 | + lookup(key).set val | |
81 | + end | |
82 | + | |
83 | + def names | |
84 | + @items.map {|i| i.name } | |
85 | + end | |
86 | + | |
87 | + def each(&block) | |
88 | + @items.each(&block) | |
89 | + end | |
90 | + | |
91 | + def key?(name) | |
92 | + @table.key?(name) | |
93 | + end | |
94 | + | |
95 | + def lookup(name) | |
96 | + @table[name] or setup_rb_error "no such config item: #{name}" | |
97 | + end | |
98 | + | |
99 | + def add(item) | |
100 | + @items.push item | |
101 | + @table[item.name] = item | |
102 | + end | |
103 | + | |
104 | + def remove(name) | |
105 | + item = lookup(name) | |
106 | + @items.delete_if {|i| i.name == name } | |
107 | + @table.delete_if {|name, i| i.name == name } | |
108 | + item | |
109 | + end | |
110 | + | |
111 | + def load_script(path, inst = nil) | |
112 | + if File.file?(path) | |
113 | + MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path | |
114 | + end | |
115 | + end | |
116 | + | |
117 | + def savefile | |
118 | + '.config' | |
119 | + end | |
120 | + | |
121 | + def load_savefile | |
122 | + begin | |
123 | + File.foreach(savefile()) do |line| | |
124 | + k, v = *line.split(/=/, 2) | |
125 | + self[k] = v.strip | |
126 | + end | |
127 | + rescue Errno::ENOENT | |
128 | + setup_rb_error $!.message + "\n#{File.basename($0)} config first" | |
129 | + end | |
130 | + end | |
131 | + | |
132 | + def save | |
133 | + @items.each {|i| i.value } | |
134 | + File.open(savefile(), 'w') {|f| | |
135 | + @items.each do |i| | |
136 | + f.printf "%s=%s\n", i.name, i.value if i.value? and i.value | |
137 | + end | |
138 | + } | |
139 | + end | |
140 | + | |
141 | + def load_standard_entries | |
142 | + standard_entries(@rbconfig).each do |ent| | |
143 | + add ent | |
144 | + end | |
145 | + end | |
146 | + | |
147 | + def standard_entries(rbconfig) | |
148 | + c = rbconfig | |
149 | + | |
150 | + rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) | |
151 | + | |
152 | + major = c['MAJOR'].to_i | |
153 | + minor = c['MINOR'].to_i | |
154 | + teeny = c['TEENY'].to_i | |
155 | + version = "#{major}.#{minor}" | |
156 | + | |
157 | + # ruby ver. >= 1.4.4? | |
158 | + newpath_p = ((major >= 2) or | |
159 | + ((major == 1) and | |
160 | + ((minor >= 5) or | |
161 | + ((minor == 4) and (teeny >= 4))))) | |
162 | + | |
163 | + if c['rubylibdir'] | |
164 | + # V > 1.6.3 | |
165 | + libruby = "#{c['prefix']}/lib/ruby" | |
166 | + librubyver = c['rubylibdir'] | |
167 | + librubyverarch = c['archdir'] | |
168 | + siteruby = c['sitedir'] | |
169 | + siterubyver = c['sitelibdir'] | |
170 | + siterubyverarch = c['sitearchdir'] | |
171 | + elsif newpath_p | |
172 | + # 1.4.4 <= V <= 1.6.3 | |
173 | + libruby = "#{c['prefix']}/lib/ruby" | |
174 | + librubyver = "#{c['prefix']}/lib/ruby/#{version}" | |
175 | + librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" | |
176 | + siteruby = c['sitedir'] | |
177 | + siterubyver = "$siteruby/#{version}" | |
178 | + siterubyverarch = "$siterubyver/#{c['arch']}" | |
179 | + else | |
180 | + # V < 1.4.4 | |
181 | + libruby = "#{c['prefix']}/lib/ruby" | |
182 | + librubyver = "#{c['prefix']}/lib/ruby/#{version}" | |
183 | + librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" | |
184 | + siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" | |
185 | + siterubyver = siteruby | |
186 | + siterubyverarch = "$siterubyver/#{c['arch']}" | |
187 | + end | |
188 | + parameterize = lambda {|path| | |
189 | + path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') | |
190 | + } | |
191 | + | |
192 | + if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } | |
193 | + makeprog = arg.sub(/'/, '').split(/=/, 2)[1] | |
194 | + else | |
195 | + makeprog = 'make' | |
196 | + end | |
197 | + | |
198 | + [ | |
199 | + ExecItem.new('installdirs', 'std/site/home', | |
200 | + 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ | |
201 | + {|val, table| | |
202 | + case val | |
203 | + when 'std' | |
204 | + table['rbdir'] = '$librubyver' | |
205 | + table['sodir'] = '$librubyverarch' | |
206 | + when 'site' | |
207 | + table['rbdir'] = '$siterubyver' | |
208 | + table['sodir'] = '$siterubyverarch' | |
209 | + when 'home' | |
210 | + setup_rb_error '$HOME was not set' unless ENV['HOME'] | |
211 | + table['prefix'] = ENV['HOME'] | |
212 | + table['rbdir'] = '$libdir/ruby' | |
213 | + table['sodir'] = '$libdir/ruby' | |
214 | + end | |
215 | + }, | |
216 | + PathItem.new('prefix', 'path', c['prefix'], | |
217 | + 'path prefix of target environment'), | |
218 | + PathItem.new('bindir', 'path', parameterize.call(c['bindir']), | |
219 | + 'the directory for commands'), | |
220 | + PathItem.new('libdir', 'path', parameterize.call(c['libdir']), | |
221 | + 'the directory for libraries'), | |
222 | + PathItem.new('datadir', 'path', parameterize.call(c['datadir']), | |
223 | + 'the directory for shared data'), | |
224 | + PathItem.new('mandir', 'path', parameterize.call(c['mandir']), | |
225 | + 'the directory for man pages'), | |
226 | + PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), | |
227 | + 'the directory for system configuration files'), | |
228 | + PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), | |
229 | + 'the directory for local state data'), | |
230 | + PathItem.new('libruby', 'path', libruby, | |
231 | + 'the directory for ruby libraries'), | |
232 | + PathItem.new('librubyver', 'path', librubyver, | |
233 | + 'the directory for standard ruby libraries'), | |
234 | + PathItem.new('librubyverarch', 'path', librubyverarch, | |
235 | + 'the directory for standard ruby extensions'), | |
236 | + PathItem.new('siteruby', 'path', siteruby, | |
237 | + 'the directory for version-independent aux ruby libraries'), | |
238 | + PathItem.new('siterubyver', 'path', siterubyver, | |
239 | + 'the directory for aux ruby libraries'), | |
240 | + PathItem.new('siterubyverarch', 'path', siterubyverarch, | |
241 | + 'the directory for aux ruby binaries'), | |
242 | + PathItem.new('rbdir', 'path', '$siterubyver', | |
243 | + 'the directory for ruby scripts'), | |
244 | + PathItem.new('sodir', 'path', '$siterubyverarch', | |
245 | + 'the directory for ruby extentions'), | |
246 | + PathItem.new('rubypath', 'path', rubypath, | |
247 | + 'the path to set to #! line'), | |
248 | + ProgramItem.new('rubyprog', 'name', rubypath, | |
249 | + 'the ruby program using for installation'), | |
250 | + ProgramItem.new('makeprog', 'name', makeprog, | |
251 | + 'the make program to compile ruby extentions'), | |
252 | + SelectItem.new('shebang', 'all/ruby/never', 'ruby', | |
253 | + 'shebang line (#!) editing mode'), | |
254 | + BoolItem.new('without-ext', 'yes/no', 'no', | |
255 | + 'does not compile/install ruby extentions') | |
256 | + ] | |
257 | + end | |
258 | + private :standard_entries | |
259 | + | |
260 | + def load_multipackage_entries | |
261 | + multipackage_entries().each do |ent| | |
262 | + add ent | |
263 | + end | |
264 | + end | |
265 | + | |
266 | + def multipackage_entries | |
267 | + [ | |
268 | + PackageSelectionItem.new('with', 'name,name...', '', 'ALL', | |
269 | + 'package names that you want to install'), | |
270 | + PackageSelectionItem.new('without', 'name,name...', '', 'NONE', | |
271 | + 'package names that you do not want to install') | |
272 | + ] | |
273 | + end | |
274 | + private :multipackage_entries | |
275 | + | |
276 | + ALIASES = { | |
277 | + 'std-ruby' => 'librubyver', | |
278 | + 'stdruby' => 'librubyver', | |
279 | + 'rubylibdir' => 'librubyver', | |
280 | + 'archdir' => 'librubyverarch', | |
281 | + 'site-ruby-common' => 'siteruby', # For backward compatibility | |
282 | + 'site-ruby' => 'siterubyver', # For backward compatibility | |
283 | + 'bin-dir' => 'bindir', | |
284 | + 'bin-dir' => 'bindir', | |
285 | + 'rb-dir' => 'rbdir', | |
286 | + 'so-dir' => 'sodir', | |
287 | + 'data-dir' => 'datadir', | |
288 | + 'ruby-path' => 'rubypath', | |
289 | + 'ruby-prog' => 'rubyprog', | |
290 | + 'ruby' => 'rubyprog', | |
291 | + 'make-prog' => 'makeprog', | |
292 | + 'make' => 'makeprog' | |
293 | + } | |
294 | + | |
295 | + def fixup | |
296 | + ALIASES.each do |ali, name| | |
297 | + @table[ali] = @table[name] | |
298 | + end | |
299 | + @items.freeze | |
300 | + @table.freeze | |
301 | + @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ | |
302 | + end | |
303 | + | |
304 | + def parse_opt(opt) | |
305 | + m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" | |
306 | + m.to_a[1,2] | |
307 | + end | |
308 | + | |
309 | + def dllext | |
310 | + @rbconfig['DLEXT'] | |
311 | + end | |
312 | + | |
313 | + def value_config?(name) | |
314 | + lookup(name).value? | |
315 | + end | |
316 | + | |
317 | + class Item | |
318 | + def initialize(name, template, default, desc) | |
319 | + @name = name.freeze | |
320 | + @template = template | |
321 | + @value = default | |
322 | + @default = default | |
323 | + @description = desc | |
324 | + end | |
325 | + | |
326 | + attr_reader :name | |
327 | + attr_reader :description | |
328 | + | |
329 | + attr_accessor :default | |
330 | + alias help_default default | |
331 | + | |
332 | + def help_opt | |
333 | + "--#{@name}=#{@template}" | |
334 | + end | |
335 | + | |
336 | + def value? | |
337 | + true | |
338 | + end | |
339 | + | |
340 | + def value | |
341 | + @value | |
342 | + end | |
343 | + | |
344 | + def resolve(table) | |
345 | + @value.gsub(%r<\$([^/]+)>) { table[$1] } | |
346 | + end | |
347 | + | |
348 | + def set(val) | |
349 | + @value = check(val) | |
350 | + end | |
351 | + | |
352 | + private | |
353 | + | |
354 | + def check(val) | |
355 | + setup_rb_error "config: --#{name} requires argument" unless val | |
356 | + val | |
357 | + end | |
358 | + end | |
359 | + | |
360 | + class BoolItem < Item | |
361 | + def config_type | |
362 | + 'bool' | |
363 | + end | |
364 | + | |
365 | + def help_opt | |
366 | + "--#{@name}" | |
367 | + end | |
368 | + | |
369 | + private | |
370 | + | |
371 | + def check(val) | |
372 | + return 'yes' unless val | |
373 | + case val | |
374 | + when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' | |
375 | + when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' | |
376 | + else | |
377 | + setup_rb_error "config: --#{@name} accepts only yes/no for argument" | |
378 | + end | |
379 | + end | |
380 | + end | |
381 | + | |
382 | + class PathItem < Item | |
383 | + def config_type | |
384 | + 'path' | |
385 | + end | |
386 | + | |
387 | + private | |
388 | + | |
389 | + def check(path) | |
390 | + setup_rb_error "config: --#{@name} requires argument" unless path | |
391 | + path[0,1] == '$' ? path : File.expand_path(path) | |
392 | + end | |
393 | + end | |
394 | + | |
395 | + class ProgramItem < Item | |
396 | + def config_type | |
397 | + 'program' | |
398 | + end | |
399 | + end | |
400 | + | |
401 | + class SelectItem < Item | |
402 | + def initialize(name, selection, default, desc) | |
403 | + super | |
404 | + @ok = selection.split('/') | |
405 | + end | |
406 | + | |
407 | + def config_type | |
408 | + 'select' | |
409 | + end | |
410 | + | |
411 | + private | |
412 | + | |
413 | + def check(val) | |
414 | + unless @ok.include?(val.strip) | |
415 | + setup_rb_error "config: use --#{@name}=#{@template} (#{val})" | |
416 | + end | |
417 | + val.strip | |
418 | + end | |
419 | + end | |
420 | + | |
421 | + class ExecItem < Item | |
422 | + def initialize(name, selection, desc, &block) | |
423 | + super name, selection, nil, desc | |
424 | + @ok = selection.split('/') | |
425 | + @action = block | |
426 | + end | |
427 | + | |
428 | + def config_type | |
429 | + 'exec' | |
430 | + end | |
431 | + | |
432 | + def value? | |
433 | + false | |
434 | + end | |
435 | + | |
436 | + def resolve(table) | |
437 | + setup_rb_error "$#{name()} wrongly used as option value" | |
438 | + end | |
439 | + | |
440 | + undef set | |
441 | + | |
442 | + def evaluate(val, table) | |
443 | + v = val.strip.downcase | |
444 | + unless @ok.include?(v) | |
445 | + setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" | |
446 | + end | |
447 | + @action.call v, table | |
448 | + end | |
449 | + end | |
450 | + | |
451 | + class PackageSelectionItem < Item | |
452 | + def initialize(name, template, default, help_default, desc) | |
453 | + super name, template, default, desc | |
454 | + @help_default = help_default | |
455 | + end | |
456 | + | |
457 | + attr_reader :help_default | |
458 | + | |
459 | + def config_type | |
460 | + 'package' | |
461 | + end | |
462 | + | |
463 | + private | |
464 | + | |
465 | + def check(val) | |
466 | + unless File.dir?("packages/#{val}") | |
467 | + setup_rb_error "config: no such package: #{val}" | |
468 | + end | |
469 | + val | |
470 | + end | |
471 | + end | |
472 | + | |
473 | + class MetaConfigEnvironment | |
474 | + def initialize(config, installer) | |
475 | + @config = config | |
476 | + @installer = installer | |
477 | + end | |
478 | + | |
479 | + def config_names | |
480 | + @config.names | |
481 | + end | |
482 | + | |
483 | + def config?(name) | |
484 | + @config.key?(name) | |
485 | + end | |
486 | + | |
487 | + def bool_config?(name) | |
488 | + @config.lookup(name).config_type == 'bool' | |
489 | + end | |
490 | + | |
491 | + def path_config?(name) | |
492 | + @config.lookup(name).config_type == 'path' | |
493 | + end | |
494 | + | |
495 | + def value_config?(name) | |
496 | + @config.lookup(name).config_type != 'exec' | |
497 | + end | |
498 | + | |
499 | + def add_config(item) | |
500 | + @config.add item | |
501 | + end | |
502 | + | |
503 | + def add_bool_config(name, default, desc) | |
504 | + @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) | |
505 | + end | |
506 | + | |
507 | + def add_path_config(name, default, desc) | |
508 | + @config.add PathItem.new(name, 'path', default, desc) | |
509 | + end | |
510 | + | |
511 | + def set_config_default(name, default) | |
512 | + @config.lookup(name).default = default | |
513 | + end | |
514 | + | |
515 | + def remove_config(name) | |
516 | + @config.remove(name) | |
517 | + end | |
518 | + | |
519 | + # For only multipackage | |
520 | + def packages | |
521 | + raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer | |
522 | + @installer.packages | |
523 | + end | |
524 | + | |
525 | + # For only multipackage | |
526 | + def declare_packages(list) | |
527 | + raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer | |
528 | + @installer.packages = list | |
529 | + end | |
530 | + end | |
531 | + | |
532 | +end # class ConfigTable | |
533 | + | |
534 | + | |
535 | +# This module requires: #verbose?, #no_harm? | |
536 | +module FileOperations | |
537 | + | |
538 | + def mkdir_p(dirname, prefix = nil) | |
539 | + dirname = prefix + File.expand_path(dirname) if prefix | |
540 | + $stderr.puts "mkdir -p #{dirname}" if verbose? | |
541 | + return if no_harm? | |
542 | + | |
543 | + # Does not check '/', it's too abnormal. | |
544 | + dirs = File.expand_path(dirname).split(%r<(?=/)>) | |
545 | + if /\A[a-z]:\z/i =~ dirs[0] | |
546 | + disk = dirs.shift | |
547 | + dirs[0] = disk + dirs[0] | |
548 | + end | |
549 | + dirs.each_index do |idx| | |
550 | + path = dirs[0..idx].join('') | |
551 | + Dir.mkdir path unless File.dir?(path) | |
552 | + end | |
553 | + end | |
554 | + | |
555 | + def rm_f(path) | |
556 | + $stderr.puts "rm -f #{path}" if verbose? | |
557 | + return if no_harm? | |
558 | + force_remove_file path | |
559 | + end | |
560 | + | |
561 | + def rm_rf(path) | |
562 | + $stderr.puts "rm -rf #{path}" if verbose? | |
563 | + return if no_harm? | |
564 | + remove_tree path | |
565 | + end | |
566 | + | |
567 | + def remove_tree(path) | |
568 | + if File.symlink?(path) | |
569 | + remove_file path | |
570 | + elsif File.dir?(path) | |
571 | + remove_tree0 path | |
572 | + else | |
573 | + force_remove_file path | |
574 | + end | |
575 | + end | |
576 | + | |
577 | + def remove_tree0(path) | |
578 | + Dir.foreach(path) do |ent| | |
579 | + next if ent == '.' | |
580 | + next if ent == '..' | |
581 | + entpath = "#{path}/#{ent}" | |
582 | + if File.symlink?(entpath) | |
583 | + remove_file entpath | |
584 | + elsif File.dir?(entpath) | |
585 | + remove_tree0 entpath | |
586 | + else | |
587 | + force_remove_file entpath | |
588 | + end | |
589 | + end | |
590 | + begin | |
591 | + Dir.rmdir path | |
592 | + rescue Errno::ENOTEMPTY | |
593 | + # directory may not be empty | |
594 | + end | |
595 | + end | |
596 | + | |
597 | + def move_file(src, dest) | |
598 | + force_remove_file dest | |
599 | + begin | |
600 | + File.rename src, dest | |
601 | + rescue | |
602 | + File.open(dest, 'wb') {|f| | |
603 | + f.write File.binread(src) | |
604 | + } | |
605 | + File.chmod File.stat(src).mode, dest | |
606 | + File.unlink src | |
607 | + end | |
608 | + end | |
609 | + | |
610 | + def force_remove_file(path) | |
611 | + begin | |
612 | + remove_file path | |
613 | + rescue | |
614 | + end | |
615 | + end | |
616 | + | |
617 | + def remove_file(path) | |
618 | + File.chmod 0777, path | |
619 | + File.unlink path | |
620 | + end | |
621 | + | |
622 | + def install(from, dest, mode, prefix = nil) | |
623 | + $stderr.puts "install #{from} #{dest}" if verbose? | |
624 | + return if no_harm? | |
625 | + | |
626 | + realdest = prefix ? prefix + File.expand_path(dest) : dest | |
627 | + realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) | |
628 | + str = File.binread(from) | |
629 | + if diff?(str, realdest) | |
630 | + verbose_off { | |
631 | + rm_f realdest if File.exist?(realdest) | |
632 | + } | |
633 | + File.open(realdest, 'wb') {|f| | |
634 | + f.write str | |
635 | + } | |
636 | + File.chmod mode, realdest | |
637 | + | |
638 | + File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| | |
639 | + if prefix | |
640 | + f.puts realdest.sub(prefix, '') | |
641 | + else | |
642 | + f.puts realdest | |
643 | + end | |
644 | + } | |
645 | + end | |
646 | + end | |
647 | + | |
648 | + def diff?(new_content, path) | |
649 | + return true unless File.exist?(path) | |
650 | + new_content != File.binread(path) | |
651 | + end | |
652 | + | |
653 | + def command(*args) | |
654 | + $stderr.puts args.join(' ') if verbose? | |
655 | + system(*args) or raise RuntimeError, | |
656 | + "system(#{args.map{|a| a.inspect }.join(' ')}) failed" | |
657 | + end | |
658 | + | |
659 | + def ruby(*args) | |
660 | + command config('rubyprog'), *args | |
661 | + end | |
662 | + | |
663 | + def make(task = nil) | |
664 | + command(*[config('makeprog'), task].compact) | |
665 | + end | |
666 | + | |
667 | + def extdir?(dir) | |
668 | + File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") | |
669 | + end | |
670 | + | |
671 | + def files_of(dir) | |
672 | + Dir.open(dir) {|d| | |
673 | + return d.select {|ent| File.file?("#{dir}/#{ent}") } | |
674 | + } | |
675 | + end | |
676 | + | |
677 | + DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) | |
678 | + | |
679 | + def directories_of(dir) | |
680 | + Dir.open(dir) {|d| | |
681 | + return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT | |
682 | + } | |
683 | + end | |
684 | + | |
685 | +end | |
686 | + | |
687 | + | |
688 | +# This module requires: #srcdir_root, #objdir_root, #relpath | |
689 | +module HookScriptAPI | |
690 | + | |
691 | + def get_config(key) | |
692 | + @config[key] | |
693 | + end | |
694 | + | |
695 | + alias config get_config | |
696 | + | |
697 | + # obsolete: use metaconfig to change configuration | |
698 | + def set_config(key, val) | |
699 | + @config[key] = val | |
700 | + end | |
701 | + | |
702 | + # | |
703 | + # srcdir/objdir (works only in the package directory) | |
704 | + # | |
705 | + | |
706 | + def curr_srcdir | |
707 | + "#{srcdir_root()}/#{relpath()}" | |
708 | + end | |
709 | + | |
710 | + def curr_objdir | |
711 | + "#{objdir_root()}/#{relpath()}" | |
712 | + end | |
713 | + | |
714 | + def srcfile(path) | |
715 | + "#{curr_srcdir()}/#{path}" | |
716 | + end | |
717 | + | |
718 | + def srcexist?(path) | |
719 | + File.exist?(srcfile(path)) | |
720 | + end | |
721 | + | |
722 | + def srcdirectory?(path) | |
723 | + File.dir?(srcfile(path)) | |
724 | + end | |
725 | + | |
726 | + def srcfile?(path) | |
727 | + File.file?(srcfile(path)) | |
728 | + end | |
729 | + | |
730 | + def srcentries(path = '.') | |
731 | + Dir.open("#{curr_srcdir()}/#{path}") {|d| | |
732 | + return d.to_a - %w(. ..) | |
733 | + } | |
734 | + end | |
735 | + | |
736 | + def srcfiles(path = '.') | |
737 | + srcentries(path).select {|fname| | |
738 | + File.file?(File.join(curr_srcdir(), path, fname)) | |
739 | + } | |
740 | + end | |
741 | + | |
742 | + def srcdirectories(path = '.') | |
743 | + srcentries(path).select {|fname| | |
744 | + File.dir?(File.join(curr_srcdir(), path, fname)) | |
745 | + } | |
746 | + end | |
747 | + | |
748 | +end | |
749 | + | |
750 | + | |
751 | +class ToplevelInstaller | |
752 | + | |
753 | + Version = '3.4.1' | |
754 | + Copyright = 'Copyright (c) 2000-2005 Minero Aoki' | |
755 | + | |
756 | + TASKS = [ | |
757 | + [ 'all', 'do config, setup, then install' ], | |
758 | + [ 'config', 'saves your configurations' ], | |
759 | + [ 'show', 'shows current configuration' ], | |
760 | + [ 'setup', 'compiles ruby extentions and others' ], | |
761 | + [ 'install', 'installs files' ], | |
762 | + [ 'test', 'run all tests in test/' ], | |
763 | + [ 'clean', "does `make clean' for each extention" ], | |
764 | + [ 'distclean',"does `make distclean' for each extention" ] | |
765 | + ] | |
766 | + | |
767 | + def ToplevelInstaller.invoke | |
768 | + config = ConfigTable.new(load_rbconfig()) | |
769 | + config.load_standard_entries | |
770 | + config.load_multipackage_entries if multipackage? | |
771 | + config.fixup | |
772 | + klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) | |
773 | + klass.new(File.dirname($0), config).invoke | |
774 | + end | |
775 | + | |
776 | + def ToplevelInstaller.multipackage? | |
777 | + File.dir?(File.dirname($0) + '/packages') | |
778 | + end | |
779 | + | |
780 | + def ToplevelInstaller.load_rbconfig | |
781 | + if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } | |
782 | + ARGV.delete(arg) | |
783 | + load File.expand_path(arg.split(/=/, 2)[1]) | |
784 | + $".push 'rbconfig.rb' | |
785 | + else | |
786 | + require 'rbconfig' | |
787 | + end | |
788 | + ::Config::CONFIG | |
789 | + end | |
790 | + | |
791 | + def initialize(ardir_root, config) | |
792 | + @ardir = File.expand_path(ardir_root) | |
793 | + @config = config | |
794 | + # cache | |
795 | + @valid_task_re = nil | |
796 | + end | |
797 | + | |
798 | + def config(key) | |
799 | + @config[key] | |
800 | + end | |
801 | + | |
802 | + def inspect | |
803 | + "#<#{self.class} #{__id__()}>" | |
804 | + end | |
805 | + | |
806 | + def invoke | |
807 | + run_metaconfigs | |
808 | + case task = parsearg_global() | |
809 | + when nil, 'all' | |
810 | + parsearg_config | |
811 | + init_installers | |
812 | + exec_config | |
813 | + exec_setup | |
814 | + exec_install | |
815 | + else | |
816 | + case task | |
817 | + when 'config', 'test' | |
818 | + ; | |
819 | + when 'clean', 'distclean' | |
820 | + @config.load_savefile if File.exist?(@config.savefile) | |
821 | + else | |
822 | + @config.load_savefile | |
823 | + end | |
824 | + __send__ "parsearg_#{task}" | |
825 | + init_installers | |
826 | + __send__ "exec_#{task}" | |
827 | + end | |
828 | + end | |
829 | + | |
830 | + def run_metaconfigs | |
831 | + @config.load_script "#{@ardir}/metaconfig" | |
832 | + end | |
833 | + | |
834 | + def init_installers | |
835 | + @installer = Installer.new(@config, @ardir, File.expand_path('.')) | |
836 | + end | |
837 | + | |
838 | + # | |
839 | + # Hook Script API bases | |
840 | + # | |
841 | + | |
842 | + def srcdir_root | |
843 | + @ardir | |
844 | + end | |
845 | + | |
846 | + def objdir_root | |
847 | + '.' | |
848 | + end | |
849 | + | |
850 | + def relpath | |
851 | + '.' | |
852 | + end | |
853 | + | |
854 | + # | |
855 | + # Option Parsing | |
856 | + # | |
857 | + | |
858 | + def parsearg_global | |
859 | + while arg = ARGV.shift | |
860 | + case arg | |
861 | + when /\A\w+\z/ | |
862 | + setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) | |
863 | + return arg | |
864 | + when '-q', '--quiet' | |
865 | + @config.verbose = false | |
866 | + when '--verbose' | |
867 | + @config.verbose = true | |
868 | + when '--help' | |
869 | + print_usage $stdout | |
870 | + exit 0 | |
871 | + when '--version' | |
872 | + puts "#{File.basename($0)} version #{Version}" | |
873 | + exit 0 | |
874 | + when '--copyright' | |
875 | + puts Copyright | |
876 | + exit 0 | |
877 | + else | |
878 | + setup_rb_error "unknown global option '#{arg}'" | |
879 | + end | |
880 | + end | |
881 | + nil | |
882 | + end | |
883 | + | |
884 | + def valid_task?(t) | |
885 | + valid_task_re() =~ t | |
886 | + end | |
887 | + | |
888 | + def valid_task_re | |
889 | + @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ | |
890 | + end | |
891 | + | |
892 | + def parsearg_no_options | |
893 | + unless ARGV.empty? | |
894 | + task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) | |
895 | + setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" | |
896 | + end | |
897 | + end | |
898 | + | |
899 | + alias parsearg_show parsearg_no_options | |
900 | + alias parsearg_setup parsearg_no_options | |
901 | + alias parsearg_test parsearg_no_options | |
902 | + alias parsearg_clean parsearg_no_options | |
903 | + alias parsearg_distclean parsearg_no_options | |
904 | + | |
905 | + def parsearg_config | |
906 | + evalopt = [] | |
907 | + set = [] | |
908 | + @config.config_opt = [] | |
909 | + while i = ARGV.shift | |
910 | + if /\A--?\z/ =~ i | |
911 | + @config.config_opt = ARGV.dup | |
912 | + break | |
913 | + end | |
914 | + name, value = *@config.parse_opt(i) | |
915 | + if @config.value_config?(name) | |
916 | + @config[name] = value | |
917 | + else | |
918 | + evalopt.push [name, value] | |
919 | + end | |
920 | + set.push name | |
921 | + end | |
922 | + evalopt.each do |name, value| | |
923 | + @config.lookup(name).evaluate value, @config | |
924 | + end | |
925 | + # Check if configuration is valid | |
926 | + set.each do |n| | |
927 | + @config[n] if @config.value_config?(n) | |
928 | + end | |
929 | + end | |
930 | + | |
931 | + def parsearg_install | |
932 | + @config.no_harm = false | |
933 | + @config.install_prefix = '' | |
934 | + while a = ARGV.shift | |
935 | + case a | |
936 | + when '--no-harm' | |
937 | + @config.no_harm = true | |
938 | + when /\A--prefix=/ | |
939 | + path = a.split(/=/, 2)[1] | |
940 | + path = File.expand_path(path) unless path[0,1] == '/' | |
941 | + @config.install_prefix = path | |
942 | + else | |
943 | + setup_rb_error "install: unknown option #{a}" | |
944 | + end | |
945 | + end | |
946 | + end | |
947 | + | |
948 | + def print_usage(out) | |
949 | + out.puts 'Typical Installation Procedure:' | |
950 | + out.puts " $ ruby #{File.basename $0} config" | |
951 | + out.puts " $ ruby #{File.basename $0} setup" | |
952 | + out.puts " # ruby #{File.basename $0} install (may require root privilege)" | |
953 | + out.puts | |
954 | + out.puts 'Detailed Usage:' | |
955 | + out.puts " ruby #{File.basename $0} <global option>" | |
956 | + out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]" | |
957 | + | |
958 | + fmt = " %-24s %s\n" | |
959 | + out.puts | |
960 | + out.puts 'Global options:' | |
961 | + out.printf fmt, '-q,--quiet', 'suppress message outputs' | |
962 | + out.printf fmt, ' --verbose', 'output messages verbosely' | |
963 | + out.printf fmt, ' --help', 'print this message' | |
964 | + out.printf fmt, ' --version', 'print version and quit' | |
965 | + out.printf fmt, ' --copyright', 'print copyright and quit' | |
966 | + out.puts | |
967 | + out.puts 'Tasks:' | |
968 | + TASKS.each do |name, desc| | |
969 | + out.printf fmt, name, desc | |
970 | + end | |
971 | + | |
972 | + fmt = " %-24s %s [%s]\n" | |
973 | + out.puts | |
974 | + out.puts 'Options for CONFIG or ALL:' | |
975 | + @config.each do |item| | |
976 | + out.printf fmt, item.help_opt, item.description, item.help_default | |
977 | + end | |
978 | + out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" | |
979 | + out.puts | |
980 | + out.puts 'Options for INSTALL:' | |
981 | + out.printf fmt, '--no-harm', 'only display what to do if given', 'off' | |
982 | + out.printf fmt, '--prefix=path', 'install path prefix', '' | |
983 | + out.puts | |
984 | + end | |
985 | + | |
986 | + # | |
987 | + # Task Handlers | |
988 | + # | |
989 | + | |
990 | + def exec_config | |
991 | + @installer.exec_config | |
992 | + @config.save # must be final | |
993 | + end | |
994 | + | |
995 | + def exec_setup | |
996 | + @installer.exec_setup | |
997 | + end | |
998 | + | |
999 | + def exec_install | |
1000 | + @installer.exec_install | |
1001 | + end | |
1002 | + | |
1003 | + def exec_test | |
1004 | + @installer.exec_test | |
1005 | + end | |
1006 | + | |
1007 | + def exec_show | |
1008 | + @config.each do |i| | |
1009 | + printf "%-20s %s\n", i.name, i.value if i.value? | |
1010 | + end | |
1011 | + end | |
1012 | + | |
1013 | + def exec_clean | |
1014 | + @installer.exec_clean | |
1015 | + end | |
1016 | + | |
1017 | + def exec_distclean | |
1018 | + @installer.exec_distclean | |
1019 | + end | |
1020 | + | |
1021 | +end # class ToplevelInstaller | |
1022 | + | |
1023 | + | |
1024 | +class ToplevelInstallerMulti < ToplevelInstaller | |
1025 | + | |
1026 | + include FileOperations | |
1027 | + | |
1028 | + def initialize(ardir_root, config) | |
1029 | + super | |
1030 | + @packages = directories_of("#{@ardir}/packages") | |
1031 | + raise 'no package exists' if @packages.empty? | |
1032 | + @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) | |
1033 | + end | |
1034 | + | |
1035 | + def run_metaconfigs | |
1036 | + @config.load_script "#{@ardir}/metaconfig", self | |
1037 | + @packages.each do |name| | |
1038 | + @config.load_script "#{@ardir}/packages/#{name}/metaconfig" | |
1039 | + end | |
1040 | + end | |
1041 | + | |
1042 | + attr_reader :packages | |
1043 | + | |
1044 | + def packages=(list) | |
1045 | + raise 'package list is empty' if list.empty? | |
1046 | + list.each do |name| | |
1047 | + raise "directory packages/#{name} does not exist"\ | |
1048 | + unless File.dir?("#{@ardir}/packages/#{name}") | |
1049 | + end | |
1050 | + @packages = list | |
1051 | + end | |
1052 | + | |
1053 | + def init_installers | |
1054 | + @installers = {} | |
1055 | + @packages.each do |pack| | |
1056 | + @installers[pack] = Installer.new(@config, | |
1057 | + "#{@ardir}/packages/#{pack}", | |
1058 | + "packages/#{pack}") | |
1059 | + end | |
1060 | + with = extract_selection(config('with')) | |
1061 | + without = extract_selection(config('without')) | |
1062 | + @selected = @installers.keys.select {|name| | |
1063 | + (with.empty? or with.include?(name)) \ | |
1064 | + and not without.include?(name) | |
1065 | + } | |
1066 | + end | |
1067 | + | |
1068 | + def extract_selection(list) | |
1069 | + a = list.split(/,/) | |
1070 | + a.each do |name| | |
1071 | + setup_rb_error "no such package: #{name}" unless @installers.key?(name) | |
1072 | + end | |
1073 | + a | |
1074 | + end | |
1075 | + | |
1076 | + def print_usage(f) | |
1077 | + super | |
1078 | + f.puts 'Inluded packages:' | |
1079 | + f.puts ' ' + @packages.sort.join(' ') | |
1080 | + f.puts | |
1081 | + end | |
1082 | + | |
1083 | + # | |
1084 | + # Task Handlers | |
1085 | + # | |
1086 | + | |
1087 | + def exec_config | |
1088 | + run_hook 'pre-config' | |
1089 | + each_selected_installers {|inst| inst.exec_config } | |
1090 | + run_hook 'post-config' | |
1091 | + @config.save # must be final | |
1092 | + end | |
1093 | + | |
1094 | + def exec_setup | |
1095 | + run_hook 'pre-setup' | |
1096 | + each_selected_installers {|inst| inst.exec_setup } | |
1097 | + run_hook 'post-setup' | |
1098 | + end | |
1099 | + | |
1100 | + def exec_install | |
1101 | + run_hook 'pre-install' | |
1102 | + each_selected_installers {|inst| inst.exec_install } | |
1103 | + run_hook 'post-install' | |
1104 | + end | |
1105 | + | |
1106 | + def exec_test | |
1107 | + run_hook 'pre-test' | |
1108 | + each_selected_installers {|inst| inst.exec_test } | |
1109 | + run_hook 'post-test' | |
1110 | + end | |
1111 | + | |
1112 | + def exec_clean | |
1113 | + rm_f @config.savefile | |
1114 | + run_hook 'pre-clean' | |
1115 | + each_selected_installers {|inst| inst.exec_clean } | |
1116 | + run_hook 'post-clean' | |
1117 | + end | |
1118 | + | |
1119 | + def exec_distclean | |
1120 | + rm_f @config.savefile | |
1121 | + run_hook 'pre-distclean' | |
1122 | + each_selected_installers {|inst| inst.exec_distclean } | |
1123 | + run_hook 'post-distclean' | |
1124 | + end | |
1125 | + | |
1126 | + # | |
1127 | + # lib | |
1128 | + # | |
1129 | + | |
1130 | + def each_selected_installers | |
1131 | + Dir.mkdir 'packages' unless File.dir?('packages') | |
1132 | + @selected.each do |pack| | |
1133 | + $stderr.puts "Processing the package `#{pack}' ..." if verbose? | |
1134 | + Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") | |
1135 | + Dir.chdir "packages/#{pack}" | |
1136 | + yield @installers[pack] | |
1137 | + Dir.chdir '../..' | |
1138 | + end | |
1139 | + end | |
1140 | + | |
1141 | + def run_hook(id) | |
1142 | + @root_installer.run_hook id | |
1143 | + end | |
1144 | + | |
1145 | + # module FileOperations requires this | |
1146 | + def verbose? | |
1147 | + @config.verbose? | |
1148 | + end | |
1149 | + | |
1150 | + # module FileOperations requires this | |
1151 | + def no_harm? | |
1152 | + @config.no_harm? | |
1153 | + end | |
1154 | + | |
1155 | +end # class ToplevelInstallerMulti | |
1156 | + | |
1157 | + | |
1158 | +class Installer | |
1159 | + | |
1160 | + FILETYPES = %w( bin lib ext data conf man ) | |
1161 | + | |
1162 | + include FileOperations | |
1163 | + include HookScriptAPI | |
1164 | + | |
1165 | + def initialize(config, srcroot, objroot) | |
1166 | + @config = config | |
1167 | + @srcdir = File.expand_path(srcroot) | |
1168 | + @objdir = File.expand_path(objroot) | |
1169 | + @currdir = '.' | |
1170 | + end | |
1171 | + | |
1172 | + def inspect | |
1173 | + "#<#{self.class} #{File.basename(@srcdir)}>" | |
1174 | + end | |
1175 | + | |
1176 | + def noop(rel) | |
1177 | + end | |
1178 | + | |
1179 | + # | |
1180 | + # Hook Script API base methods | |
1181 | + # | |
1182 | + | |
1183 | + def srcdir_root | |
1184 | + @srcdir | |
1185 | + end | |
1186 | + | |
1187 | + def objdir_root | |
1188 | + @objdir | |
1189 | + end | |
1190 | + | |
1191 | + def relpath | |
1192 | + @currdir | |
1193 | + end | |
1194 | + | |
1195 | + # | |
1196 | + # Config Access | |
1197 | + # | |
1198 | + | |
1199 | + # module FileOperations requires this | |
1200 | + def verbose? | |
1201 | + @config.verbose? | |
1202 | + end | |
1203 | + | |
1204 | + # module FileOperations requires this | |
1205 | + def no_harm? | |
1206 | + @config.no_harm? | |
1207 | + end | |
1208 | + | |
1209 | + def verbose_off | |
1210 | + begin | |
1211 | + save, @config.verbose = @config.verbose?, false | |
1212 | + yield | |
1213 | + ensure | |
1214 | + @config.verbose = save | |
1215 | + end | |
1216 | + end | |
1217 | + | |
1218 | + # | |
1219 | + # TASK config | |
1220 | + # | |
1221 | + | |
1222 | + def exec_config | |
1223 | + exec_task_traverse 'config' | |
1224 | + end | |
1225 | + | |
1226 | + alias config_dir_bin noop | |
1227 | + alias config_dir_lib noop | |
1228 | + | |
1229 | + def config_dir_ext(rel) | |
1230 | + extconf if extdir?(curr_srcdir()) | |
1231 | + end | |
1232 | + | |
1233 | + alias config_dir_data noop | |
1234 | + alias config_dir_conf noop | |
1235 | + alias config_dir_man noop | |
1236 | + | |
1237 | + def extconf | |
1238 | + ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt | |
1239 | + end | |
1240 | + | |
1241 | + # | |
1242 | + # TASK setup | |
1243 | + # | |
1244 | + | |
1245 | + def exec_setup | |
1246 | + exec_task_traverse 'setup' | |
1247 | + end | |
1248 | + | |
1249 | + def setup_dir_bin(rel) | |
1250 | + files_of(curr_srcdir()).each do |fname| | |
1251 | + update_shebang_line "#{curr_srcdir()}/#{fname}" | |
1252 | + end | |
1253 | + end | |
1254 | + | |
1255 | + alias setup_dir_lib noop | |
1256 | + | |
1257 | + def setup_dir_ext(rel) | |
1258 | + make if extdir?(curr_srcdir()) | |
1259 | + end | |
1260 | + | |
1261 | + alias setup_dir_data noop | |
1262 | + alias setup_dir_conf noop | |
1263 | + alias setup_dir_man noop | |
1264 | + | |
1265 | + def update_shebang_line(path) | |
1266 | + return if no_harm? | |
1267 | + return if config('shebang') == 'never' | |
1268 | + old = Shebang.load(path) | |
1269 | + if old | |
1270 | + $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 | |
1271 | + new = new_shebang(old) | |
1272 | + return if new.to_s == old.to_s | |
1273 | + else | |
1274 | + return unless config('shebang') == 'all' | |
1275 | + new = Shebang.new(config('rubypath')) | |
1276 | + end | |
1277 | + $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? | |
1278 | + open_atomic_writer(path) {|output| | |
1279 | + File.open(path, 'rb') {|f| | |
1280 | + f.gets if old # discard | |
1281 | + output.puts new.to_s | |
1282 | + output.print f.read | |
1283 | + } | |
1284 | + } | |
1285 | + end | |
1286 | + | |
1287 | + def new_shebang(old) | |
1288 | + if /\Aruby/ =~ File.basename(old.cmd) | |
1289 | + Shebang.new(config('rubypath'), old.args) | |
1290 | + elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' | |
1291 | + Shebang.new(config('rubypath'), old.args[1..-1]) | |
1292 | + else | |
1293 | + return old unless config('shebang') == 'all' | |
1294 | + Shebang.new(config('rubypath')) | |
1295 | + end | |
1296 | + end | |
1297 | + | |
1298 | + def open_atomic_writer(path, &block) | |
1299 | + tmpfile = File.basename(path) + '.tmp' | |
1300 | + begin | |
1301 | + File.open(tmpfile, 'wb', &block) | |
1302 | + File.rename tmpfile, File.basename(path) | |
1303 | + ensure | |
1304 | + File.unlink tmpfile if File.exist?(tmpfile) | |
1305 | + end | |
1306 | + end | |
1307 | + | |
1308 | + class Shebang | |
1309 | + def Shebang.load(path) | |
1310 | + line = nil | |
1311 | + File.open(path) {|f| | |
1312 | + line = f.gets | |
1313 | + } | |
1314 | + return nil unless /\A#!/ =~ line | |
1315 | + parse(line) | |
1316 | + end | |
1317 | + | |
1318 | + def Shebang.parse(line) | |
1319 | + cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') | |
1320 | + new(cmd, args) | |
1321 | + end | |
1322 | + | |
1323 | + def initialize(cmd, args = []) | |
1324 | + @cmd = cmd | |
1325 | + @args = args | |
1326 | + end | |
1327 | + | |
1328 | + attr_reader :cmd | |
1329 | + attr_reader :args | |
1330 | + | |
1331 | + def to_s | |
1332 | + "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") | |
1333 | + end | |
1334 | + end | |
1335 | + | |
1336 | + # | |
1337 | + # TASK install | |
1338 | + # | |
1339 | + | |
1340 | + def exec_install | |
1341 | + rm_f 'InstalledFiles' | |
1342 | + exec_task_traverse 'install' | |
1343 | + end | |
1344 | + | |
1345 | + def install_dir_bin(rel) | |
1346 | + install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 | |
1347 | + end | |
1348 | + | |
1349 | + def install_dir_lib(rel) | |
1350 | + install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 | |
1351 | + end | |
1352 | + | |
1353 | + def install_dir_ext(rel) | |
1354 | + return unless extdir?(curr_srcdir()) | |
1355 | + install_files rubyextentions('.'), | |
1356 | + "#{config('sodir')}/#{File.dirname(rel)}", | |
1357 | + 0555 | |
1358 | + end | |
1359 | + | |
1360 | + def install_dir_data(rel) | |
1361 | + install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 | |
1362 | + end | |
1363 | + | |
1364 | + def install_dir_conf(rel) | |
1365 | + # FIXME: should not remove current config files | |
1366 | + # (rename previous file to .old/.org) | |
1367 | + install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 | |
1368 | + end | |
1369 | + | |
1370 | + def install_dir_man(rel) | |
1371 | + install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 | |
1372 | + end | |
1373 | + | |
1374 | + def install_files(list, dest, mode) | |
1375 | + mkdir_p dest, @config.install_prefix | |
1376 | + list.each do |fname| | |
1377 | + install fname, dest, mode, @config.install_prefix | |
1378 | + end | |
1379 | + end | |
1380 | + | |
1381 | + def libfiles | |
1382 | + glob_reject(%w(*.y *.output), targetfiles()) | |
1383 | + end | |
1384 | + | |
1385 | + def rubyextentions(dir) | |
1386 | + ents = glob_select("*.#{@config.dllext}", targetfiles()) | |
1387 | + if ents.empty? | |
1388 | + setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" | |
1389 | + end | |
1390 | + ents | |
1391 | + end | |
1392 | + | |
1393 | + def targetfiles | |
1394 | + mapdir(existfiles() - hookfiles()) | |
1395 | + end | |
1396 | + | |
1397 | + def mapdir(ents) | |
1398 | + ents.map {|ent| | |
1399 | + if File.exist?(ent) | |
1400 | + then ent # objdir | |
1401 | + else "#{curr_srcdir()}/#{ent}" # srcdir | |
1402 | + end | |
1403 | + } | |
1404 | + end | |
1405 | + | |
1406 | + # picked up many entries from cvs-1.11.1/src/ignore.c | |
1407 | + JUNK_FILES = %w( | |
1408 | + core RCSLOG tags TAGS .make.state | |
1409 | + .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb | |
1410 | + *~ *.old *.bak *.BAK *.orig *.rej _$* *$ | |
1411 | + | |
1412 | + *.org *.in .* | |
1413 | + ) | |
1414 | + | |
1415 | + def existfiles | |
1416 | + glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) | |
1417 | + end | |
1418 | + | |
1419 | + def hookfiles | |
1420 | + %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| | |
1421 | + %w( config setup install clean ).map {|t| sprintf(fmt, t) } | |
1422 | + }.flatten | |
1423 | + end | |
1424 | + | |
1425 | + def glob_select(pat, ents) | |
1426 | + re = globs2re([pat]) | |
1427 | + ents.select {|ent| re =~ ent } | |
1428 | + end | |
1429 | + | |
1430 | + def glob_reject(pats, ents) | |
1431 | + re = globs2re(pats) | |
1432 | + ents.reject {|ent| re =~ ent } | |
1433 | + end | |
1434 | + | |
1435 | + GLOB2REGEX = { | |
1436 | + '.' => '\.', | |
1437 | + '$' => '\$', | |
1438 | + '#' => '\#', | |
1439 | + '*' => '.*' | |
1440 | + } | |
1441 | + | |
1442 | + def globs2re(pats) | |
1443 | + /\A(?:#{ | |
1444 | + pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') | |
1445 | + })\z/ | |
1446 | + end | |
1447 | + | |
1448 | + # | |
1449 | + # TASK test | |
1450 | + # | |
1451 | + | |
1452 | + TESTDIR = 'test' | |
1453 | + | |
1454 | + def exec_test | |
1455 | + unless File.directory?('test') | |
1456 | + $stderr.puts 'no test in this package' if verbose? | |
1457 | + return | |
1458 | + end | |
1459 | + $stderr.puts 'Running tests...' if verbose? | |
1460 | + begin | |
1461 | + require 'test/unit' | |
1462 | + rescue LoadError | |
1463 | + setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' | |
1464 | + end | |
1465 | + runner = Test::Unit::AutoRunner.new(true) | |
1466 | + runner.to_run << TESTDIR | |
1467 | + runner.run | |
1468 | + end | |
1469 | + | |
1470 | + # | |
1471 | + # TASK clean | |
1472 | + # | |
1473 | + | |
1474 | + def exec_clean | |
1475 | + exec_task_traverse 'clean' | |
1476 | + rm_f @config.savefile | |
1477 | + rm_f 'InstalledFiles' | |
1478 | + end | |
1479 | + | |
1480 | + alias clean_dir_bin noop | |
1481 | + alias clean_dir_lib noop | |
1482 | + alias clean_dir_data noop | |
1483 | + alias clean_dir_conf noop | |
1484 | + alias clean_dir_man noop | |
1485 | + | |
1486 | + def clean_dir_ext(rel) | |
1487 | + return unless extdir?(curr_srcdir()) | |
1488 | + make 'clean' if File.file?('Makefile') | |
1489 | + end | |
1490 | + | |
1491 | + # | |
1492 | + # TASK distclean | |
1493 | + # | |
1494 | + | |
1495 | + def exec_distclean | |
1496 | + exec_task_traverse 'distclean' | |
1497 | + rm_f @config.savefile | |
1498 | + rm_f 'InstalledFiles' | |
1499 | + end | |
1500 | + | |
1501 | + alias distclean_dir_bin noop | |
1502 | + alias distclean_dir_lib noop | |
1503 | + | |
1504 | + def distclean_dir_ext(rel) | |
1505 | + return unless extdir?(curr_srcdir()) | |
1506 | + make 'distclean' if File.file?('Makefile') | |
1507 | + end | |
1508 | + | |
1509 | + alias distclean_dir_data noop | |
1510 | + alias distclean_dir_conf noop | |
1511 | + alias distclean_dir_man noop | |
1512 | + | |
1513 | + # | |
1514 | + # Traversing | |
1515 | + # | |
1516 | + | |
1517 | + def exec_task_traverse(task) | |
1518 | + run_hook "pre-#{task}" | |
1519 | + FILETYPES.each do |type| | |
1520 | + if type == 'ext' and config('without-ext') == 'yes' | |
1521 | + $stderr.puts 'skipping ext/* by user option' if verbose? | |
1522 | + next | |
1523 | + end | |
1524 | + traverse task, type, "#{task}_dir_#{type}" | |
1525 | + end | |
1526 | + run_hook "post-#{task}" | |
1527 | + end | |
1528 | + | |
1529 | + def traverse(task, rel, mid) | |
1530 | + dive_into(rel) { | |
1531 | + run_hook "pre-#{task}" | |
1532 | + __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') | |
1533 | + directories_of(curr_srcdir()).each do |d| | |
1534 | + traverse task, "#{rel}/#{d}", mid | |
1535 | + end | |
1536 | + run_hook "post-#{task}" | |
1537 | + } | |
1538 | + end | |
1539 | + | |
1540 | + def dive_into(rel) | |
1541 | + return unless File.dir?("#{@srcdir}/#{rel}") | |
1542 | + | |
1543 | + dir = File.basename(rel) | |
1544 | + Dir.mkdir dir unless File.dir?(dir) | |
1545 | + prevdir = Dir.pwd | |
1546 | + Dir.chdir dir | |
1547 | + $stderr.puts '---> ' + rel if verbose? | |
1548 | + @currdir = rel | |
1549 | + yield | |
1550 | + Dir.chdir prevdir | |
1551 | + $stderr.puts '<--- ' + rel if verbose? | |
1552 | + @currdir = File.dirname(rel) | |
1553 | + end | |
1554 | + | |
1555 | + def run_hook(id) | |
1556 | + path = [ "#{curr_srcdir()}/#{id}", | |
1557 | + "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } | |
1558 | + return unless path | |
1559 | + begin | |
1560 | + instance_eval File.read(path), path, 1 | |
1561 | + rescue | |
1562 | + raise if $DEBUG | |
1563 | + setup_rb_error "hook #{path} failed:\n" + $!.message | |
1564 | + end | |
1565 | + end | |
1566 | + | |
1567 | +end # class Installer | |
1568 | + | |
1569 | + | |
1570 | +class SetupError < StandardError; end | |
1571 | + | |
1572 | +def setup_rb_error(msg) | |
1573 | + raise SetupError, msg | |
1574 | +end | |
1575 | + | |
1576 | +if $0 == __FILE__ | |
1577 | + begin | |
1578 | + ToplevelInstaller.invoke | |
1579 | + rescue SetupError | |
1580 | + raise if $DEBUG | |
1581 | + $stderr.puts $!.message | |
1582 | + $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." | |
1583 | + exit 1 | |
1584 | + end | |
1585 | +end | ... | ... |
... | ... | @@ -0,0 +1,356 @@ |
1 | +#! /usr/bin/env ruby | |
2 | +#-- | |
3 | +# MIME::Types | |
4 | +# A Ruby implementation of a MIME Types information library. Based in spirit | |
5 | +# on the Perl MIME::Types information library by Mark Overmeer. | |
6 | +# http://rubyforge.org/projects/mime-types/ | |
7 | +# | |
8 | +# Licensed under the Ruby disjunctive licence with the GNU GPL or the Perl | |
9 | +# Artistic licence. See Licence.txt for more information. | |
10 | +# | |
11 | +# Copyright 2003 - 2009 Austin Ziegler | |
12 | +#++ | |
13 | +$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0 | |
14 | + | |
15 | +require 'mime/types' | |
16 | +require 'test/unit' unless defined? $ZENTEST and $ZENTEST | |
17 | + | |
18 | +module TestMIME | |
19 | + class TestType < Test::Unit::TestCase #:nodoc: | |
20 | + def setup | |
21 | + @zip = MIME::Type.new('x-appl/x-zip') { |t| t.extensions = ['zip', 'zp'] } | |
22 | + end | |
23 | + | |
24 | + def test_class_from_array | |
25 | + assert_nothing_raised do | |
26 | + @yaml = MIME::Type.from_array('text/x-yaml', %w(yaml yml), '8bit', 'linux') | |
27 | + end | |
28 | + assert_instance_of(MIME::Type, @yaml) | |
29 | + assert_equal('text/yaml', @yaml.simplified) | |
30 | + end | |
31 | + | |
32 | + def test_class_from_hash | |
33 | + assert_nothing_raised do | |
34 | + @yaml = MIME::Type.from_hash('Content-Type' => 'text/x-yaml', | |
35 | + 'Content-Transfer-Encoding' => '8bit', | |
36 | + 'System' => 'linux', | |
37 | + 'Extensions' => %w(yaml yml)) | |
38 | + end | |
39 | + assert_instance_of(MIME::Type, @yaml) | |
40 | + assert_equal('text/yaml', @yaml.simplified) | |
41 | + end | |
42 | + | |
43 | + def test_class_from_mime_type | |
44 | + assert_nothing_raised do | |
45 | + @zip2 = MIME::Type.from_mime_type(@zip) | |
46 | + end | |
47 | + assert_instance_of(MIME::Type, @zip) | |
48 | + assert_equal('appl/zip', @zip.simplified) | |
49 | + assert_not_equal(@zip.object_id, @zip2.object_id) | |
50 | + end | |
51 | + | |
52 | + def test_class_simplified | |
53 | + assert_equal(MIME::Type.simplified('text/plain'), 'text/plain') | |
54 | + assert_equal(MIME::Type.simplified('image/jpeg'), 'image/jpeg') | |
55 | + assert_equal(MIME::Type.simplified('application/x-msword'), 'application/msword') | |
56 | + assert_equal(MIME::Type.simplified('text/vCard'), 'text/vcard') | |
57 | + assert_equal(MIME::Type.simplified('application/pkcs7-mime'), 'application/pkcs7-mime') | |
58 | + assert_equal(@zip.simplified, 'appl/zip') | |
59 | + assert_equal(MIME::Type.simplified('x-xyz/abc'), 'xyz/abc') | |
60 | + end | |
61 | + | |
62 | + def test_CMP # '<=>' | |
63 | + assert(MIME::Type.new('text/plain') == MIME::Type.new('text/plain')) | |
64 | + assert(MIME::Type.new('text/plain') != MIME::Type.new('image/jpeg')) | |
65 | + assert(MIME::Type.new('text/plain') == 'text/plain') | |
66 | + assert(MIME::Type.new('text/plain') != 'image/jpeg') | |
67 | + assert(MIME::Type.new('text/plain') > MIME::Type.new('text/html')) | |
68 | + assert(MIME::Type.new('text/plain') > 'text/html') | |
69 | + assert(MIME::Type.new('text/html') < MIME::Type.new('text/plain')) | |
70 | + assert(MIME::Type.new('text/html') < 'text/plain') | |
71 | + assert('text/html' == MIME::Type.new('text/html')) | |
72 | + assert('text/html' < MIME::Type.new('text/plain')) | |
73 | + assert('text/plain' > MIME::Type.new('text/html')) | |
74 | + end | |
75 | + | |
76 | + def test_ascii_eh | |
77 | + assert(MIME::Type.new('text/plain').ascii?) | |
78 | + assert(!MIME::Type.new('image/jpeg').ascii?) | |
79 | + assert(!MIME::Type.new('application/x-msword').ascii?) | |
80 | + assert(MIME::Type.new('text/vCard').ascii?) | |
81 | + assert(!MIME::Type.new('application/pkcs7-mime').ascii?) | |
82 | + assert(!@zip.ascii?) | |
83 | + end | |
84 | + | |
85 | + def test_binary_eh | |
86 | + assert(!MIME::Type.new('text/plain').binary?) | |
87 | + assert(MIME::Type.new('image/jpeg').binary?) | |
88 | + assert(MIME::Type.new('application/x-msword').binary?) | |
89 | + assert(!MIME::Type.new('text/vCard').binary?) | |
90 | + assert(MIME::Type.new('application/pkcs7-mime').binary?) | |
91 | + assert(@zip.binary?) | |
92 | + end | |
93 | + | |
94 | + def test_complete_eh | |
95 | + assert_nothing_raised do | |
96 | + @yaml = MIME::Type.from_array('text/x-yaml', %w(yaml yml), '8bit', | |
97 | + 'linux') | |
98 | + end | |
99 | + assert(@yaml.complete?) | |
100 | + assert_nothing_raised { @yaml.extensions = nil } | |
101 | + assert(!@yaml.complete?) | |
102 | + end | |
103 | + | |
104 | + def test_content_type | |
105 | + assert_equal(MIME::Type.new('text/plain').content_type, 'text/plain') | |
106 | + assert_equal(MIME::Type.new('image/jpeg').content_type, 'image/jpeg') | |
107 | + assert_equal(MIME::Type.new('application/x-msword').content_type, 'application/x-msword') | |
108 | + assert_equal(MIME::Type.new('text/vCard').content_type, 'text/vCard') | |
109 | + assert_equal(MIME::Type.new('application/pkcs7-mime').content_type, 'application/pkcs7-mime') | |
110 | + assert_equal(@zip.content_type, 'x-appl/x-zip'); | |
111 | + end | |
112 | + | |
113 | + def test_encoding | |
114 | + assert_equal(MIME::Type.new('text/plain').encoding, 'quoted-printable') | |
115 | + assert_equal(MIME::Type.new('image/jpeg').encoding, 'base64') | |
116 | + assert_equal(MIME::Type.new('application/x-msword').encoding, 'base64') | |
117 | + assert_equal(MIME::Type.new('text/vCard').encoding, 'quoted-printable') | |
118 | + assert_equal(MIME::Type.new('application/pkcs7-mime').encoding, 'base64') | |
119 | + assert_nothing_raised do | |
120 | + @yaml = MIME::Type.from_array('text/x-yaml', %w(yaml yml), '8bit', | |
121 | + 'linux') | |
122 | + end | |
123 | + assert_equal(@yaml.encoding, '8bit') | |
124 | + assert_nothing_raised { @yaml.encoding = 'base64' } | |
125 | + assert_equal(@yaml.encoding, 'base64') | |
126 | + assert_nothing_raised { @yaml.encoding = :default } | |
127 | + assert_equal(@yaml.encoding, 'quoted-printable') | |
128 | + assert_raises(ArgumentError) { @yaml.encoding = 'binary' } | |
129 | + assert_equal(@zip.encoding, 'base64') | |
130 | + end | |
131 | + | |
132 | + def _test_default_encoding | |
133 | + raise NotImplementedError, 'Need to write test_default_encoding' | |
134 | + end | |
135 | + | |
136 | + def _test_docs | |
137 | + raise NotImplementedError, 'Need to write test_docs' | |
138 | + end | |
139 | + | |
140 | + def _test_docs_equals | |
141 | + raise NotImplementedError, 'Need to write test_docs_equals' | |
142 | + end | |
143 | + | |
144 | + def test_eql? | |
145 | + assert(MIME::Type.new('text/plain').eql?(MIME::Type.new('text/plain'))) | |
146 | + assert(!MIME::Type.new('text/plain').eql?(MIME::Type.new('image/jpeg'))) | |
147 | + assert(!MIME::Type.new('text/plain').eql?('text/plain')) | |
148 | + assert(!MIME::Type.new('text/plain').eql?('image/jpeg')) | |
149 | + end | |
150 | + | |
151 | + def _test_encoding | |
152 | + raise NotImplementedError, 'Need to write test_encoding' | |
153 | + end | |
154 | + | |
155 | + def _test_encoding_equals | |
156 | + raise NotImplementedError, 'Need to write test_encoding_equals' | |
157 | + end | |
158 | + | |
159 | + def test_extensions | |
160 | + assert_nothing_raised do | |
161 | + @yaml = MIME::Type.from_array('text/x-yaml', %w(yaml yml), '8bit', | |
162 | + 'linux') | |
163 | + end | |
164 | + assert_equal(@yaml.extensions, %w(yaml yml)) | |
165 | + assert_nothing_raised { @yaml.extensions = 'yaml' } | |
166 | + assert_equal(@yaml.extensions, ['yaml']) | |
167 | + assert_equal(@zip.extensions.size, 2) | |
168 | + assert_equal(@zip.extensions, ['zip', 'zp']) | |
169 | + end | |
170 | + | |
171 | + def _test_extensions_equals | |
172 | + raise NotImplementedError, 'Need to write test_extensions_equals' | |
173 | + end | |
174 | + | |
175 | + def test_like_eh | |
176 | + assert(MIME::Type.new('text/plain').like?(MIME::Type.new('text/plain'))) | |
177 | + assert(MIME::Type.new('text/plain').like?(MIME::Type.new('text/x-plain'))) | |
178 | + assert(!MIME::Type.new('text/plain').like?(MIME::Type.new('image/jpeg'))) | |
179 | + assert(MIME::Type.new('text/plain').like?('text/plain')) | |
180 | + assert(MIME::Type.new('text/plain').like?('text/x-plain')) | |
181 | + assert(!MIME::Type.new('text/plain').like?('image/jpeg')) | |
182 | + end | |
183 | + | |
184 | + def test_media_type | |
185 | + assert_equal(MIME::Type.new('text/plain').media_type, 'text') | |
186 | + assert_equal(MIME::Type.new('image/jpeg').media_type, 'image') | |
187 | + assert_equal(MIME::Type.new('application/x-msword').media_type, 'application') | |
188 | + assert_equal(MIME::Type.new('text/vCard').media_type, 'text') | |
189 | + assert_equal(MIME::Type.new('application/pkcs7-mime').media_type, 'application') | |
190 | + assert_equal(MIME::Type.new('x-chemical/x-pdb').media_type, 'chemical') | |
191 | + assert_equal(@zip.media_type, 'appl') | |
192 | + end | |
193 | + | |
194 | + def _test_obsolete_eh | |
195 | + raise NotImplementedError, 'Need to write test_obsolete_eh' | |
196 | + end | |
197 | + | |
198 | + def _test_obsolete_equals | |
199 | + raise NotImplementedError, 'Need to write test_obsolete_equals' | |
200 | + end | |
201 | + | |
202 | + def test_platform_eh | |
203 | + assert_nothing_raised do | |
204 | + @yaml = MIME::Type.from_array('text/x-yaml', %w(yaml yml), '8bit', | |
205 | + 'oddbox') | |
206 | + end | |
207 | + assert(!@yaml.platform?) | |
208 | + assert_nothing_raised { @yaml.system = nil } | |
209 | + assert(!@yaml.platform?) | |
210 | + assert_nothing_raised { @yaml.system = /#{RUBY_PLATFORM}/ } | |
211 | + assert(@yaml.platform?) | |
212 | + end | |
213 | + | |
214 | + def test_raw_media_type | |
215 | + assert_equal(MIME::Type.new('text/plain').raw_media_type, 'text') | |
216 | + assert_equal(MIME::Type.new('image/jpeg').raw_media_type, 'image') | |
217 | + assert_equal(MIME::Type.new('application/x-msword').raw_media_type, 'application') | |
218 | + assert_equal(MIME::Type.new('text/vCard').raw_media_type, 'text') | |
219 | + assert_equal(MIME::Type.new('application/pkcs7-mime').raw_media_type, 'application') | |
220 | + | |
221 | + assert_equal(MIME::Type.new('x-chemical/x-pdb').raw_media_type, 'x-chemical') | |
222 | + assert_equal(@zip.raw_media_type, 'x-appl') | |
223 | + end | |
224 | + | |
225 | + def test_raw_sub_type | |
226 | + assert_equal(MIME::Type.new('text/plain').raw_sub_type, 'plain') | |
227 | + assert_equal(MIME::Type.new('image/jpeg').raw_sub_type, 'jpeg') | |
228 | + assert_equal(MIME::Type.new('application/x-msword').raw_sub_type, 'x-msword') | |
229 | + assert_equal(MIME::Type.new('text/vCard').raw_sub_type, 'vCard') | |
230 | + assert_equal(MIME::Type.new('application/pkcs7-mime').raw_sub_type, 'pkcs7-mime') | |
231 | + assert_equal(@zip.raw_sub_type, 'x-zip') | |
232 | + end | |
233 | + | |
234 | + def test_registered_eh | |
235 | + assert(MIME::Type.new('text/plain').registered?) | |
236 | + assert(MIME::Type.new('image/jpeg').registered?) | |
237 | + assert(!MIME::Type.new('application/x-msword').registered?) | |
238 | + assert(MIME::Type.new('text/vCard').registered?) | |
239 | + assert(MIME::Type.new('application/pkcs7-mime').registered?) | |
240 | + assert(!@zip.registered?) | |
241 | + end | |
242 | + | |
243 | + def _test_registered_equals | |
244 | + raise NotImplementedError, 'Need to write test_registered_equals' | |
245 | + end | |
246 | + | |
247 | + def test_signature_eh | |
248 | + assert(!MIME::Type.new('text/plain').signature?) | |
249 | + assert(!MIME::Type.new('image/jpeg').signature?) | |
250 | + assert(!MIME::Type.new('application/x-msword').signature?) | |
251 | + assert(MIME::Type.new('text/vCard').signature?) | |
252 | + assert(MIME::Type.new('application/pkcs7-mime').signature?) | |
253 | + end | |
254 | + | |
255 | + def test_simplified | |
256 | + assert_equal(MIME::Type.new('text/plain').simplified, 'text/plain') | |
257 | + assert_equal(MIME::Type.new('image/jpeg').simplified, 'image/jpeg') | |
258 | + assert_equal(MIME::Type.new('application/x-msword').simplified, 'application/msword') | |
259 | + assert_equal(MIME::Type.new('text/vCard').simplified, 'text/vcard') | |
260 | + assert_equal(MIME::Type.new('application/pkcs7-mime').simplified, 'application/pkcs7-mime') | |
261 | + assert_equal(MIME::Type.new('x-chemical/x-pdb').simplified, 'chemical/pdb') | |
262 | + end | |
263 | + | |
264 | + def test_sub_type | |
265 | + assert_equal(MIME::Type.new('text/plain').sub_type, 'plain') | |
266 | + assert_equal(MIME::Type.new('image/jpeg').sub_type, 'jpeg') | |
267 | + assert_equal(MIME::Type.new('application/x-msword').sub_type, 'msword') | |
268 | + assert_equal(MIME::Type.new('text/vCard').sub_type, 'vcard') | |
269 | + assert_equal(MIME::Type.new('application/pkcs7-mime').sub_type, 'pkcs7-mime') | |
270 | + assert_equal(@zip.sub_type, 'zip') | |
271 | + end | |
272 | + | |
273 | + def test_system_equals | |
274 | + assert_nothing_raised do | |
275 | + @yaml = MIME::Type.from_array('text/x-yaml', %w(yaml yml), '8bit', | |
276 | + 'linux') | |
277 | + end | |
278 | + assert_equal(@yaml.system, %r{linux}) | |
279 | + assert_nothing_raised { @yaml.system = /win32/ } | |
280 | + assert_equal(@yaml.system, %r{win32}) | |
281 | + assert_nothing_raised { @yaml.system = nil } | |
282 | + assert_nil(@yaml.system) | |
283 | + end | |
284 | + | |
285 | + def test_system_eh | |
286 | + assert_nothing_raised do | |
287 | + @yaml = MIME::Type.from_array('text/x-yaml', %w(yaml yml), '8bit', | |
288 | + 'linux') | |
289 | + end | |
290 | + assert(@yaml.system?) | |
291 | + assert_nothing_raised { @yaml.system = nil } | |
292 | + assert(!@yaml.system?) | |
293 | + end | |
294 | + | |
295 | + def test_to_a | |
296 | + assert_nothing_raised do | |
297 | + @yaml = MIME::Type.from_array('text/x-yaml', %w(yaml yml), '8bit', | |
298 | + 'linux') | |
299 | + end | |
300 | + assert_equal(@yaml.to_a, ['text/x-yaml', %w(yaml yml), '8bit', | |
301 | + /linux/, nil, nil, nil, false]) | |
302 | + end | |
303 | + | |
304 | + def test_to_hash | |
305 | + assert_nothing_raised do | |
306 | + @yaml = MIME::Type.from_array('text/x-yaml', %w(yaml yml), '8bit', | |
307 | + 'linux') | |
308 | + end | |
309 | + assert_equal(@yaml.to_hash, | |
310 | + { 'Content-Type' => 'text/x-yaml', | |
311 | + 'Content-Transfer-Encoding' => '8bit', | |
312 | + 'Extensions' => %w(yaml yml), | |
313 | + 'System' => /linux/, | |
314 | + 'Registered' => false, | |
315 | + 'URL' => nil, | |
316 | + 'Obsolete' => nil, | |
317 | + 'Docs' => nil }) | |
318 | + end | |
319 | + | |
320 | + def test_to_s | |
321 | + assert_equal("#{MIME::Type.new('text/plain')}", 'text/plain') | |
322 | + end | |
323 | + | |
324 | + def test_class_constructors | |
325 | + assert_not_nil(@zip) | |
326 | + yaml = MIME::Type.new('text/x-yaml') do |y| | |
327 | + y.extensions = %w(yaml yml) | |
328 | + y.encoding = '8bit' | |
329 | + y.system = 'linux' | |
330 | + end | |
331 | + assert_instance_of(MIME::Type, yaml) | |
332 | + assert_raises(MIME::InvalidContentType) { MIME::Type.new('apps') } | |
333 | + assert_raises(MIME::InvalidContentType) { MIME::Type.new(nil) } | |
334 | + end | |
335 | + | |
336 | + def _test_to_str | |
337 | + raise NotImplementedError, 'Need to write test_to_str' | |
338 | + end | |
339 | + | |
340 | + def _test_url | |
341 | + raise NotImplementedError, 'Need to write test_url' | |
342 | + end | |
343 | + | |
344 | + def _test_url_equals | |
345 | + raise NotImplementedError, 'Need to write test_url_equals' | |
346 | + end | |
347 | + | |
348 | + def _test_urls | |
349 | + raise NotImplementedError, 'Need to write test_urls' | |
350 | + end | |
351 | + | |
352 | + def __test_use_instead | |
353 | + raise NotImplementedError, 'Need to write test_use_instead' | |
354 | + end | |
355 | + end | |
356 | +end | ... | ... |
... | ... | @@ -0,0 +1,122 @@ |
1 | +#! /usr/bin/env ruby | |
2 | +#-- | |
3 | +# MIME::Types | |
4 | +# A Ruby implementation of a MIME Types information library. Based in spirit | |
5 | +# on the Perl MIME::Types information library by Mark Overmeer. | |
6 | +# http://rubyforge.org/projects/mime-types/ | |
7 | +# | |
8 | +# Licensed under the Ruby disjunctive licence with the GNU GPL or the Perl | |
9 | +# Artistic licence. See Licence.txt for more information. | |
10 | +# | |
11 | +# Copyright 2003 - 2009 Austin Ziegler | |
12 | +#++ | |
13 | +$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib") if __FILE__ == $0 | |
14 | + | |
15 | +require 'mime/types' | |
16 | +require 'test/unit' unless defined? $ZENTEST and $ZENTEST | |
17 | + | |
18 | +module TestMIME | |
19 | + class TestTypes < Test::Unit::TestCase #:nodoc: | |
20 | + def test_class_index_1 | |
21 | + text_plain = MIME::Type.new('text/plain') do |t| | |
22 | + t.encoding = '8bit' | |
23 | + t.extensions = %w(asc txt c cc h hh cpp hpp dat hlp) | |
24 | + end | |
25 | + text_plain_vms = MIME::Type.new('text/plain') do |t| | |
26 | + t.encoding = '8bit' | |
27 | + t.extensions = %w(doc) | |
28 | + t.system = 'vms' | |
29 | + end | |
30 | + | |
31 | + assert_equal(MIME::Types['text/plain'], [text_plain, text_plain_vms]) | |
32 | + end | |
33 | + | |
34 | + def test_class_index_2 | |
35 | + tst_bmp = MIME::Types["image/x-bmp"] + | |
36 | + MIME::Types["image/vnd.wap.wbmp"] + MIME::Types["image/x-win-bmp"] | |
37 | + | |
38 | + assert_equal(tst_bmp.sort, MIME::Types[/bmp$/].sort) | |
39 | + | |
40 | + assert_nothing_raised { | |
41 | + MIME::Types['image/bmp'][0].system = RUBY_PLATFORM | |
42 | + } | |
43 | + | |
44 | + assert_equal([MIME::Type.from_array('image/x-bmp', ['bmp'])], | |
45 | + MIME::Types[/bmp$/, { :platform => true }]) | |
46 | + end | |
47 | + | |
48 | + def test_class_index_3 | |
49 | + assert(MIME::Types['text/vnd.fly', { :complete => true }].empty?) | |
50 | + assert(!MIME::Types['text/plain', { :complete => true} ].empty?) | |
51 | + end | |
52 | + | |
53 | + def _test_class_index_extensions | |
54 | + raise NotImplementedError, 'Need to write test_class_index_extensions' | |
55 | + end | |
56 | + | |
57 | + def _test_class_add | |
58 | + assert_nothing_raised do | |
59 | + @eruby = MIME::Type.new("application/x-eruby") do |t| | |
60 | + t.extensions = "rhtml" | |
61 | + t.encoding = "8bit" | |
62 | + end | |
63 | + | |
64 | + MIME::Types.add(@eruby) | |
65 | + end | |
66 | + | |
67 | + assert_equal(MIME::Types['application/x-eruby'], [@eruby]) | |
68 | + end | |
69 | + | |
70 | + def _test_class_add_type_variant | |
71 | + raise NotImplementedError, 'Need to write test_class_add_type_variant' | |
72 | + end | |
73 | + | |
74 | + def test_class_type_for | |
75 | + assert_equal(MIME::Types.type_for('xml').sort, [ MIME::Types['text/xml'], MIME::Types['application/xml'] ].sort) | |
76 | + assert_equal(MIME::Types.type_for('gif'), MIME::Types['image/gif']) | |
77 | + assert_nothing_raised do | |
78 | + MIME::Types['image/gif'][0].system = RUBY_PLATFORM | |
79 | + end | |
80 | + assert_equal(MIME::Types.type_for('gif', true), MIME::Types['image/gif']) | |
81 | + assert(MIME::Types.type_for('zzz').empty?) | |
82 | + end | |
83 | + | |
84 | + def test_class_of | |
85 | + assert_equal(MIME::Types.of('xml').sort, [ MIME::Types['text/xml'], MIME::Types['application/xml'] ].sort) | |
86 | + assert_equal(MIME::Types.of('gif'), MIME::Types['image/gif']) | |
87 | + assert_nothing_raised do | |
88 | + MIME::Types['image/gif'][0].system = RUBY_PLATFORM | |
89 | + end | |
90 | + assert_equal(MIME::Types.of('gif', true), MIME::Types['image/gif']) | |
91 | + assert(MIME::Types.of('zzz').empty?) | |
92 | + end | |
93 | + | |
94 | + def _test_add | |
95 | + raise NotImplementedError, 'Need to write test_add' | |
96 | + end | |
97 | + | |
98 | + def _test_add_type_variant | |
99 | + raise NotImplementedError, 'Need to write test_add_type_variant' | |
100 | + end | |
101 | + | |
102 | + def _test_data_version | |
103 | + raise NotImplementedError, 'Need to write test_data_version' | |
104 | + end | |
105 | + | |
106 | + def _test_index | |
107 | + raise NotImplementedError, 'Need to write test_index' | |
108 | + end | |
109 | + | |
110 | + def _test_index_extensions | |
111 | + raise NotImplementedError, 'Need to write test_index_extensions' | |
112 | + end | |
113 | + | |
114 | + def _test_of | |
115 | + raise NotImplementedError, 'Need to write test_of' | |
116 | + end | |
117 | + | |
118 | + def _test_type_for | |
119 | + raise NotImplementedError, 'Need to write test_type_for' | |
120 | + end | |
121 | + end | |
122 | +end | ... | ... |
... | ... | @@ -0,0 +1,56 @@ |
1 | +--- !ruby/object:Gem::Specification | |
2 | +name: xml-simple | |
3 | +version: !ruby/object:Gem::Version | |
4 | + version: 1.0.12 | |
5 | +platform: ruby | |
6 | +authors: | |
7 | +- Maik Schmidt | |
8 | +autorequire: | |
9 | +bindir: bin | |
10 | +cert_chain: [] | |
11 | + | |
12 | +date: 2009-02-26 00:00:00 -05:00 | |
13 | +default_executable: | |
14 | +dependencies: [] | |
15 | + | |
16 | +description: | |
17 | +email: contact@maik-schmidt.de | |
18 | +executables: [] | |
19 | + | |
20 | +extensions: [] | |
21 | + | |
22 | +extra_rdoc_files: [] | |
23 | + | |
24 | +files: | |
25 | +- lib/xmlsimple.rb | |
26 | +has_rdoc: true | |
27 | +homepage: http://xml-simple.rubyforge.org | |
28 | +licenses: [] | |
29 | + | |
30 | +post_install_message: | |
31 | +rdoc_options: [] | |
32 | + | |
33 | +require_paths: | |
34 | +- bin | |
35 | +- lib | |
36 | +required_ruby_version: !ruby/object:Gem::Requirement | |
37 | + requirements: | |
38 | + - - ">=" | |
39 | + - !ruby/object:Gem::Version | |
40 | + version: "0" | |
41 | + version: | |
42 | +required_rubygems_version: !ruby/object:Gem::Requirement | |
43 | + requirements: | |
44 | + - - ">=" | |
45 | + - !ruby/object:Gem::Version | |
46 | + version: "0" | |
47 | + version: | |
48 | +requirements: [] | |
49 | + | |
50 | +rubyforge_project: xml-simple | |
51 | +rubygems_version: 1.3.4 | |
52 | +signing_key: | |
53 | +specification_version: 2 | |
54 | +summary: A simple API for XML processing. | |
55 | +test_files: [] | |
56 | + | ... | ... |
... | ... | @@ -0,0 +1,1028 @@ |
1 | +# = XmlSimple | |
2 | +# | |
3 | +# Author:: Maik Schmidt <contact@maik-schmidt.de> | |
4 | +# Copyright:: Copyright (c) 2003-2009 Maik Schmidt | |
5 | +# License:: Distributes under the same terms as Ruby. | |
6 | +# | |
7 | +require 'rexml/document' | |
8 | +require 'stringio' | |
9 | + | |
10 | +# Easy API to maintain XML (especially configuration files). | |
11 | +class XmlSimple | |
12 | + include REXML | |
13 | + | |
14 | + @@VERSION = '1.0.12' | |
15 | + | |
16 | + # A simple cache for XML documents that were already transformed | |
17 | + # by xml_in. | |
18 | + class Cache | |
19 | + # Creates and initializes a new Cache object. | |
20 | + def initialize | |
21 | + @mem_share_cache = {} | |
22 | + @mem_copy_cache = {} | |
23 | + end | |
24 | + | |
25 | + # Saves a data structure into a file. | |
26 | + # | |
27 | + # data:: | |
28 | + # Data structure to be saved. | |
29 | + # filename:: | |
30 | + # Name of the file belonging to the data structure. | |
31 | + def save_storable(data, filename) | |
32 | + cache_file = get_cache_filename(filename) | |
33 | + File.open(cache_file, "w+") { |f| Marshal.dump(data, f) } | |
34 | + end | |
35 | + | |
36 | + # Restores a data structure from a file. If restoring the data | |
37 | + # structure failed for any reason, nil will be returned. | |
38 | + # | |
39 | + # filename:: | |
40 | + # Name of the file belonging to the data structure. | |
41 | + def restore_storable(filename) | |
42 | + cache_file = get_cache_filename(filename) | |
43 | + return nil unless File::exist?(cache_file) | |
44 | + return nil unless File::mtime(cache_file).to_i > File::mtime(filename).to_i | |
45 | + data = nil | |
46 | + File.open(cache_file) { |f| data = Marshal.load(f) } | |
47 | + data | |
48 | + end | |
49 | + | |
50 | + # Saves a data structure in a shared memory cache. | |
51 | + # | |
52 | + # data:: | |
53 | + # Data structure to be saved. | |
54 | + # filename:: | |
55 | + # Name of the file belonging to the data structure. | |
56 | + def save_mem_share(data, filename) | |
57 | + @mem_share_cache[filename] = [Time::now.to_i, data] | |
58 | + end | |
59 | + | |
60 | + # Restores a data structure from a shared memory cache. You | |
61 | + # should consider these elements as "read only". If restoring | |
62 | + # the data structure failed for any reason, nil will be | |
63 | + # returned. | |
64 | + # | |
65 | + # filename:: | |
66 | + # Name of the file belonging to the data structure. | |
67 | + def restore_mem_share(filename) | |
68 | + get_from_memory_cache(filename, @mem_share_cache) | |
69 | + end | |
70 | + | |
71 | + # Copies a data structure to a memory cache. | |
72 | + # | |
73 | + # data:: | |
74 | + # Data structure to be copied. | |
75 | + # filename:: | |
76 | + # Name of the file belonging to the data structure. | |
77 | + def save_mem_copy(data, filename) | |
78 | + @mem_share_cache[filename] = [Time::now.to_i, Marshal.dump(data)] | |
79 | + end | |
80 | + | |
81 | + # Restores a data structure from a memory cache. If restoring | |
82 | + # the data structure failed for any reason, nil will be | |
83 | + # returned. | |
84 | + # | |
85 | + # filename:: | |
86 | + # Name of the file belonging to the data structure. | |
87 | + def restore_mem_copy(filename) | |
88 | + data = get_from_memory_cache(filename, @mem_share_cache) | |
89 | + data = Marshal.load(data) unless data.nil? | |
90 | + data | |
91 | + end | |
92 | + | |
93 | + private | |
94 | + | |
95 | + # Returns the "cache filename" belonging to a filename, i.e. | |
96 | + # the extension '.xml' in the original filename will be replaced | |
97 | + # by '.stor'. If filename does not have this extension, '.stor' | |
98 | + # will be appended. | |
99 | + # | |
100 | + # filename:: | |
101 | + # Filename to get "cache filename" for. | |
102 | + def get_cache_filename(filename) | |
103 | + filename.sub(/(\.xml)?$/, '.stor') | |
104 | + end | |
105 | + | |
106 | + # Returns a cache entry from a memory cache belonging to a | |
107 | + # certain filename. If no entry could be found for any reason, | |
108 | + # nil will be returned. | |
109 | + # | |
110 | + # filename:: | |
111 | + # Name of the file the cache entry belongs to. | |
112 | + # cache:: | |
113 | + # Memory cache to get entry from. | |
114 | + def get_from_memory_cache(filename, cache) | |
115 | + return nil unless cache[filename] | |
116 | + return nil unless cache[filename][0] > File::mtime(filename).to_i | |
117 | + return cache[filename][1] | |
118 | + end | |
119 | + end | |
120 | + | |
121 | + # Create a "global" cache. | |
122 | + @@cache = Cache.new | |
123 | + | |
124 | + # Creates and intializes a new XmlSimple object. | |
125 | + # | |
126 | + # defaults:: | |
127 | + # Default values for options. | |
128 | + def initialize(defaults = nil) | |
129 | + unless defaults.nil? || defaults.instance_of?(Hash) | |
130 | + raise ArgumentError, "Options have to be a Hash." | |
131 | + end | |
132 | + @default_options = normalize_option_names(defaults, (KNOWN_OPTIONS['in'] + KNOWN_OPTIONS['out']).uniq) | |
133 | + @options = Hash.new | |
134 | + @_var_values = nil | |
135 | + end | |
136 | + | |
137 | + # Converts an XML document in the same way as the Perl module XML::Simple. | |
138 | + # | |
139 | + # string:: | |
140 | + # XML source. Could be one of the following: | |
141 | + # | |
142 | + # - nil: Tries to load and parse '<scriptname>.xml'. | |
143 | + # - filename: Tries to load and parse filename. | |
144 | + # - IO object: Reads from object until EOF is detected and parses result. | |
145 | + # - XML string: Parses string. | |
146 | + # | |
147 | + # options:: | |
148 | + # Options to be used. | |
149 | + def xml_in(string = nil, options = nil) | |
150 | + handle_options('in', options) | |
151 | + | |
152 | + # If no XML string or filename was supplied look for scriptname.xml. | |
153 | + if string.nil? | |
154 | + string = File::basename($0).dup | |
155 | + string.sub!(/\.[^.]+$/, '') | |
156 | + string += '.xml' | |
157 | + | |
158 | + directory = File::dirname($0) | |
159 | + @options['searchpath'].unshift(directory) unless directory.nil? | |
160 | + end | |
161 | + | |
162 | + if string.instance_of?(String) | |
163 | + if string =~ /<.*?>/m | |
164 | + @doc = parse(string) | |
165 | + elsif string == '-' | |
166 | + @doc = parse($stdin.read) | |
167 | + else | |
168 | + filename = find_xml_file(string, @options['searchpath']) | |
169 | + | |
170 | + if @options.has_key?('cache') | |
171 | + @options['cache'].each { |scheme| | |
172 | + case(scheme) | |
173 | + when 'storable' | |
174 | + content = @@cache.restore_storable(filename) | |
175 | + when 'mem_share' | |
176 | + content = @@cache.restore_mem_share(filename) | |
177 | + when 'mem_copy' | |
178 | + content = @@cache.restore_mem_copy(filename) | |
179 | + else | |
180 | + raise ArgumentError, "Unsupported caching scheme: <#{scheme}>." | |
181 | + end | |
182 | + return content if content | |
183 | + } | |
184 | + end | |
185 | + | |
186 | + @doc = load_xml_file(filename) | |
187 | + end | |
188 | + elsif string.kind_of?(IO) || string.kind_of?(StringIO) || string.kind_of?(Zlib::GzipReader) | |
189 | + @doc = parse(string.read) | |
190 | + else | |
191 | + raise ArgumentError, "Could not parse object of type: <#{string.type}>." | |
192 | + end | |
193 | + | |
194 | + result = collapse(@doc.root) | |
195 | + result = @options['keeproot'] ? merge({}, @doc.root.name, result) : result | |
196 | + put_into_cache(result, filename) | |
197 | + result | |
198 | + end | |
199 | + | |
200 | + # This is the functional version of the instance method xml_in. | |
201 | + def XmlSimple.xml_in(string = nil, options = nil) | |
202 | + xml_simple = XmlSimple.new | |
203 | + xml_simple.xml_in(string, options) | |
204 | + end | |
205 | + | |
206 | + # Converts a data structure into an XML document. | |
207 | + # | |
208 | + # ref:: | |
209 | + # Reference to data structure to be converted into XML. | |
210 | + # options:: | |
211 | + # Options to be used. | |
212 | + def xml_out(ref, options = nil) | |
213 | + handle_options('out', options) | |
214 | + if ref.instance_of?(Array) | |
215 | + ref = { @options['anonymoustag'] => ref } | |
216 | + end | |
217 | + | |
218 | + if @options['keeproot'] | |
219 | + keys = ref.keys | |
220 | + if keys.size == 1 | |
221 | + ref = ref[keys[0]] | |
222 | + @options['rootname'] = keys[0] | |
223 | + end | |
224 | + elsif @options['rootname'] == '' | |
225 | + if ref.instance_of?(Hash) | |
226 | + refsave = ref | |
227 | + ref = {} | |
228 | + refsave.each { |key, value| | |
229 | + if !scalar(value) | |
230 | + ref[key] = value | |
231 | + else | |
232 | + ref[key] = [ value.to_s ] | |
233 | + end | |
234 | + } | |
235 | + end | |
236 | + end | |
237 | + | |
238 | + @ancestors = [] | |
239 | + xml = value_to_xml(ref, @options['rootname'], '') | |
240 | + @ancestors = nil | |
241 | + | |
242 | + if @options['xmldeclaration'] | |
243 | + xml = @options['xmldeclaration'] + "\n" + xml | |
244 | + end | |
245 | + | |
246 | + if @options.has_key?('outputfile') | |
247 | + if @options['outputfile'].kind_of?(IO) | |
248 | + return @options['outputfile'].write(xml) | |
249 | + else | |
250 | + File.open(@options['outputfile'], "w") { |file| file.write(xml) } | |
251 | + end | |
252 | + end | |
253 | + xml | |
254 | + end | |
255 | + | |
256 | + # This is the functional version of the instance method xml_out. | |
257 | + def XmlSimple.xml_out(hash, options = nil) | |
258 | + xml_simple = XmlSimple.new | |
259 | + xml_simple.xml_out(hash, options) | |
260 | + end | |
261 | + | |
262 | + private | |
263 | + | |
264 | + # Declare options that are valid for xml_in and xml_out. | |
265 | + KNOWN_OPTIONS = { | |
266 | + 'in' => %w( | |
267 | + keyattr keeproot forcecontent contentkey noattr | |
268 | + searchpath forcearray suppressempty anonymoustag | |
269 | + cache grouptags normalisespace normalizespace | |
270 | + variables varattr keytosymbol attrprefix | |
271 | + ), | |
272 | + 'out' => %w( | |
273 | + keyattr keeproot contentkey noattr rootname | |
274 | + xmldeclaration outputfile noescape suppressempty | |
275 | + anonymoustag indent grouptags noindent attrprefix | |
276 | + ) | |
277 | + } | |
278 | + | |
279 | + # Define some reasonable defaults. | |
280 | + DEF_KEY_ATTRIBUTES = [] | |
281 | + DEF_ROOT_NAME = 'opt' | |
282 | + DEF_CONTENT_KEY = 'content' | |
283 | + DEF_XML_DECLARATION = "<?xml version='1.0' standalone='yes'?>" | |
284 | + DEF_ANONYMOUS_TAG = 'anon' | |
285 | + DEF_FORCE_ARRAY = true | |
286 | + DEF_INDENTATION = ' ' | |
287 | + DEF_KEY_TO_SYMBOL = false | |
288 | + | |
289 | + # Normalizes option names in a hash, i.e., turns all | |
290 | + # characters to lower case and removes all underscores. | |
291 | + # Additionally, this method checks, if an unknown option | |
292 | + # was used and raises an according exception. | |
293 | + # | |
294 | + # options:: | |
295 | + # Hash to be normalized. | |
296 | + # known_options:: | |
297 | + # List of known options. | |
298 | + def normalize_option_names(options, known_options) | |
299 | + return nil if options.nil? | |
300 | + result = Hash.new | |
301 | + options.each { |key, value| | |
302 | + lkey = key.downcase | |
303 | + lkey.gsub!(/_/, '') | |
304 | + if !known_options.member?(lkey) | |
305 | + raise ArgumentError, "Unrecognised option: #{lkey}." | |
306 | + end | |
307 | + result[lkey] = value | |
308 | + } | |
309 | + result | |
310 | + end | |
311 | + | |
312 | + # Merges a set of options with the default options. | |
313 | + # | |
314 | + # direction:: | |
315 | + # 'in': If options should be handled for xml_in. | |
316 | + # 'out': If options should be handled for xml_out. | |
317 | + # options:: | |
318 | + # Options to be merged with the default options. | |
319 | + def handle_options(direction, options) | |
320 | + @options = options || Hash.new | |
321 | + | |
322 | + raise ArgumentError, "Options must be a Hash!" unless @options.instance_of?(Hash) | |
323 | + | |
324 | + unless KNOWN_OPTIONS.has_key?(direction) | |
325 | + raise ArgumentError, "Unknown direction: <#{direction}>." | |
326 | + end | |
327 | + | |
328 | + known_options = KNOWN_OPTIONS[direction] | |
329 | + @options = normalize_option_names(@options, known_options) | |
330 | + | |
331 | + unless @default_options.nil? | |
332 | + known_options.each { |option| | |
333 | + unless @options.has_key?(option) | |
334 | + if @default_options.has_key?(option) | |
335 | + @options[option] = @default_options[option] | |
336 | + end | |
337 | + end | |
338 | + } | |
339 | + end | |
340 | + | |
341 | + unless @options.has_key?('noattr') | |
342 | + @options['noattr'] = false | |
343 | + end | |
344 | + | |
345 | + if @options.has_key?('rootname') | |
346 | + @options['rootname'] = '' if @options['rootname'].nil? | |
347 | + else | |
348 | + @options['rootname'] = DEF_ROOT_NAME | |
349 | + end | |
350 | + | |
351 | + if @options.has_key?('xmldeclaration') && @options['xmldeclaration'] == true | |
352 | + @options['xmldeclaration'] = DEF_XML_DECLARATION | |
353 | + end | |
354 | + | |
355 | + @options['keytosymbol'] = DEF_KEY_TO_SYMBOL unless @options.has_key?('keytosymbol') | |
356 | + | |
357 | + if @options.has_key?('contentkey') | |
358 | + if @options['contentkey'] =~ /^-(.*)$/ | |
359 | + @options['contentkey'] = $1 | |
360 | + @options['collapseagain'] = true | |
361 | + end | |
362 | + else | |
363 | + @options['contentkey'] = DEF_CONTENT_KEY | |
364 | + end | |
365 | + | |
366 | + unless @options.has_key?('normalisespace') | |
367 | + @options['normalisespace'] = @options['normalizespace'] | |
368 | + end | |
369 | + @options['normalisespace'] = 0 if @options['normalisespace'].nil? | |
370 | + | |
371 | + if @options.has_key?('searchpath') | |
372 | + unless @options['searchpath'].instance_of?(Array) | |
373 | + @options['searchpath'] = [ @options['searchpath'] ] | |
374 | + end | |
375 | + else | |
376 | + @options['searchpath'] = [] | |
377 | + end | |
378 | + | |
379 | + if @options.has_key?('cache') && scalar(@options['cache']) | |
380 | + @options['cache'] = [ @options['cache'] ] | |
381 | + end | |
382 | + | |
383 | + @options['anonymoustag'] = DEF_ANONYMOUS_TAG unless @options.has_key?('anonymoustag') | |
384 | + | |
385 | + if !@options.has_key?('indent') || @options['indent'].nil? | |
386 | + @options['indent'] = DEF_INDENTATION | |
387 | + end | |
388 | + | |
389 | + @options['indent'] = '' if @options.has_key?('noindent') | |
390 | + | |
391 | + # Special cleanup for 'keyattr' which could be an array or | |
392 | + # a hash or left to default to array. | |
393 | + if @options.has_key?('keyattr') | |
394 | + if !scalar(@options['keyattr']) | |
395 | + # Convert keyattr => { elem => '+attr' } | |
396 | + # to keyattr => { elem => ['attr', '+'] } | |
397 | + if @options['keyattr'].instance_of?(Hash) | |
398 | + @options['keyattr'].each { |key, value| | |
399 | + if value =~ /^([-+])?(.*)$/ | |
400 | + @options['keyattr'][key] = [$2, $1 ? $1 : ''] | |
401 | + end | |
402 | + } | |
403 | + elsif !@options['keyattr'].instance_of?(Array) | |
404 | + raise ArgumentError, "'keyattr' must be String, Hash, or Array!" | |
405 | + end | |
406 | + else | |
407 | + @options['keyattr'] = [ @options['keyattr'] ] | |
408 | + end | |
409 | + else | |
410 | + @options['keyattr'] = DEF_KEY_ATTRIBUTES | |
411 | + end | |
412 | + | |
413 | + if @options.has_key?('forcearray') | |
414 | + if @options['forcearray'].instance_of?(Regexp) | |
415 | + @options['forcearray'] = [ @options['forcearray'] ] | |
416 | + end | |
417 | + | |
418 | + if @options['forcearray'].instance_of?(Array) | |
419 | + force_list = @options['forcearray'] | |
420 | + unless force_list.empty? | |
421 | + @options['forcearray'] = {} | |
422 | + force_list.each { |tag| | |
423 | + if tag.instance_of?(Regexp) | |
424 | + unless @options['forcearray']['_regex'].instance_of?(Array) | |
425 | + @options['forcearray']['_regex'] = [] | |
426 | + end | |
427 | + @options['forcearray']['_regex'] << tag | |
428 | + else | |
429 | + @options['forcearray'][tag] = true | |
430 | + end | |
431 | + } | |
432 | + else | |
433 | + @options['forcearray'] = false | |
434 | + end | |
435 | + else | |
436 | + @options['forcearray'] = @options['forcearray'] ? true : false | |
437 | + end | |
438 | + else | |
439 | + @options['forcearray'] = DEF_FORCE_ARRAY | |
440 | + end | |
441 | + | |
442 | + if @options.has_key?('grouptags') && !@options['grouptags'].instance_of?(Hash) | |
443 | + raise ArgumentError, "Illegal value for 'GroupTags' option - expected a Hash." | |
444 | + end | |
445 | + | |
446 | + if @options.has_key?('variables') && !@options['variables'].instance_of?(Hash) | |
447 | + raise ArgumentError, "Illegal value for 'Variables' option - expected a Hash." | |
448 | + end | |
449 | + | |
450 | + if @options.has_key?('variables') | |
451 | + @_var_values = @options['variables'] | |
452 | + elsif @options.has_key?('varattr') | |
453 | + @_var_values = {} | |
454 | + end | |
455 | + end | |
456 | + | |
457 | + # Actually converts an XML document element into a data structure. | |
458 | + # | |
459 | + # element:: | |
460 | + # The document element to be collapsed. | |
461 | + def collapse(element) | |
462 | + result = @options['noattr'] ? {} : get_attributes(element) | |
463 | + | |
464 | + if @options['normalisespace'] == 2 | |
465 | + result.each { |k, v| result[k] = normalise_space(v) } | |
466 | + end | |
467 | + | |
468 | + if element.has_elements? | |
469 | + element.each_element { |child| | |
470 | + value = collapse(child) | |
471 | + if empty(value) && (element.attributes.empty? || @options['noattr']) | |
472 | + next if @options.has_key?('suppressempty') && @options['suppressempty'] == true | |
473 | + end | |
474 | + result = merge(result, child.name, value) | |
475 | + } | |
476 | + if has_mixed_content?(element) | |
477 | + # normalisespace? | |
478 | + content = element.texts.map { |x| x.to_s } | |
479 | + content = content[0] if content.size == 1 | |
480 | + result[@options['contentkey']] = content | |
481 | + end | |
482 | + elsif element.has_text? # i.e. it has only text. | |
483 | + return collapse_text_node(result, element) | |
484 | + end | |
485 | + | |
486 | + # Turn Arrays into Hashes if key fields present. | |
487 | + count = fold_arrays(result) | |
488 | + | |
489 | + # Disintermediate grouped tags. | |
490 | + if @options.has_key?('grouptags') | |
491 | + result.each { |key, value| | |
492 | + next unless (value.instance_of?(Hash) && (value.size == 1)) | |
493 | + child_key, child_value = value.to_a[0] | |
494 | + if @options['grouptags'][key] == child_key | |
495 | + result[key] = child_value | |
496 | + end | |
497 | + } | |
498 | + end | |
499 | + | |
500 | + # Fold Hashes containing a single anonymous Array up into just the Array. | |
501 | + if count == 1 | |
502 | + anonymoustag = @options['anonymoustag'] | |
503 | + if result.has_key?(anonymoustag) && result[anonymoustag].instance_of?(Array) | |
504 | + return result[anonymoustag] | |
505 | + end | |
506 | + end | |
507 | + | |
508 | + if result.empty? && @options.has_key?('suppressempty') | |
509 | + return @options['suppressempty'] == '' ? '' : nil | |
510 | + end | |
511 | + | |
512 | + result | |
513 | + end | |
514 | + | |
515 | + # Collapses a text node and merges it with an existing Hash, if | |
516 | + # possible. | |
517 | + # Thanks to Curtis Schofield for reporting a subtle bug. | |
518 | + # | |
519 | + # hash:: | |
520 | + # Hash to merge text node value with, if possible. | |
521 | + # element:: | |
522 | + # Text node to be collapsed. | |
523 | + def collapse_text_node(hash, element) | |
524 | + value = node_to_text(element) | |
525 | + if empty(value) && !element.has_attributes? | |
526 | + return {} | |
527 | + end | |
528 | + | |
529 | + if element.has_attributes? && !@options['noattr'] | |
530 | + return merge(hash, @options['contentkey'], value) | |
531 | + else | |
532 | + if @options['forcecontent'] | |
533 | + return merge(hash, @options['contentkey'], value) | |
534 | + else | |
535 | + return value | |
536 | + end | |
537 | + end | |
538 | + end | |
539 | + | |
540 | + # Folds all arrays in a Hash. | |
541 | + # | |
542 | + # hash:: | |
543 | + # Hash to be folded. | |
544 | + def fold_arrays(hash) | |
545 | + fold_amount = 0 | |
546 | + keyattr = @options['keyattr'] | |
547 | + if (keyattr.instance_of?(Array) || keyattr.instance_of?(Hash)) | |
548 | + hash.each { |key, value| | |
549 | + if value.instance_of?(Array) | |
550 | + if keyattr.instance_of?(Array) | |
551 | + hash[key] = fold_array(value) | |
552 | + else | |
553 | + hash[key] = fold_array_by_name(key, value) | |
554 | + end | |
555 | + fold_amount += 1 | |
556 | + end | |
557 | + } | |
558 | + end | |
559 | + fold_amount | |
560 | + end | |
561 | + | |
562 | + # Folds an Array to a Hash, if possible. Folding happens | |
563 | + # according to the content of keyattr, which has to be | |
564 | + # an array. | |
565 | + # | |
566 | + # array:: | |
567 | + # Array to be folded. | |
568 | + def fold_array(array) | |
569 | + hash = Hash.new | |
570 | + array.each { |x| | |
571 | + return array unless x.instance_of?(Hash) | |
572 | + key_matched = false | |
573 | + @options['keyattr'].each { |key| | |
574 | + if x.has_key?(key) | |
575 | + key_matched = true | |
576 | + value = x[key] | |
577 | + return array if value.instance_of?(Hash) || value.instance_of?(Array) | |
578 | + value = normalise_space(value) if @options['normalisespace'] == 1 | |
579 | + x.delete(key) | |
580 | + hash[value] = x | |
581 | + break | |
582 | + end | |
583 | + } | |
584 | + return array unless key_matched | |
585 | + } | |
586 | + hash = collapse_content(hash) if @options['collapseagain'] | |
587 | + hash | |
588 | + end | |
589 | + | |
590 | + # Folds an Array to a Hash, if possible. Folding happens | |
591 | + # according to the content of keyattr, which has to be | |
592 | + # a Hash. | |
593 | + # | |
594 | + # name:: | |
595 | + # Name of the attribute to be folded upon. | |
596 | + # array:: | |
597 | + # Array to be folded. | |
598 | + def fold_array_by_name(name, array) | |
599 | + return array unless @options['keyattr'].has_key?(name) | |
600 | + key, flag = @options['keyattr'][name] | |
601 | + | |
602 | + hash = Hash.new | |
603 | + array.each { |x| | |
604 | + if x.instance_of?(Hash) && x.has_key?(key) | |
605 | + value = x[key] | |
606 | + return array if value.instance_of?(Hash) || value.instance_of?(Array) | |
607 | + value = normalise_space(value) if @options['normalisespace'] == 1 | |
608 | + hash[value] = x | |
609 | + hash[value]["-#{key}"] = hash[value][key] if flag == '-' | |
610 | + hash[value].delete(key) unless flag == '+' | |
611 | + else | |
612 | + $stderr.puts("Warning: <#{name}> element has no '#{key}' attribute.") | |
613 | + return array | |
614 | + end | |
615 | + } | |
616 | + hash = collapse_content(hash) if @options['collapseagain'] | |
617 | + hash | |
618 | + end | |
619 | + | |
620 | + # Tries to collapse a Hash even more ;-) | |
621 | + # | |
622 | + # hash:: | |
623 | + # Hash to be collapsed again. | |
624 | + def collapse_content(hash) | |
625 | + content_key = @options['contentkey'] | |
626 | + hash.each_value { |value| | |
627 | + return hash unless value.instance_of?(Hash) && value.size == 1 && value.has_key?(content_key) | |
628 | + hash.each_key { |key| hash[key] = hash[key][content_key] } | |
629 | + } | |
630 | + hash | |
631 | + end | |
632 | + | |
633 | + # Adds a new key/value pair to an existing Hash. If the key to be added | |
634 | + # does already exist and the existing value associated with key is not | |
635 | + # an Array, it will be converted into an Array. Then the new value is | |
636 | + # appended to that Array. | |
637 | + # | |
638 | + # hash:: | |
639 | + # Hash to add key/value pair to. | |
640 | + # key:: | |
641 | + # Key to be added. | |
642 | + # value:: | |
643 | + # Value to be associated with key. | |
644 | + def merge(hash, key, value) | |
645 | + if value.instance_of?(String) | |
646 | + value = normalise_space(value) if @options['normalisespace'] == 2 | |
647 | + | |
648 | + # do variable substitutions | |
649 | + unless @_var_values.nil? || @_var_values.empty? | |
650 | + value.gsub!(/\$\{(\w+)\}/) { |x| get_var($1) } | |
651 | + end | |
652 | + | |
653 | + # look for variable definitions | |
654 | + if @options.has_key?('varattr') | |
655 | + varattr = @options['varattr'] | |
656 | + if hash.has_key?(varattr) | |
657 | + set_var(hash[varattr], value) | |
658 | + end | |
659 | + end | |
660 | + end | |
661 | + | |
662 | + #patch for converting keys to symbols | |
663 | + if @options.has_key?('keytosymbol') | |
664 | + if @options['keytosymbol'] == true | |
665 | + key = key.to_s.downcase.to_sym | |
666 | + end | |
667 | + end | |
668 | + | |
669 | + if hash.has_key?(key) | |
670 | + if hash[key].instance_of?(Array) | |
671 | + hash[key] << value | |
672 | + else | |
673 | + hash[key] = [ hash[key], value ] | |
674 | + end | |
675 | + elsif value.instance_of?(Array) # Handle anonymous arrays. | |
676 | + hash[key] = [ value ] | |
677 | + else | |
678 | + if force_array?(key) | |
679 | + hash[key] = [ value ] | |
680 | + else | |
681 | + hash[key] = value | |
682 | + end | |
683 | + end | |
684 | + hash | |
685 | + end | |
686 | + | |
687 | + # Checks, if the 'forcearray' option has to be used for | |
688 | + # a certain key. | |
689 | + def force_array?(key) | |
690 | + return false if key == @options['contentkey'] | |
691 | + return true if @options['forcearray'] == true | |
692 | + forcearray = @options['forcearray'] | |
693 | + if forcearray.instance_of?(Hash) | |
694 | + return true if forcearray.has_key?(key) | |
695 | + return false unless forcearray.has_key?('_regex') | |
696 | + forcearray['_regex'].each { |x| return true if key =~ x } | |
697 | + end | |
698 | + return false | |
699 | + end | |
700 | + | |
701 | + # Converts the attributes array of a document node into a Hash. | |
702 | + # Returns an empty Hash, if node has no attributes. | |
703 | + # | |
704 | + # node:: | |
705 | + # Document node to extract attributes from. | |
706 | + def get_attributes(node) | |
707 | + attributes = {} | |
708 | + if @options['attrprefix'] | |
709 | + node.attributes.each { |n,v| attributes["@" + n] = v } | |
710 | + else | |
711 | + node.attributes.each { |n,v| attributes[n] = v } | |
712 | + end | |
713 | + attributes | |
714 | + end | |
715 | + | |
716 | + # Determines, if a document element has mixed content. | |
717 | + # | |
718 | + # element:: | |
719 | + # Document element to be checked. | |
720 | + def has_mixed_content?(element) | |
721 | + if element.has_text? && element.has_elements? | |
722 | + return true if element.texts.join('') !~ /^\s*$/s | |
723 | + end | |
724 | + false | |
725 | + end | |
726 | + | |
727 | + # Called when a variable definition is encountered in the XML. | |
728 | + # A variable definition looks like | |
729 | + # <element attrname="name">value</element> | |
730 | + # where attrname matches the varattr setting. | |
731 | + def set_var(name, value) | |
732 | + @_var_values[name] = value | |
733 | + end | |
734 | + | |
735 | + # Called during variable substitution to get the value for the | |
736 | + # named variable. | |
737 | + def get_var(name) | |
738 | + if @_var_values.has_key?(name) | |
739 | + return @_var_values[name] | |
740 | + else | |
741 | + return "${#{name}}" | |
742 | + end | |
743 | + end | |
744 | + | |
745 | + # Recurses through a data structure building up and returning an | |
746 | + # XML representation of that structure as a string. | |
747 | + # | |
748 | + # ref:: | |
749 | + # Reference to the data structure to be encoded. | |
750 | + # name:: | |
751 | + # The XML tag name to be used for this item. | |
752 | + # indent:: | |
753 | + # A string of spaces for use as the current indent level. | |
754 | + def value_to_xml(ref, name, indent) | |
755 | + named = !name.nil? && name != '' | |
756 | + nl = @options.has_key?('noindent') ? '' : "\n" | |
757 | + | |
758 | + if !scalar(ref) | |
759 | + if @ancestors.member?(ref) | |
760 | + raise ArgumentError, "Circular data structures not supported!" | |
761 | + end | |
762 | + @ancestors << ref | |
763 | + else | |
764 | + if named | |
765 | + return [indent, '<', name, '>', @options['noescape'] ? ref.to_s : escape_value(ref.to_s), '</', name, '>', nl].join('') | |
766 | + else | |
767 | + return ref.to_s + nl | |
768 | + end | |
769 | + end | |
770 | + | |
771 | + # Unfold hash to array if possible. | |
772 | + if ref.instance_of?(Hash) && !ref.empty? && !@options['keyattr'].empty? && indent != '' | |
773 | + ref = hash_to_array(name, ref) | |
774 | + end | |
775 | + | |
776 | + result = [] | |
777 | + if ref.instance_of?(Hash) | |
778 | + # Reintermediate grouped values if applicable. | |
779 | + if @options.has_key?('grouptags') | |
780 | + ref.each { |key, value| | |
781 | + if @options['grouptags'].has_key?(key) | |
782 | + ref[key] = { @options['grouptags'][key] => value } | |
783 | + end | |
784 | + } | |
785 | + end | |
786 | + | |
787 | + nested = [] | |
788 | + text_content = nil | |
789 | + if named | |
790 | + result << indent << '<' << name | |
791 | + end | |
792 | + | |
793 | + if !ref.empty? | |
794 | + ref.each { |key, value| | |
795 | + next if !key.nil? && key[0, 1] == '-' | |
796 | + if value.nil? | |
797 | + unless @options.has_key?('suppressempty') && @options['suppressempty'].nil? | |
798 | + raise ArgumentError, "Use of uninitialized value!" | |
799 | + end | |
800 | + value = {} | |
801 | + end | |
802 | + | |
803 | + # Check for the '@' attribute prefix to allow separation of attributes and elements | |
804 | + if @options['noattr'] || | |
805 | + (@options['attrprefix'] && !(key =~ /^@(.*)/)) || | |
806 | + !scalar(value) | |
807 | + nested << value_to_xml(value, key, indent + @options['indent']) | |
808 | + else | |
809 | + value = value.to_s | |
810 | + value = escape_value(value) unless @options['noescape'] | |
811 | + if key == @options['contentkey'] | |
812 | + text_content = value | |
813 | + else | |
814 | + result << ' ' << ($1||key) << '="' << value << '"' | |
815 | + end | |
816 | + end | |
817 | + } | |
818 | + else | |
819 | + text_content = '' | |
820 | + end | |
821 | + | |
822 | + if !nested.empty? || !text_content.nil? | |
823 | + if named | |
824 | + result << '>' | |
825 | + if !text_content.nil? | |
826 | + result << text_content | |
827 | + nested[0].sub!(/^\s+/, '') if !nested.empty? | |
828 | + else | |
829 | + result << nl | |
830 | + end | |
831 | + if !nested.empty? | |
832 | + result << nested << indent | |
833 | + end | |
834 | + result << '</' << name << '>' << nl | |
835 | + else | |
836 | + result << nested | |
837 | + end | |
838 | + else | |
839 | + result << ' />' << nl | |
840 | + end | |
841 | + elsif ref.instance_of?(Array) | |
842 | + ref.each { |value| | |
843 | + if scalar(value) | |
844 | + result << indent << '<' << name << '>' | |
845 | + result << (@options['noescape'] ? value.to_s : escape_value(value.to_s)) | |
846 | + result << '</' << name << '>' << nl | |
847 | + elsif value.instance_of?(Hash) | |
848 | + result << value_to_xml(value, name, indent) | |
849 | + else | |
850 | + result << indent << '<' << name << '>' << nl | |
851 | + result << value_to_xml(value, @options['anonymoustag'], indent + @options['indent']) | |
852 | + result << indent << '</' << name << '>' << nl | |
853 | + end | |
854 | + } | |
855 | + else | |
856 | + # Probably, this is obsolete. | |
857 | + raise ArgumentError, "Can't encode a value of type: #{ref.type}." | |
858 | + end | |
859 | + @ancestors.pop if !scalar(ref) | |
860 | + result.join('') | |
861 | + end | |
862 | + | |
863 | + # Checks, if a certain value is a "scalar" value. Whatever | |
864 | + # that will be in Ruby ... ;-) | |
865 | + # | |
866 | + # value:: | |
867 | + # Value to be checked. | |
868 | + def scalar(value) | |
869 | + return false if value.instance_of?(Hash) || value.instance_of?(Array) | |
870 | + return true | |
871 | + end | |
872 | + | |
873 | + # Attempts to unfold a hash of hashes into an array of hashes. Returns | |
874 | + # a reference to th array on success or the original hash, if unfolding | |
875 | + # is not possible. | |
876 | + # | |
877 | + # parent:: | |
878 | + # | |
879 | + # hashref:: | |
880 | + # Reference to the hash to be unfolded. | |
881 | + def hash_to_array(parent, hashref) | |
882 | + arrayref = [] | |
883 | + hashref.each { |key, value| | |
884 | + return hashref unless value.instance_of?(Hash) | |
885 | + | |
886 | + if @options['keyattr'].instance_of?(Hash) | |
887 | + return hashref unless @options['keyattr'].has_key?(parent) | |
888 | + arrayref << { @options['keyattr'][parent][0] => key }.update(value) | |
889 | + else | |
890 | + arrayref << { @options['keyattr'][0] => key }.update(value) | |
891 | + end | |
892 | + } | |
893 | + arrayref | |
894 | + end | |
895 | + | |
896 | + # Replaces XML markup characters by their external entities. | |
897 | + # | |
898 | + # data:: | |
899 | + # The string to be escaped. | |
900 | + def escape_value(data) | |
901 | + Text::normalize(data) | |
902 | + end | |
903 | + | |
904 | + # Removes leading and trailing whitespace and sequences of | |
905 | + # whitespaces from a string. | |
906 | + # | |
907 | + # text:: | |
908 | + # String to be normalised. | |
909 | + def normalise_space(text) | |
910 | + text.strip.gsub(/\s\s+/, ' ') | |
911 | + end | |
912 | + | |
913 | + # Checks, if an object is nil, an empty String or an empty Hash. | |
914 | + # Thanks to Norbert Gawor for a bugfix. | |
915 | + # | |
916 | + # value:: | |
917 | + # Value to be checked for emptyness. | |
918 | + def empty(value) | |
919 | + case value | |
920 | + when Hash | |
921 | + return value.empty? | |
922 | + when String | |
923 | + return value !~ /\S/m | |
924 | + else | |
925 | + return value.nil? | |
926 | + end | |
927 | + end | |
928 | + | |
929 | + # Converts a document node into a String. | |
930 | + # If the node could not be converted into a String | |
931 | + # for any reason, default will be returned. | |
932 | + # | |
933 | + # node:: | |
934 | + # Document node to be converted. | |
935 | + # default:: | |
936 | + # Value to be returned, if node could not be converted. | |
937 | + def node_to_text(node, default = nil) | |
938 | + if node.instance_of?(REXML::Element) | |
939 | + node.texts.map { |t| t.value }.join('') | |
940 | + elsif node.instance_of?(REXML::Attribute) | |
941 | + node.value.nil? ? default : node.value.strip | |
942 | + elsif node.instance_of?(REXML::Text) | |
943 | + node.value.strip | |
944 | + else | |
945 | + default | |
946 | + end | |
947 | + end | |
948 | + | |
949 | + # Parses an XML string and returns the according document. | |
950 | + # | |
951 | + # xml_string:: | |
952 | + # XML string to be parsed. | |
953 | + # | |
954 | + # The following exception may be raised: | |
955 | + # | |
956 | + # REXML::ParseException:: | |
957 | + # If the specified file is not wellformed. | |
958 | + def parse(xml_string) | |
959 | + Document.new(xml_string) | |
960 | + end | |
961 | + | |
962 | + # Searches in a list of paths for a certain file. Returns | |
963 | + # the full path to the file, if it could be found. Otherwise, | |
964 | + # an exception will be raised. | |
965 | + # | |
966 | + # filename:: | |
967 | + # Name of the file to search for. | |
968 | + # searchpath:: | |
969 | + # List of paths to search in. | |
970 | + def find_xml_file(file, searchpath) | |
971 | + filename = File::basename(file) | |
972 | + | |
973 | + if filename != file | |
974 | + return file if File::file?(file) | |
975 | + else | |
976 | + searchpath.each { |path| | |
977 | + full_path = File::join(path, filename) | |
978 | + return full_path if File::file?(full_path) | |
979 | + } | |
980 | + end | |
981 | + | |
982 | + if searchpath.empty? | |
983 | + return file if File::file?(file) | |
984 | + raise ArgumentError, "File does not exist: #{file}." | |
985 | + end | |
986 | + raise ArgumentError, "Could not find <#{filename}> in <#{searchpath.join(':')}>" | |
987 | + end | |
988 | + | |
989 | + # Loads and parses an XML configuration file. | |
990 | + # | |
991 | + # filename:: | |
992 | + # Name of the configuration file to be loaded. | |
993 | + # | |
994 | + # The following exceptions may be raised: | |
995 | + # | |
996 | + # Errno::ENOENT:: | |
997 | + # If the specified file does not exist. | |
998 | + # REXML::ParseException:: | |
999 | + # If the specified file is not wellformed. | |
1000 | + def load_xml_file(filename) | |
1001 | + parse(IO::read(filename)) | |
1002 | + end | |
1003 | + | |
1004 | + # Caches the data belonging to a certain file. | |
1005 | + # | |
1006 | + # data:: | |
1007 | + # Data to be cached. | |
1008 | + # filename:: | |
1009 | + # Name of file the data was read from. | |
1010 | + def put_into_cache(data, filename) | |
1011 | + if @options.has_key?('cache') | |
1012 | + @options['cache'].each { |scheme| | |
1013 | + case(scheme) | |
1014 | + when 'storable' | |
1015 | + @@cache.save_storable(data, filename) | |
1016 | + when 'mem_share' | |
1017 | + @@cache.save_mem_share(data, filename) | |
1018 | + when 'mem_copy' | |
1019 | + @@cache.save_mem_copy(data, filename) | |
1020 | + else | |
1021 | + raise ArgumentError, "Unsupported caching scheme: <#{scheme}>." | |
1022 | + end | |
1023 | + } | |
1024 | + end | |
1025 | + end | |
1026 | +end | |
1027 | + | |
1028 | +# vim:sw=2 | ... | ... |