rhc 0.96.9 → 0.97.17
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -0
- data/bin/rhc +6 -18
- data/bin/rhc-app +3 -3
- data/bin/rhc-chk +2 -2
- data/bin/rhc-create-app +2 -2
- data/bin/rhc-create-domain +5 -2
- data/bin/rhc-ctl-app +2 -2
- data/bin/rhc-ctl-domain +5 -2
- data/bin/rhc-domain +6 -3
- data/bin/rhc-domain-info +6 -3
- data/bin/rhc-port-forward +9 -2
- data/bin/rhc-snapshot +2 -2
- data/bin/rhc-sshkey +2 -2
- data/bin/rhc-tail-files +2 -2
- data/features/lib/rhc_helper/app.rb +1 -1
- data/features/lib/rhc_helper/commandify.rb +32 -3
- data/features/lib/rhc_helper/domain.rb +46 -20
- data/features/step_definitions/cartridge_steps.rb +3 -3
- data/features/step_definitions/client_steps.rb +3 -1
- data/features/step_definitions/domain_steps.rb +45 -0
- data/features/verify.feature +36 -0
- data/lib/rhc-common.rb +6 -8
- data/lib/rhc-rest.rb +11 -2
- data/lib/rhc-rest/application.rb +20 -8
- data/lib/rhc-rest/cartridge.rb +18 -6
- data/lib/rhc-rest/client.rb +13 -37
- data/lib/rhc-rest/domain.rb +12 -4
- data/lib/rhc-rest/exceptions/exceptions.rb +1 -1
- data/lib/rhc-rest/key.rb +2 -2
- data/lib/rhc-rest/user.rb +2 -2
- data/lib/rhc/cli.rb +2 -3
- data/lib/rhc/commands.rb +154 -4
- data/lib/rhc/commands/base.rb +49 -12
- data/lib/rhc/commands/domain.rb +142 -0
- data/lib/rhc/commands/server.rb +1 -0
- data/lib/rhc/commands/setup.rb +3 -10
- data/lib/rhc/config.rb +20 -18
- data/lib/rhc/exceptions.rb +20 -0
- data/lib/rhc/help_formatter.rb +3 -22
- data/lib/rhc/helpers.rb +36 -5
- data/lib/rhc/json.rb +44 -44
- data/lib/rhc/targz.rb +3 -3
- data/lib/rhc/usage_templates/command_help.erb +26 -0
- data/lib/rhc/usage_templates/help.erb +27 -0
- data/lib/rhc/vendor/zliby.rb +563 -563
- data/lib/rhc/version.rb +2 -2
- data/lib/rhc/wizard.rb +10 -5
- data/spec/coverage_helper.rb +0 -1
- data/spec/rest_spec_helper.rb +95 -0
- data/spec/rhc/cli_spec.rb +7 -2
- data/spec/rhc/command_spec.rb +59 -13
- data/spec/rhc/commands/domain_spec.rb +225 -0
- data/spec/rhc/config_spec.rb +4 -4
- data/spec/rhc/helpers_spec.rb +27 -1
- data/spec/rhc/rest_application_spec.rb +6 -0
- data/spec/rhc/rest_client_spec.rb +32 -32
- data/spec/rhc/rest_spec.rb +2 -2
- data/spec/rhc/wizard_spec.rb +11 -4
- data/spec/spec_helper.rb +9 -9
- metadata +314 -312
data/lib/rhc/commands/server.rb
CHANGED
@@ -2,6 +2,7 @@ require 'rhc/commands/base'
|
|
2
2
|
|
3
3
|
module RHC::Commands
|
4
4
|
class Server < Base
|
5
|
+
suppress_wizard
|
5
6
|
|
6
7
|
summary "Display information about the status of the OpenShift service."
|
7
8
|
description "Retrieves any open issues or notices about the operation of the OpenShift service and displays them in the order they were opened."
|
data/lib/rhc/commands/setup.rb
CHANGED
@@ -4,18 +4,11 @@ require 'rhc/config'
|
|
4
4
|
|
5
5
|
module RHC::Commands
|
6
6
|
class Setup < Base
|
7
|
-
|
7
|
+
suppress_wizard
|
8
8
|
|
9
|
+
summary "Runs the setup wizard to configure your OpenShift account."
|
9
10
|
def run
|
10
|
-
|
11
|
-
if args[0] == 'help'
|
12
|
-
say Commander::Runner.instance.help_formatter.render_command(@command)
|
13
|
-
return 0
|
14
|
-
end
|
15
|
-
|
16
|
-
w = RHC::RerunWizard.new(config.config_path)
|
17
|
-
# exit 0 on success 1 otherwise
|
18
|
-
w.run ? 0 : 1
|
11
|
+
RHC::RerunWizard.new(config).run ? 0 : 1
|
19
12
|
end
|
20
13
|
end
|
21
14
|
end
|
data/lib/rhc/config.rb
CHANGED
@@ -3,20 +3,11 @@ require 'rhc/core_ext'
|
|
3
3
|
|
4
4
|
module RHC
|
5
5
|
module Config
|
6
|
-
# FIXME: Config shouldn't really exit
|
7
|
-
# stub this out for now so we can test it
|
8
|
-
def self.exit(code)
|
9
|
-
# :nocov:
|
10
|
-
Kernel.exit(code)
|
11
|
-
# :nocov:
|
12
|
-
end
|
13
|
-
|
14
6
|
def self.read_config_files
|
15
7
|
@@global_config = RHC::Vendor::ParseConfig.new(@@global_config_path) if File.exists?(@@global_config_path)
|
16
8
|
@@local_config = RHC::Vendor::ParseConfig.new(File.expand_path(@@local_config_path)) if File.exists?(@@local_config_path)
|
17
9
|
rescue Errno::EACCES => e
|
18
|
-
|
19
|
-
exit 253
|
10
|
+
raise Errno::EACCES.new("Could not open config file: #{e.message}")
|
20
11
|
end
|
21
12
|
|
22
13
|
def self.set_defaults
|
@@ -95,6 +86,10 @@ module RHC
|
|
95
86
|
self[key]
|
96
87
|
end
|
97
88
|
|
89
|
+
def self.username
|
90
|
+
self['default_rhlogin']
|
91
|
+
end
|
92
|
+
|
98
93
|
# Public: configures the default user for this session
|
99
94
|
def self.config_user(username)
|
100
95
|
@@defaults.add('default_rhlogin', username)
|
@@ -113,14 +108,23 @@ module RHC
|
|
113
108
|
@@opts['password']
|
114
109
|
end
|
115
110
|
|
116
|
-
def self.
|
111
|
+
def self.noprompt(bool)
|
112
|
+
@@opts.add('noprompt', bool)
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.noprompt?
|
116
|
+
@@opts['noprompt']
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.set_local_config(confpath, must_exist=true)
|
117
120
|
begin
|
118
121
|
@@local_config_path = File.expand_path(confpath)
|
119
122
|
@@config_path = @@local_config_path if @@opts_config_path.nil?
|
120
123
|
@@local_config = RHC::Vendor::ParseConfig.new(@@local_config_path)
|
121
124
|
rescue Errno::EACCES => e
|
122
|
-
|
123
|
-
|
125
|
+
if must_exist
|
126
|
+
raise Errno::EACCES.new "Could not open config file: #{e.message}"
|
127
|
+
end
|
124
128
|
end
|
125
129
|
end
|
126
130
|
|
@@ -130,8 +134,7 @@ module RHC
|
|
130
134
|
@@config_path = @@opts_config_path
|
131
135
|
@@opts_config = RHC::Vendor::ParseConfig.new(@@opts_config_path) if File.exists?(@@opts_config_path)
|
132
136
|
rescue Errno::EACCES => e
|
133
|
-
|
134
|
-
exit 253
|
137
|
+
raise Errno::EACCES.new "Could not open config file: #{e.message}"
|
135
138
|
end
|
136
139
|
end
|
137
140
|
|
@@ -139,8 +142,7 @@ module RHC
|
|
139
142
|
unless opts["config"].nil?
|
140
143
|
opts_config_path = File.expand_path(opts["config"])
|
141
144
|
if !File.readable?(opts_config_path)
|
142
|
-
|
143
|
-
exit 253
|
145
|
+
raise Errno::EACCES.new "Could not open config file: #{@opts_config_path}"
|
144
146
|
else
|
145
147
|
set_opts_config(opts_config_path)
|
146
148
|
end
|
@@ -161,7 +163,7 @@ module RHC
|
|
161
163
|
|
162
164
|
# Public: convinience function to see if we should run the wizard
|
163
165
|
def self.should_run_wizard?
|
164
|
-
not (has_local_config? or has_opts_config?)
|
166
|
+
not (has_local_config? or has_opts_config? or noprompt?)
|
165
167
|
end
|
166
168
|
|
167
169
|
def self.should_run_ssh_wizard?
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rhc-rest/exceptions/exceptions'
|
2
|
+
module RHC
|
3
|
+
class DomainNotFoundException < Rhc::Rest::ResourceNotFoundException
|
4
|
+
def initialize(message="Domain not found")
|
5
|
+
super message, 127
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class ApplicationNotFoundException < Rhc::Rest::ResourceNotFoundException
|
10
|
+
def initialize(message="Application not found")
|
11
|
+
super message, 101
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class KeyNotFoundException < Rhc::Rest::ResourceNotFoundException
|
16
|
+
def initialize(message="SSHKey not found")
|
17
|
+
super message, 118
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/rhc/help_formatter.rb
CHANGED
@@ -1,28 +1,9 @@
|
|
1
1
|
require 'commander/help_formatters/base'
|
2
2
|
|
3
3
|
module RHC
|
4
|
-
class UsageHelpFormatter < Commander::HelpFormatter::
|
5
|
-
def
|
6
|
-
|
7
|
-
@runner.options.each { |o|
|
8
|
-
result += o[:switches].join('|')
|
9
|
-
result += "\t#{o[:description]}\n"
|
10
|
-
}
|
11
|
-
result
|
12
|
-
end
|
13
|
-
|
14
|
-
def render
|
15
|
-
# TODO: render the rhc usage when we move 100% to using Commander
|
16
|
-
result = "#{@runner.program(:name)} - #{@runner.program(:description)}\n\n"
|
17
|
-
result += global_options_output
|
18
|
-
result
|
19
|
-
end
|
20
|
-
|
21
|
-
def render_command command
|
22
|
-
result = ""
|
23
|
-
result = "Usage: #{@runner.program(:name)} #{command.name}\n"
|
24
|
-
result += "#{command.summary}\n\n"
|
25
|
-
result += global_options_output
|
4
|
+
class UsageHelpFormatter < Commander::HelpFormatter::Terminal
|
5
|
+
def template name
|
6
|
+
ERB.new(File.read(File.join(File.dirname(__FILE__), 'usage_templates', "#{name}.erb")), nil, '-')
|
26
7
|
end
|
27
8
|
end
|
28
9
|
|
data/lib/rhc/helpers.rb
CHANGED
@@ -8,8 +8,8 @@ module RHC
|
|
8
8
|
|
9
9
|
module Helpers
|
10
10
|
private
|
11
|
-
def self.global_option(
|
12
|
-
RHC::Commands.global_option
|
11
|
+
def self.global_option(switches, description)
|
12
|
+
RHC::Commands.global_option switches, description
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -56,13 +56,15 @@ module RHC
|
|
56
56
|
# Global config
|
57
57
|
#
|
58
58
|
|
59
|
-
global_option '
|
59
|
+
global_option ['--config FILE'], "Path of a different config file"
|
60
60
|
def config
|
61
61
|
raise "Operations requiring configuration must define a config accessor"
|
62
62
|
end
|
63
63
|
|
64
|
-
global_option '
|
65
|
-
global_option '-
|
64
|
+
global_option ['--noprompt'], "Bypass first run wizard"
|
65
|
+
global_option ['-l', '--rhlogin login'], "Red Hat login (RedHat Network or OpenShift)"
|
66
|
+
global_option ['-p', '--password password'], "Red Hat password"
|
67
|
+
global_option ['-d', '--debug'], "Turn on debugging"
|
66
68
|
|
67
69
|
def openshift_server
|
68
70
|
config.get_value('libra_server')
|
@@ -70,7 +72,23 @@ module RHC
|
|
70
72
|
def openshift_url
|
71
73
|
"https://#{openshift_server}"
|
72
74
|
end
|
75
|
+
def openshift_rest_node
|
76
|
+
"#{openshift_url}/broker/rest/api"
|
77
|
+
end
|
78
|
+
|
79
|
+
def rest_client
|
80
|
+
return @rest_client if @rest_client
|
81
|
+
|
82
|
+
username = config.username
|
83
|
+
unless username
|
84
|
+
username = ask "To connect to #{openshift_server} enter your OpenShift login (email or Red Hat login id): "
|
85
|
+
config.config_user(username)
|
86
|
+
end
|
87
|
+
|
88
|
+
password = RHC::Config.password || RHC::get_password
|
73
89
|
|
90
|
+
@rest_client = Rhc::Rest::Client.new(openshift_rest_node, username, password, @options.debug)
|
91
|
+
end
|
74
92
|
|
75
93
|
#
|
76
94
|
# Output helpers
|
@@ -181,6 +199,19 @@ module RHC
|
|
181
199
|
section(:top => 1, :bottom => 1, &block)
|
182
200
|
end
|
183
201
|
|
202
|
+
##
|
203
|
+
# results
|
204
|
+
#
|
205
|
+
# highline helper which creates a paragraph with a header
|
206
|
+
# to distinguish the final results of a command from other output
|
207
|
+
#
|
208
|
+
def results(&block)
|
209
|
+
paragraph do
|
210
|
+
say "RESULT:"
|
211
|
+
yield
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
184
215
|
# Platform helpers
|
185
216
|
def jruby? ; RUBY_PLATFORM =~ /java/i end
|
186
217
|
def windows? ; RUBY_PLATFORM =~ /win(32|dows|ce)|djgpp|(ms|cyg|bcc)win|mingw32/i end
|
data/lib/rhc/json.rb
CHANGED
@@ -2,50 +2,50 @@ require 'rhc/vendor/okjson'
|
|
2
2
|
|
3
3
|
module RHC
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
5
|
+
module Json
|
6
|
+
|
7
|
+
def self.decode(string, options={})
|
8
|
+
string = string.read if string.respond_to?(:read)
|
9
|
+
result = RHC::Vendor::OkJson.decode(string)
|
10
|
+
options[:symbolize_keys] ? symbolize_keys(result) : result
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.encode(object, options={})
|
14
|
+
RHC::Vendor::OkJson.valenc(stringify_keys(object))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.symbolize_keys(object)
|
18
|
+
modify_keys(object) do |key|
|
19
|
+
key.is_a?(String) ? key.to_sym : key
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.stringify_keys(object)
|
24
|
+
modify_keys(object) do |key|
|
25
|
+
key.is_a?(Symbol) ? key.to_s : key
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.modify_keys(object, &modifier)
|
30
|
+
case object
|
31
|
+
when Array
|
32
|
+
object.map do |value|
|
33
|
+
modify_keys(value, &modifier)
|
34
|
+
end
|
35
|
+
when Hash
|
36
|
+
object.inject({}) do |result, (key, value)|
|
37
|
+
new_key = modifier.call(key)
|
38
|
+
new_value = modify_keys(value, &modifier)
|
39
|
+
result.merge! new_key => new_value
|
40
|
+
end
|
41
|
+
else
|
42
|
+
object
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
class JsonError < ::StandardError; end
|
49
49
|
|
50
50
|
end
|
51
51
|
|
data/lib/rhc/targz.rb
CHANGED
@@ -7,7 +7,7 @@ TAR_BIN = File.executable?('/usr/bin/gnutar') ? '/usr/bin/gnutar' : 'tar'
|
|
7
7
|
|
8
8
|
module RHC
|
9
9
|
|
10
|
-
|
10
|
+
module TarGz
|
11
11
|
|
12
12
|
def self.contains(filename, search, force_ruby=false)
|
13
13
|
|
@@ -30,12 +30,12 @@ module RHC
|
|
30
30
|
return false
|
31
31
|
end
|
32
32
|
else
|
33
|
-
`#{TAR_BIN} --wildcards -tf #{filename} '#{search.to_s}'`
|
33
|
+
`#{TAR_BIN} --wildcards -tf #{filename} '#{search.to_s}' 2> /dev/null`
|
34
34
|
contains = $?.exitstatus == 0
|
35
35
|
end
|
36
36
|
contains
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
end
|
40
40
|
|
41
41
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Usage: rhc <%= @command.name %> <%= @command.syntax %>
|
2
|
+
<%= @command.description || @command.summary || 'No description.' %>
|
3
|
+
<% unless @actions.nil? or @actions.empty? -%>
|
4
|
+
|
5
|
+
List of Actions
|
6
|
+
<% for action in @actions -%>
|
7
|
+
<%= "%-18s %s\n" % [action[:name], action[:summary]] -%>
|
8
|
+
<% end -%>
|
9
|
+
<% end -%>
|
10
|
+
<% unless @command.options.nil? or @command.options.empty? -%>
|
11
|
+
|
12
|
+
Options for <%= @command.name %>
|
13
|
+
<% for option in @command.options -%>
|
14
|
+
<%= "%-25s %s\n" % [option[:switches].join('|'), option[:description]] -%>
|
15
|
+
<% end -%>
|
16
|
+
<% end -%>
|
17
|
+
|
18
|
+
Global Options
|
19
|
+
<% for option in @global_options -%>
|
20
|
+
<%= "%-25s %s\n" % [option[:switches].join('|'), option[:description]] -%>
|
21
|
+
<% end -%>
|
22
|
+
<%#-
|
23
|
+
Other Attrs we may wish to use:
|
24
|
+
|
25
|
+
* @examples - for description, command in @examples
|
26
|
+
-%>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Usage: <%= program :name %> (<resource> | --help) [<action>] [<args>]
|
2
|
+
<%= program :description %>
|
3
|
+
|
4
|
+
List of Resources
|
5
|
+
<%# remove these as they are added to commander%>
|
6
|
+
app Manage applications within the rhcloud account.
|
7
|
+
sshkey Manage multiple keys for the registered rhcloud user.
|
8
|
+
port-forward Forward remote ports to the workstation
|
9
|
+
<% for name, command in @commands.sort -%>
|
10
|
+
<%- unless alias? name or name == "help" or name.include?(" ") -%> <%="%-18s %s\n" % [command.name, command.summary || command.description] %><%- end -%>
|
11
|
+
<%- end -%>
|
12
|
+
|
13
|
+
Global Options
|
14
|
+
<%- unless @options.nil? or @options.empty? -%>
|
15
|
+
<% for option in @options -%>
|
16
|
+
<%= "%-25s %s\n" % [option[:switches].join('|'), option[:description]] -%>
|
17
|
+
<% end -%>
|
18
|
+
<%- end -%>
|
19
|
+
|
20
|
+
See '<%= program :name %> <resource> --help' for more applicable commands and arguments on a specific resource.
|
21
|
+
<% if program :help -%>
|
22
|
+
<% for title, body in program(:help) %>
|
23
|
+
<%= $terminal.color title.to_s.upcase, :bold %>:
|
24
|
+
|
25
|
+
<%= body %>
|
26
|
+
<% end -%>
|
27
|
+
<% end -%>
|
data/lib/rhc/vendor/zliby.rb
CHANGED
@@ -5,7 +5,7 @@ module Vendor
|
|
5
5
|
module Zlib
|
6
6
|
|
7
7
|
ZLIBY_VERSION = "0.0.5"
|
8
|
-
ZLIB_VERSION = "1.2.3"
|
8
|
+
ZLIB_VERSION = "1.2.3"
|
9
9
|
VERSION = "0.6.0" #For compatibility with Ruby-core Zlib
|
10
10
|
MAXBITS = 15
|
11
11
|
MAXLCODES = 286
|
@@ -16,597 +16,597 @@ MAX_WBITS = 15
|
|
16
16
|
Z_DEFLATED = 8
|
17
17
|
|
18
18
|
def self.adler32 string="", adler=1
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
19
|
+
if adler > (2**128) - 1 then raise RangeError.new end
|
20
|
+
accum1 = adler & 0xffff
|
21
|
+
accum2 = (adler >> 16) & 0xffff
|
22
|
+
|
23
|
+
len = string.length
|
24
|
+
x = -1
|
25
|
+
while len > 0
|
26
|
+
tlen = len > 5552 ? 5552 : len
|
27
|
+
len -= tlen
|
28
|
+
while tlen >0
|
29
|
+
x += 1
|
30
|
+
accum1 += string[x]
|
31
|
+
accum2 += accum1
|
32
|
+
tlen -= 1
|
33
|
+
end
|
34
|
+
accum1 %= 65521
|
35
|
+
accum2 %= 65521
|
36
|
+
end
|
37
|
+
accum2 << 16 | accum1
|
38
38
|
end
|
39
39
|
|
40
40
|
def self.crc_table
|
41
|
-
|
41
|
+
[0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995, 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648, 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990, 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145, 1258607687, 3524101629, 2768942443, 901097722, 1119000684, 3686517206, 2898065728, 853044451, 1172266101, 3705015759, 2882616665, 651767980, 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527, 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772, 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290, 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 3865271297, 1802195444, 476864866, 2238001368, 4066508878, 1812370925, 453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202, 4240017532, 1658658271, 366619977, 2362670323, 4224994405, 1303535960, 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467, 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048, 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054, 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443, 3233442989, 3988292384, 2596254646, 62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430, 2053790376, 3826175755, 2466906013, 167816743, 2097651377, 4027552580, 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143, 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732, 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850, 2936675148, 906185462, 1090812512, 3747672003, 2825379669, 829329135, 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109, 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954, 1555261956, 3268935591, 3050360625, 752459403, 1541320221, 2607071920, 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603, 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992, 534414190, 2176718541, 4139329115, 1873836001, 414664567, 2282248934, 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105, 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270, 936918000, 2847714899, 3736837829, 1202900863, 817233897, 3183342108, 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471, 3272380065, 1510334235, 755167117]
|
42
42
|
end
|
43
43
|
|
44
44
|
def self.crc32 string="", crc=0
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
if crc > 2**128 - 1 then raise RangeError.new end
|
46
|
+
crc = crc ^ 0xffffffff
|
47
|
+
string.each_byte do |byte|
|
48
|
+
index = (crc ^ byte) & 0xff
|
49
|
+
crc = (crc >> 8) ^ crc_table[index]
|
50
|
+
end
|
51
|
+
crc ^ 0xffffffff
|
52
52
|
end
|
53
53
|
|
54
54
|
|
55
55
|
class ZStream
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
public
|
56
|
+
|
57
|
+
def initialize
|
58
|
+
@input_buffer = []
|
59
|
+
@output_buffer = []
|
60
|
+
@out_pos = -1
|
61
|
+
@in_pos = -1
|
62
|
+
@bit_bucket = 0
|
63
|
+
@bit_count = 0
|
64
|
+
|
65
|
+
end
|
66
|
+
#Returns the adler-32 checksum of the input data.
|
67
|
+
def adler
|
68
|
+
end
|
69
|
+
|
70
|
+
#Returns the number of bytes read. Normally 0 since all bytes are read at once.
|
71
|
+
def avail_in
|
72
|
+
@input_buffer.length - @in_pos
|
73
|
+
end
|
74
|
+
|
75
|
+
#Returns number of free bytes in the output buffer. As the output buffer is self expanding this normally returns 0.
|
76
|
+
def avail_out
|
77
|
+
@output_buffer.length - @out_pos
|
78
|
+
end
|
79
|
+
|
80
|
+
#Allocates size bytes in output buffer. If size < avail_out it truncates the buffer.
|
81
|
+
def avail_out= size
|
82
|
+
size.times do
|
83
|
+
if size > avail_out
|
84
|
+
@output_buffer.push nil
|
85
|
+
else
|
86
|
+
@output_buffer.pop
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
#Closes stream. Further operations will raise Zlib::StreamError
|
92
|
+
def close
|
93
|
+
@closed = true
|
94
|
+
end
|
95
|
+
|
96
|
+
#True if stream closed, otherwise False.
|
97
|
+
def closed?
|
98
|
+
@closed
|
99
|
+
end
|
100
|
+
|
101
|
+
#Best guess of input data, one of Zlib::BINARY, Zlib::ASCII, or Zlib::UNKNOWN
|
102
|
+
def data_type
|
103
|
+
end
|
104
|
+
|
105
|
+
#See close
|
106
|
+
def end
|
107
|
+
close
|
108
|
+
end
|
109
|
+
|
110
|
+
#See closed?
|
111
|
+
def ended?
|
112
|
+
closed?
|
113
|
+
end
|
114
|
+
|
115
|
+
#Finishes the stream, flushes output buffer, implemented by child classes
|
116
|
+
def finish
|
117
|
+
close
|
118
|
+
end
|
119
|
+
|
120
|
+
#True if stream is finished, otherwise False
|
121
|
+
def finished?
|
122
|
+
if @finished.nil? then
|
123
|
+
false
|
124
|
+
else
|
125
|
+
@finished
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
#Flushes input buffer and returns the data therein.
|
130
|
+
def flush_next_in
|
131
|
+
@in_pos = @input_buffer.length
|
132
|
+
@finished = true
|
133
|
+
ret = @input_buffer.pack("c*")
|
134
|
+
@input_buffer = []
|
135
|
+
ret
|
136
|
+
end
|
137
|
+
|
138
|
+
#Flushes the output buffer and returns all the data
|
139
|
+
def flush_next_out
|
140
|
+
@out_pos = @output_buffer.length
|
141
|
+
@finished = true
|
142
|
+
ret = @output_buffer.pack("c*")
|
143
|
+
@output_buffer = []
|
144
|
+
ret
|
145
|
+
end
|
146
|
+
|
147
|
+
#Reset stream. Input and Output buffers are reset.
|
148
|
+
def reset
|
149
|
+
@out_pos = -1
|
150
|
+
@in_pos = -1
|
151
|
+
@input_buffer = []
|
152
|
+
@output_buffer = []
|
153
|
+
end
|
154
|
+
|
155
|
+
#See finished.
|
156
|
+
def stream_end?
|
157
|
+
finished?
|
158
|
+
end
|
159
|
+
|
160
|
+
#Size of input buffer.
|
161
|
+
def total_in
|
162
|
+
@input_buffer.length
|
163
|
+
end
|
164
|
+
|
165
|
+
#Size of output buffer.
|
166
|
+
def total_out
|
167
|
+
@output_buffer.length
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
#returns need bits from the input buffer
|
172
|
+
# == Format Notes
|
173
|
+
# bits are stored LSB to MSB
|
174
|
+
def get_bits need
|
175
|
+
val = @bit_bucket
|
176
|
+
while @bit_count < need
|
177
|
+
val |= (@input_buffer[@in_pos+=1] << @bit_count)
|
178
|
+
@bit_count += 8
|
179
|
+
end
|
180
|
+
|
181
|
+
@bit_bucket = val >> need
|
182
|
+
@bit_count -= need
|
183
|
+
val & ((1 << need) - 1)
|
184
|
+
end
|
185
|
+
public
|
186
186
|
end
|
187
187
|
|
188
188
|
#== DEFLATE Decompression
|
189
189
|
#Implements decompression of a RFC-1951[ftp://ftp.rfc-editor.org/in-notes/rfc1951.txt] compatible stream.
|
190
190
|
class Inflate < ZStream
|
191
191
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
192
|
+
def initialize window_bits=MAX_WBITS
|
193
|
+
@w_bits = window_bits
|
194
|
+
if @w_bits < 0 then
|
195
|
+
@rawdeflate = true
|
196
|
+
@w_bits *= -1
|
197
|
+
end
|
198
|
+
super()
|
199
|
+
@zstring = ""
|
200
|
+
end
|
201
|
+
|
202
|
+
#Appends data to the input stream
|
203
|
+
def <<(string)
|
204
|
+
@zstring << string
|
205
|
+
inflate
|
206
|
+
end
|
207
|
+
|
208
|
+
#Sets the inflate dictionary
|
209
|
+
def set_dictionary string
|
210
|
+
@dict = string
|
211
|
+
reset
|
212
|
+
end
|
213
|
+
|
214
|
+
#==Example
|
215
|
+
# f = File.open "example.z"
|
216
|
+
# i = Inflate.new
|
217
|
+
# i.inflate f.read
|
218
|
+
def inflate zstring=nil
|
219
|
+
@zstring = zstring unless zstring.nil?
|
220
|
+
#We can't use unpack, IronRuby doesn't have it yet.
|
221
|
+
@zstring.each_byte {|b| @input_buffer << b}
|
222
|
+
|
223
|
+
unless @rawdeflate then
|
224
|
+
|
225
|
+
compression_method_and_flags = @input_buffer[@in_pos+=1]
|
226
|
+
flags = @input_buffer[@in_pos+=1]
|
227
|
+
|
228
|
+
#CMF and FLG, when viewed as a 16-bit unsigned integer stored inMSB order (CMF*256 + FLG), is a multiple of 31
|
229
|
+
if ((compression_method_and_flags << 0x08) + flags) % 31 != 0 then raise Zlib::DataError.new("incorrect header check") end
|
230
|
+
|
231
|
+
#CM = 8 denotes the "deflate" compression method with a window size up to 32K. (RFC's only specify CM 8)
|
232
|
+
compression_method = compression_method_and_flags & 0x0F
|
233
|
+
|
234
|
+
if compression_method != Z_DEFLATED then raise Zlib::DataError.new("unknown compression method") end
|
235
|
+
|
236
|
+
#For CM = 8, CINFO is the base-2 logarithm of the LZ77 window size,minus eight (CINFO=7 indicates a 32K window size)
|
237
|
+
compression_info = compression_method_and_flags >> 0x04
|
238
|
+
|
239
|
+
if (compression_info + 8) > @w_bits then raise Zlib::DataError.new("invalid window size") end
|
240
|
+
|
241
|
+
preset_dictionary_flag = ((flags & 0x20) >> 0x05) == 1
|
242
|
+
compression_level = (flags & 0xC0) >> 0x06
|
243
|
+
|
244
|
+
if preset_dictionary_flag and @dict.nil? then raise Zlib::NeedDict.new "Preset dictionary needed!" end
|
245
|
+
|
246
|
+
#TODO: Add Preset dictionary support
|
247
|
+
if preset_dictionary_flag then
|
248
|
+
@dict_crc = @input_buffer[@in_pos+=1] << 24 | @input_buffer[@in_pos+=1] << 16 | @input_buffer[@in_pos+=1] << 8 | @input_buffer[@in_pos+=1]
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
252
|
+
last_block = false
|
253
|
+
#Begin processing DEFLATE stream
|
254
|
+
until last_block
|
255
|
+
last_block = (get_bits(1) == 1)
|
256
|
+
block_type = get_bits(2)
|
257
|
+
case block_type
|
258
|
+
when 0 then no_compression
|
259
|
+
when 1 then fixed_codes
|
260
|
+
when 2 then dynamic_codes
|
261
|
+
when 3 then raise Zlib::DataError.new("invalid block type")
|
262
|
+
end
|
263
|
+
end
|
264
|
+
finish
|
265
|
+
end
|
266
|
+
|
267
|
+
#Finishes inflating and flushes the buffer
|
268
|
+
def finish
|
269
|
+
output = ""
|
270
|
+
inflate unless @output_buffer.length > 0
|
271
|
+
@output_buffer.each {|c| output << c }
|
272
|
+
super
|
273
|
+
output
|
274
|
+
end
|
275
|
+
|
276
|
+
private
|
277
|
+
|
278
|
+
def no_compression
|
279
|
+
@bit_bucket = 0
|
280
|
+
@bit_count = 0
|
281
|
+
if @in_pos + 4 > @input_buffer.length then raise Zlib::DataError.new("not enough input to read length code") end
|
282
|
+
length = @input_buffer[@in_pos+=1] | (@input_buffer[@in_pos+=1] << 8)
|
283
|
+
|
284
|
+
if (~length & 0xff != @input_buffer[@in_pos+=1]) || (((~length >> 8) & 0xff) != @input_buffer[@in_pos+=1]) then raise Zlib::DataError.new("invalid stored block lengths") end
|
285
|
+
|
286
|
+
if @in_pos + length > @input_buffer.length then raise Zlib::DataError.new("ran out of input") end
|
287
|
+
|
288
|
+
|
289
|
+
length.times do
|
290
|
+
@output_buffer[@out_pos += 1] = @input_buffer[@in_pos += 1]
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
end
|
295
|
+
|
296
|
+
def fixed_codes
|
297
|
+
if @fixed_length_codes.nil? && @fixed_distance_codes.nil? then generate_huffmans end
|
298
|
+
codes @fixed_length_codes, @fixed_distance_codes
|
299
|
+
end
|
300
|
+
|
301
|
+
def dynamic_codes
|
302
|
+
|
303
|
+
order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]
|
304
|
+
nlen = get_bits(5) + 257
|
305
|
+
ndist = get_bits(5) + 1
|
306
|
+
ncode = get_bits(4) + 4
|
307
|
+
|
308
|
+
|
309
|
+
lengths=[]
|
310
|
+
dynamic_length_codes = Zlib::Inflate::HuffmanTree.new
|
311
|
+
dynamic_distance_codes = Zlib::Inflate::HuffmanTree.new
|
312
|
+
|
313
|
+
if (nlen > MAXLCODES || ndist > MAXDCODES) then raise Zlib::DataError.new("too many length or distance codes") end
|
314
|
+
idx = 0
|
315
|
+
|
316
|
+
while idx < ncode
|
317
|
+
lengths[order[idx]] = get_bits(3)
|
318
|
+
idx += 1
|
319
|
+
end
|
320
|
+
while idx < 19
|
321
|
+
lengths[order[idx]] = 0
|
322
|
+
idx += 1
|
323
|
+
end
|
324
|
+
err = construct_tree dynamic_length_codes, lengths, 18
|
325
|
+
if err != 0 then raise Zlib::DataError.new("code lengths codes incomplete") end
|
326
|
+
|
327
|
+
idx = 0
|
328
|
+
while idx < (nlen + ndist)
|
329
|
+
symbol = decode(dynamic_length_codes)
|
330
|
+
if symbol < 16 then
|
331
|
+
lengths[idx] = symbol
|
332
|
+
idx += 1;
|
333
|
+
else
|
334
|
+
len = 0
|
335
|
+
if symbol == 16 then
|
336
|
+
if idx == 0 then raise Zlib::DataError.new("repeat lengths with no first length") end
|
337
|
+
len = lengths[idx - 1]
|
338
|
+
symbol = 3 + get_bits(2)
|
339
|
+
elsif symbol == 17 then
|
340
|
+
symbol = 3 + get_bits(3)
|
341
|
+
elsif symbol == 18 then
|
342
|
+
symbol = 11 + get_bits(7)
|
343
|
+
else
|
344
|
+
raise Zlib::DataError.new("invalid repeat length code")
|
345
|
+
end
|
346
|
+
if (idx + symbol) > (nlen + ndist) then raise Zlib::DataError.new("repeat more than specified lengths") end
|
347
|
+
until symbol == 0
|
348
|
+
lengths[idx] = len
|
349
|
+
idx+=1
|
350
|
+
symbol -= 1
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
err = construct_tree dynamic_length_codes, lengths, nlen-1
|
356
|
+
|
357
|
+
if err < 0 || (err > 0 && (nlen - dynamic_length_codes.count[0] != 1)) then raise Zlib::DataError.new("invalid literal/length code lengths") end
|
358
|
+
|
359
|
+
nlen.times { lengths.delete_at 0 } #We do this since we don't have pointer arithmetic in ruby
|
360
|
+
|
361
|
+
err = construct_tree dynamic_distance_codes, lengths, ndist-1
|
362
|
+
if err < 0 || (err > 0 && (ndist - dynamic_distance_codes.count[0] != 1)) then raise Zlib::DataError.new("invalid distance code lengths") end
|
363
|
+
|
364
|
+
codes dynamic_length_codes, dynamic_distance_codes
|
365
|
+
end
|
366
|
+
|
367
|
+
def generate_huffmans
|
368
|
+
|
369
|
+
lengths = []
|
370
|
+
|
371
|
+
#literal/length table
|
372
|
+
for idx in (000..143)
|
373
|
+
lengths[idx] = 8
|
374
|
+
end
|
375
|
+
for idx in (144..255)
|
376
|
+
lengths[idx] = 9
|
377
|
+
end
|
378
|
+
for idx in (256..279)
|
379
|
+
lengths[idx] = 7
|
380
|
+
end
|
381
|
+
for idx in (280..287)
|
382
|
+
lengths[idx] = 8
|
383
|
+
end
|
384
|
+
@fixed_length_codes = Zlib::Inflate::HuffmanTree.new
|
385
|
+
construct_tree @fixed_length_codes, lengths, 287
|
386
|
+
|
387
|
+
for idx in (00..29)
|
388
|
+
lengths[idx] = 5
|
389
|
+
end
|
390
|
+
@fixed_distance_codes = Zlib::Inflate::HuffmanTree.new
|
391
|
+
construct_tree @fixed_distance_codes, lengths, 29
|
392
|
+
|
393
|
+
end
|
394
|
+
|
395
|
+
def codes length_codes, distance_codes
|
396
|
+
lens = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258]
|
397
|
+
lext = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0]
|
398
|
+
dists = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577]
|
399
|
+
dext = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13]
|
400
|
+
|
401
|
+
symbol = 0
|
402
|
+
|
403
|
+
until symbol == 256
|
404
|
+
symbol = decode(length_codes)
|
405
|
+
if symbol < 0 then return symbol end
|
406
|
+
if symbol < 256 then @output_buffer[@out_pos+=1] = symbol end
|
407
|
+
if symbol > 256 then
|
408
|
+
symbol -= 257
|
409
|
+
if symbol >= 29 then raise Zlib::DataError.new("invalid literal/length or distance code in fixed or dynamic block") end
|
410
|
+
len = lens[symbol] + get_bits(lext[symbol])
|
411
|
+
symbol = decode(distance_codes)
|
412
|
+
if symbol < 0 then return symbol end
|
413
|
+
dist = dists[symbol] + get_bits(dext[symbol])
|
414
|
+
if dist > @output_buffer.length then raise Zlib::DataError.new("distance is too far back in fixed or dynamic block") end
|
415
|
+
while len > 0
|
416
|
+
@output_buffer[@out_pos+=1] = @output_buffer[@out_pos - dist]
|
417
|
+
len -= 1
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
return 0
|
422
|
+
end
|
423
|
+
|
424
|
+
def decode huffman_tree
|
425
|
+
code = 0
|
426
|
+
first = 0
|
427
|
+
index = 0
|
428
|
+
for len in (1..15)
|
429
|
+
code |= get_bits(1)
|
430
|
+
count = huffman_tree.count[len]
|
431
|
+
if code < (first + count) then return huffman_tree.symbol[index + (code - first)] end
|
432
|
+
index += count
|
433
|
+
first += count
|
434
|
+
first <<= 1
|
435
|
+
code <<= 1
|
436
|
+
end
|
437
|
+
-9
|
438
|
+
end
|
439
|
+
|
440
|
+
def construct_tree huffman_tree, lengths, n_symbols
|
441
|
+
offs = []
|
442
|
+
|
443
|
+
for len in (000..MAXBITS)
|
444
|
+
huffman_tree.count[len] = 0
|
445
|
+
end
|
446
|
+
|
447
|
+
for symbol in (000..n_symbols)
|
448
|
+
huffman_tree.count[lengths[symbol]] += 1
|
449
|
+
end
|
450
|
+
|
451
|
+
if huffman_tree.count[0] == n_symbols then return 0 end
|
452
|
+
|
453
|
+
left = 1
|
454
|
+
for len in (1..MAXBITS)
|
455
|
+
left <<= 1
|
456
|
+
left -= huffman_tree.count[len];
|
457
|
+
if left < 0 then return left end
|
458
|
+
end
|
459
|
+
|
460
|
+
offs[1] = 0
|
461
|
+
|
462
|
+
for len in (1..(MAXBITS-1))
|
463
|
+
offs[len+1] = offs[len] + huffman_tree.count[len]
|
464
|
+
end
|
465
|
+
|
466
|
+
for symbol in (0..n_symbols)
|
467
|
+
if lengths[symbol] != 0 then
|
468
|
+
huffman_tree.symbol[offs[lengths[symbol]]] = symbol
|
469
|
+
offs[lengths[symbol]] += 1
|
470
|
+
end
|
471
|
+
|
472
|
+
end
|
473
|
+
left
|
474
|
+
end
|
475
475
|
|
476
476
|
class HuffmanTree
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
477
|
+
attr_accessor :count, :symbol
|
478
|
+
def initialize
|
479
|
+
@count = []
|
480
|
+
@symbol = []
|
481
|
+
end
|
482
482
|
end
|
483
483
|
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
484
|
+
class << self
|
485
|
+
def inflate zstring
|
486
|
+
d = self.new
|
487
|
+
d.inflate zstring
|
488
|
+
end
|
489
|
+
end
|
490
490
|
|
491
491
|
end
|
492
492
|
|
493
493
|
|
494
494
|
class GzipFile
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
495
|
+
|
496
|
+
def initialize
|
497
|
+
@input_buffer = []
|
498
|
+
@output_buffer = []
|
499
|
+
@out_pos = -1
|
500
|
+
@in_pos = -1
|
501
|
+
end
|
502
|
+
|
503
|
+
def close
|
504
|
+
end
|
505
|
+
|
506
|
+
class Error < Exception
|
507
|
+
end
|
508
508
|
|
509
509
|
end
|
510
510
|
|
511
511
|
class GzipReader < GzipFile
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
512
|
+
OSES = ['FAT filesystem',
|
513
|
+
'Amiga',
|
514
|
+
'VMS (or OpenVMS)',
|
515
|
+
'Unix',
|
516
|
+
'VM/CMS',
|
517
|
+
'Atari TOS',
|
518
|
+
'HPFS fileystem (OS/2, NT)',
|
519
|
+
'Macintosh',
|
520
|
+
'Z-System',
|
521
|
+
'CP/M',
|
522
|
+
'TOPS-20',
|
523
|
+
'NTFS filesystem (NT)',
|
524
|
+
'QDOS',
|
525
|
+
'Acorn RISCOS',
|
526
|
+
'unknown']
|
527
|
+
|
528
|
+
def initialize io
|
529
|
+
|
530
|
+
#Add a helper method to check bits
|
531
|
+
::Fixnum.module_eval do
|
532
|
+
def isbitset? bit_to_check
|
533
|
+
if self & (2 ** bit_to_check) == (2 ** bit_to_check) then true else false end
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
super()
|
538
|
+
@io = io
|
539
|
+
io.read.each_byte {|b| @input_buffer << b}
|
540
|
+
if @input_buffer[@in_pos+=1] != 0x1f || @input_buffer[@in_pos+=1] != 0x8b then raise Zlib::GzipFile::Error.new("not in gzip format") end
|
541
|
+
if @input_buffer[@in_pos+=1] != 0x08 then raise Zlib::GzipFile::Error.new("unknown compression method") end
|
542
|
+
flg = @input_buffer[@in_pos+=1]
|
543
|
+
@ftext = flg.isbitset? 0
|
544
|
+
@fhcrc = flg.isbitset? 1
|
545
|
+
@fextra = flg.isbitset? 2
|
546
|
+
@fname = flg.isbitset? 3
|
547
|
+
@fcomment = flg.isbitset? 4
|
548
|
+
@mtime = Time.at(@input_buffer[@in_pos+=1] | (@input_buffer[@in_pos+=1] << 8) | (@input_buffer[@in_pos+=1] << 16) | (@input_buffer[@in_pos+=1] << 24))
|
549
|
+
@xfl = @input_buffer[@in_pos+=1]
|
550
|
+
@os = OSES[@input_buffer[@in_pos+=1]]
|
551
|
+
if @fextra then
|
552
|
+
@xlen = (@input_buffer[@in_pos+=1] | (@input_buffer[@in_pos+=1] << 8))
|
553
|
+
@xtra_field = []
|
554
|
+
@xlen.times {@xtra_field << @input_buffer[@in_pos+=1]}
|
555
|
+
end
|
556
|
+
if @fname then
|
557
|
+
@original_name = ""
|
558
|
+
until @original_name["\0"].nil? == false
|
559
|
+
@original_name.concat(@input_buffer[@in_pos+=1])
|
560
|
+
end
|
561
|
+
@original_name.chop!
|
562
|
+
end
|
563
|
+
if @fcomment then
|
564
|
+
@comment = ""
|
565
|
+
until @comment["\0"].nil? == false
|
566
|
+
@comment.concat(@input_buffer[@in_pos+=1])
|
567
|
+
end
|
568
|
+
@comment.chop!
|
569
|
+
end
|
570
|
+
if @fhcrc then
|
571
|
+
@header_crc = @input_buffer[@in_pos+=1] | (@input_buffer[@in_pos+=1] << 8)
|
572
|
+
end
|
573
|
+
@contents = ""
|
574
|
+
until @in_pos == @input_buffer.length-1
|
575
|
+
@contents.concat(@input_buffer[@in_pos+=1])
|
576
|
+
end
|
577
|
+
|
578
|
+
#we do raw deflate, no headers
|
579
|
+
@zstream = Zlib::Inflate.new -MAX_WBITS
|
580
|
+
@inflated = StringIO.new(@zstream.inflate @contents)
|
581
|
+
|
582
|
+
end
|
583
|
+
|
584
|
+
def read length=nil
|
585
|
+
@inflated.read length
|
586
|
+
end
|
587
|
+
|
588
|
+
def eof?
|
589
|
+
@inflated.eof?
|
590
|
+
end
|
591
|
+
|
592
|
+
def pos
|
593
|
+
@inflated.pos
|
594
|
+
end
|
595
|
+
|
596
|
+
def rewind
|
597
|
+
@inflated.rewind
|
598
|
+
@io.seek 0, IO::SEEK_SET
|
599
|
+
end
|
600
|
+
|
601
|
+
class << self
|
602
|
+
|
603
|
+
def open filename
|
604
|
+
io = File.open filename, 'rb'
|
605
|
+
gz = self.new io
|
606
|
+
if block_given? then yield gz else gz end
|
607
|
+
end
|
608
|
+
|
609
|
+
end
|
610
610
|
end
|
611
611
|
|
612
612
|
|