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,7 +20,9 @@ This will create a Rails 2.3.2 app with Heroku-recommended code: | ||
20 | * jQuery for Javascript | 20 | * jQuery for Javascript |
21 | * Clearance for authentication | 21 | * Clearance for authentication |
22 | * Cucumber, Shoulda, Factory Girl, & Mocha for testing | 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 | * Blitz for features, model, controller, & helper generators | 26 | * Blitz for features, model, controller, & helper generators |
25 | 27 | ||
26 | If you don't have all the necessary gems, they will be installed. | 28 | If you don't have all the necessary gems, they will be installed. |
@@ -0,0 +1,133 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 @@ | @@ -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 |