rhc 0.96.9 → 0.97.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|