rhc 0.96.9 → 0.97.17

Sign up to get free protection for your applications and to get access to all the features.
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