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.
Files changed (60) hide show
  1. data/README.md +1 -0
  2. data/bin/rhc +6 -18
  3. data/bin/rhc-app +3 -3
  4. data/bin/rhc-chk +2 -2
  5. data/bin/rhc-create-app +2 -2
  6. data/bin/rhc-create-domain +5 -2
  7. data/bin/rhc-ctl-app +2 -2
  8. data/bin/rhc-ctl-domain +5 -2
  9. data/bin/rhc-domain +6 -3
  10. data/bin/rhc-domain-info +6 -3
  11. data/bin/rhc-port-forward +9 -2
  12. data/bin/rhc-snapshot +2 -2
  13. data/bin/rhc-sshkey +2 -2
  14. data/bin/rhc-tail-files +2 -2
  15. data/features/lib/rhc_helper/app.rb +1 -1
  16. data/features/lib/rhc_helper/commandify.rb +32 -3
  17. data/features/lib/rhc_helper/domain.rb +46 -20
  18. data/features/step_definitions/cartridge_steps.rb +3 -3
  19. data/features/step_definitions/client_steps.rb +3 -1
  20. data/features/step_definitions/domain_steps.rb +45 -0
  21. data/features/verify.feature +36 -0
  22. data/lib/rhc-common.rb +6 -8
  23. data/lib/rhc-rest.rb +11 -2
  24. data/lib/rhc-rest/application.rb +20 -8
  25. data/lib/rhc-rest/cartridge.rb +18 -6
  26. data/lib/rhc-rest/client.rb +13 -37
  27. data/lib/rhc-rest/domain.rb +12 -4
  28. data/lib/rhc-rest/exceptions/exceptions.rb +1 -1
  29. data/lib/rhc-rest/key.rb +2 -2
  30. data/lib/rhc-rest/user.rb +2 -2
  31. data/lib/rhc/cli.rb +2 -3
  32. data/lib/rhc/commands.rb +154 -4
  33. data/lib/rhc/commands/base.rb +49 -12
  34. data/lib/rhc/commands/domain.rb +142 -0
  35. data/lib/rhc/commands/server.rb +1 -0
  36. data/lib/rhc/commands/setup.rb +3 -10
  37. data/lib/rhc/config.rb +20 -18
  38. data/lib/rhc/exceptions.rb +20 -0
  39. data/lib/rhc/help_formatter.rb +3 -22
  40. data/lib/rhc/helpers.rb +36 -5
  41. data/lib/rhc/json.rb +44 -44
  42. data/lib/rhc/targz.rb +3 -3
  43. data/lib/rhc/usage_templates/command_help.erb +26 -0
  44. data/lib/rhc/usage_templates/help.erb +27 -0
  45. data/lib/rhc/vendor/zliby.rb +563 -563
  46. data/lib/rhc/version.rb +2 -2
  47. data/lib/rhc/wizard.rb +10 -5
  48. data/spec/coverage_helper.rb +0 -1
  49. data/spec/rest_spec_helper.rb +95 -0
  50. data/spec/rhc/cli_spec.rb +7 -2
  51. data/spec/rhc/command_spec.rb +59 -13
  52. data/spec/rhc/commands/domain_spec.rb +225 -0
  53. data/spec/rhc/config_spec.rb +4 -4
  54. data/spec/rhc/helpers_spec.rb +27 -1
  55. data/spec/rhc/rest_application_spec.rb +6 -0
  56. data/spec/rhc/rest_client_spec.rb +32 -32
  57. data/spec/rhc/rest_spec.rb +2 -2
  58. data/spec/rhc/wizard_spec.rb +11 -4
  59. data/spec/spec_helper.rb +9 -9
  60. metadata +314 -312
@@ -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."
@@ -4,18 +4,11 @@ require 'rhc/config'
4
4
 
5
5
  module RHC::Commands
6
6
  class Setup < Base
7
- summary "Runs the setup wizard to configure your OpenShift account."
7
+ suppress_wizard
8
8
 
9
+ summary "Runs the setup wizard to configure your OpenShift account."
9
10
  def run
10
- # TODO: make help subcommand global
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
- say "Could not open config file: #{e.message}"
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.set_local_config(confpath)
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
- say "Could not open config file: #{e.message}"
123
- exit 253
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
- say "Could not open config file: #{e.message}"
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
- say "Could not open config file: #{@opts_config_path}"
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
@@ -1,28 +1,9 @@
1
1
  require 'commander/help_formatters/base'
2
2
 
3
3
  module RHC
4
- class UsageHelpFormatter < Commander::HelpFormatter::Base
5
- def global_options_output
6
- result = "Global Options:\n"
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(*args)
12
- RHC::Commands.global_option *args
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 '-c', '--config FILE', "Path of a different config file"
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 '-l', '--rhlogin login', "Red Hat login (RedHat Network or OpenShift)"
65
- global_option '-p', '--password password', "Red Hat password"
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
- 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
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
- module TarGz
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
- end
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 -%>
@@ -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
- 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
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
- [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]
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
- 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
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
- 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
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
- 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
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
- attr_accessor :count, :symbol
478
- def initialize
479
- @count = []
480
- @symbol = []
481
- end
477
+ attr_accessor :count, :symbol
478
+ def initialize
479
+ @count = []
480
+ @symbol = []
481
+ end
482
482
  end
483
483
 
484
- class << self
485
- def inflate zstring
486
- d = self.new
487
- d.inflate zstring
488
- end
489
- end
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
- 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
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
- 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
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