rex-text 0.1.0
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +52 -0
- data/Gemfile +4 -0
- data/LICENSE +27 -0
- data/README.md +32 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/rex/codepage.map +104 -0
- data/lib/rex/text.rb +195 -0
- data/lib/rex/text/badchars.rb +50 -0
- data/lib/rex/text/base32.rb +87 -0
- data/lib/rex/text/base64.rb +42 -0
- data/lib/rex/text/binary_manipulation.rb +117 -0
- data/lib/rex/text/block_api.rb +33 -0
- data/lib/rex/text/checksum.rb +39 -0
- data/lib/rex/text/compress.rb +105 -0
- data/lib/rex/text/ebcdic.rb +219 -0
- data/lib/rex/text/encode.rb +104 -0
- data/lib/rex/text/hash.rb +37 -0
- data/lib/rex/text/hex.rb +204 -0
- data/lib/rex/text/illegal_sequence.rb +6 -0
- data/lib/rex/text/lang.rb +156 -0
- data/lib/rex/text/pattern.rb +91 -0
- data/lib/rex/text/rand.rb +233 -0
- data/lib/rex/text/randomize.rb +125 -0
- data/lib/rex/text/silly.rb +59 -0
- data/lib/rex/text/unicode.rb +276 -0
- data/lib/rex/text/version.rb +5 -0
- data/rex-text.gemspec +24 -0
- metadata +195 -0
- metadata.gz.sig +3 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
module Rex
|
|
3
|
+
module Text
|
|
4
|
+
# We are re-opening the module to add these module methods.
|
|
5
|
+
# Breaking them up this way allows us to maintain a little higher
|
|
6
|
+
# degree of organisation and make it easier to find what you're looking for
|
|
7
|
+
# without hanging the underlying calls that we historically rely upon.
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Return the index of the first badchar in +data+, otherwise return
|
|
11
|
+
# nil if there wasn't any badchar occurences.
|
|
12
|
+
#
|
|
13
|
+
# @param data [String] The string to check for bad characters
|
|
14
|
+
# @param badchars [String] A list of characters considered to be bad
|
|
15
|
+
# @return [Fixnum] Index of the first bad character if any exist in +data+
|
|
16
|
+
# @return [nil] If +data+ contains no bad characters
|
|
17
|
+
def self.badchar_index(data, badchars = '')
|
|
18
|
+
badchars.unpack("C*").each { |badchar|
|
|
19
|
+
pos = data.index(badchar.chr)
|
|
20
|
+
return pos if pos
|
|
21
|
+
}
|
|
22
|
+
return nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# Removes bad characters from a string.
|
|
27
|
+
#
|
|
28
|
+
# Modifies +data+ in place
|
|
29
|
+
#
|
|
30
|
+
# @param data [#delete]
|
|
31
|
+
# @param badchars [String] A list of characters considered to be bad
|
|
32
|
+
def self.remove_badchars(data, badchars = '')
|
|
33
|
+
return data if badchars.length == 0
|
|
34
|
+
badchars_pat = badchars.unpack("C*").map{|c| "\\x%.2x" % c}.join
|
|
35
|
+
data.gsub!(/[#{badchars_pat}]/n, '')
|
|
36
|
+
data
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
# Returns all chars that are not in the supplied set
|
|
41
|
+
#
|
|
42
|
+
# @param keepers [String]
|
|
43
|
+
# @return [String] All characters not contained in +keepers+
|
|
44
|
+
def self.charset_exclude(keepers)
|
|
45
|
+
excluded_bytes = [*(0..255)] - keepers.unpack("C*")
|
|
46
|
+
excluded_bytes.pack("C*")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
module Rex
|
|
3
|
+
module Text
|
|
4
|
+
# We are re-opening the module to add these module methods.
|
|
5
|
+
# Breaking them up this way allows us to maintain a little higher
|
|
6
|
+
# degree of organisation and make it easier to find what you're looking for
|
|
7
|
+
# without hanging the underlying calls that we historically rely upon.
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Base32 code
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
# Based on --> https://github.com/stesla/base32
|
|
14
|
+
|
|
15
|
+
# Copyright (c) 2007-2011 Samuel Tesla
|
|
16
|
+
|
|
17
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
18
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
19
|
+
# in the Software without restriction, including without limitation the rights
|
|
20
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
21
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
22
|
+
# furnished to do so, subject to the following conditions:
|
|
23
|
+
|
|
24
|
+
# The above copyright notice and this permission notice shall be included in
|
|
25
|
+
# all copies or substantial portions of the Software.
|
|
26
|
+
|
|
27
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
28
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
29
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
30
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
31
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
32
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
33
|
+
# THE SOFTWARE.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# Base32 encoder
|
|
38
|
+
#
|
|
39
|
+
def self.b32encode(bytes_in)
|
|
40
|
+
n = (bytes_in.length * 8.0 / 5.0).ceil
|
|
41
|
+
p = n < 8 ? 5 - (bytes_in.length * 8) % 5 : 0
|
|
42
|
+
c = bytes_in.inject(0) {|m,o| (m << 8) + o} << p
|
|
43
|
+
[(0..n-1).to_a.reverse.collect {|i| Base32[(c >> i * 5) & 0x1f].chr},
|
|
44
|
+
("=" * (8-n))]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.encode_base32(str)
|
|
48
|
+
bytes = str.bytes
|
|
49
|
+
result = ''
|
|
50
|
+
size= 5
|
|
51
|
+
while bytes.any? do
|
|
52
|
+
bytes.each_slice(size) do |a|
|
|
53
|
+
bytes_out = b32encode(a).flatten.join
|
|
54
|
+
result << bytes_out
|
|
55
|
+
bytes = bytes.drop(size)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
return result
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
#
|
|
62
|
+
# Base32 decoder
|
|
63
|
+
#
|
|
64
|
+
def self.b32decode(bytes_in)
|
|
65
|
+
bytes = bytes_in.take_while {|c| c != 61} # strip padding
|
|
66
|
+
n = (bytes.length * 5.0 / 8.0).floor
|
|
67
|
+
p = bytes.length < 8 ? 5 - (n * 8) % 5 : 0
|
|
68
|
+
c = bytes.inject(0) {|m,o| (m << 5) + Base32.index(o.chr)} >> p
|
|
69
|
+
(0..n-1).to_a.reverse.collect {|i| ((c >> i * 8) & 0xff).chr}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.decode_base32(str)
|
|
73
|
+
bytes = str.bytes
|
|
74
|
+
result = ''
|
|
75
|
+
size= 8
|
|
76
|
+
while bytes.any? do
|
|
77
|
+
bytes.each_slice(size) do |a|
|
|
78
|
+
bytes_out = b32decode(a).flatten.join
|
|
79
|
+
result << bytes_out
|
|
80
|
+
bytes = bytes.drop(size)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
return result
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
module Rex
|
|
3
|
+
module Text
|
|
4
|
+
# We are re-opening the module to add these module methods.
|
|
5
|
+
# Breaking them up this way allows us to maintain a little higher
|
|
6
|
+
# degree of organisation and make it easier to find what you're looking for
|
|
7
|
+
# without hanging the underlying calls that we historically rely upon.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
#
|
|
11
|
+
# Base64 encoder
|
|
12
|
+
#
|
|
13
|
+
def self.encode_base64(str, delim='')
|
|
14
|
+
[str.to_s].pack("m").gsub(/\s+/, delim)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# Base64 decoder
|
|
19
|
+
#
|
|
20
|
+
def self.decode_base64(str)
|
|
21
|
+
str.to_s.unpack("m")[0]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
#
|
|
25
|
+
# Base64 encoder (URL-safe RFC6920)
|
|
26
|
+
#
|
|
27
|
+
def self.encode_base64url(str, delim='')
|
|
28
|
+
encode_base64(str, delim).
|
|
29
|
+
tr('+/', '-_').
|
|
30
|
+
gsub('=', '')
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
# Base64 decoder (URL-safe RFC6920, ignores invalid characters)
|
|
35
|
+
#
|
|
36
|
+
def self.decode_base64url(str)
|
|
37
|
+
decode_base64(
|
|
38
|
+
str.gsub(/[^a-zA-Z0-9_\-]/, '').
|
|
39
|
+
tr('-_', '+/'))
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
module Rex
|
|
3
|
+
module Text
|
|
4
|
+
# We are re-opening the module to add these module methods.
|
|
5
|
+
# Breaking them up this way allows us to maintain a little higher
|
|
6
|
+
# degree of organisation and make it easier to find what you're looking for
|
|
7
|
+
# without hanging the underlying calls that we historically rely upon.
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Creates a comma separated list of numbers
|
|
11
|
+
#
|
|
12
|
+
def self.to_num(str, wrap = DefaultWrap)
|
|
13
|
+
code = str.unpack('C*')
|
|
14
|
+
buff = ""
|
|
15
|
+
0.upto(code.length-1) do |byte|
|
|
16
|
+
if(byte % 15 == 0) and (buff.length > 0)
|
|
17
|
+
buff << "\r\n"
|
|
18
|
+
end
|
|
19
|
+
buff << sprintf('0x%.2x, ', code[byte])
|
|
20
|
+
end
|
|
21
|
+
# strip , at the end
|
|
22
|
+
buff = buff.chomp(', ')
|
|
23
|
+
buff << "\r\n"
|
|
24
|
+
return buff
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
#
|
|
28
|
+
# Creates a comma separated list of dwords
|
|
29
|
+
#
|
|
30
|
+
def self.to_dword(str, wrap = DefaultWrap)
|
|
31
|
+
code = str
|
|
32
|
+
alignnr = str.length % 4
|
|
33
|
+
if (alignnr > 0)
|
|
34
|
+
code << "\x00" * (4 - alignnr)
|
|
35
|
+
end
|
|
36
|
+
codevalues = Array.new
|
|
37
|
+
code.split("").each_slice(4) do |chars4|
|
|
38
|
+
chars4 = chars4.join("")
|
|
39
|
+
dwordvalue = chars4.unpack('*V')
|
|
40
|
+
codevalues.push(dwordvalue[0])
|
|
41
|
+
end
|
|
42
|
+
buff = ""
|
|
43
|
+
0.upto(codevalues.length-1) do |byte|
|
|
44
|
+
if(byte % 8 == 0) and (buff.length > 0)
|
|
45
|
+
buff << "\r\n"
|
|
46
|
+
end
|
|
47
|
+
buff << sprintf('0x%.8x, ', codevalues[byte])
|
|
48
|
+
end
|
|
49
|
+
# strip , at the end
|
|
50
|
+
buff = buff.chomp(', ')
|
|
51
|
+
buff << "\r\n"
|
|
52
|
+
return buff
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
# Returns the words in +str+ as an Array.
|
|
57
|
+
#
|
|
58
|
+
# strict - include *only* words, no boundary characters (like spaces, etc.)
|
|
59
|
+
#
|
|
60
|
+
def self.to_words( str, strict = false )
|
|
61
|
+
splits = str.split( /\b/ )
|
|
62
|
+
splits.reject! { |w| !(w =~ /\w/) } if strict
|
|
63
|
+
splits
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
#
|
|
67
|
+
# Pack a value as 64 bit litle endian; does not exist for Array.pack
|
|
68
|
+
#
|
|
69
|
+
def self.pack_int64le(val)
|
|
70
|
+
[val & 0x00000000ffffffff, val >> 32].pack("V2")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
#
|
|
74
|
+
# Rotate a 32-bit value to the right by +cnt+ bits
|
|
75
|
+
#
|
|
76
|
+
# @param val [Fixnum] The value to rotate
|
|
77
|
+
# @param cnt [Fixnum] Number of bits to rotate by
|
|
78
|
+
def self.ror(val, cnt)
|
|
79
|
+
bits = [val].pack("N").unpack("B32")[0].split(//)
|
|
80
|
+
1.upto(cnt) do |c|
|
|
81
|
+
bits.unshift( bits.pop )
|
|
82
|
+
end
|
|
83
|
+
[bits.join].pack("B32").unpack("N")[0]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
#
|
|
87
|
+
# Rotate a 32-bit value to the left by +cnt+ bits
|
|
88
|
+
#
|
|
89
|
+
# @param val (see ror)
|
|
90
|
+
# @param cnt (see ror)
|
|
91
|
+
# @return (see ror)
|
|
92
|
+
def self.rol(val, cnt)
|
|
93
|
+
bits = [val].pack("N").unpack("B32")[0].split(//)
|
|
94
|
+
1.upto(cnt) do |c|
|
|
95
|
+
bits.push( bits.shift )
|
|
96
|
+
end
|
|
97
|
+
[bits.join].pack("B32").unpack("N")[0]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
#
|
|
101
|
+
# Removes noise from 2 Strings and return a refined String version.
|
|
102
|
+
#
|
|
103
|
+
def self.refine( str1, str2 )
|
|
104
|
+
return str1 if str1 == str2
|
|
105
|
+
|
|
106
|
+
# get the words of the first str in an array
|
|
107
|
+
s_words = to_words( str1 )
|
|
108
|
+
|
|
109
|
+
# get the words of the second str in an array
|
|
110
|
+
o_words = to_words( str2 )
|
|
111
|
+
|
|
112
|
+
# get what hasn't changed (the rdiff, so to speak) as a string
|
|
113
|
+
(s_words - (s_words - o_words)).join
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
module Rex
|
|
3
|
+
module Text
|
|
4
|
+
# We are re-opening the module to add these module methods.
|
|
5
|
+
# Breaking them up this way allows us to maintain a little higher
|
|
6
|
+
# degree of organisation and make it easier to find what you're looking for
|
|
7
|
+
# without hanging the underlying calls that we historically rely upon.
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Calculate the block API hash for the given module/function
|
|
11
|
+
#
|
|
12
|
+
# @param mod [String] The name of the module containing the target function.
|
|
13
|
+
# @param fun [String] The name of the function.
|
|
14
|
+
#
|
|
15
|
+
# @return [String] The hash of the mod/fun pair in string format
|
|
16
|
+
def self.block_api_hash(mod, fun)
|
|
17
|
+
unicode_mod = (mod.upcase + "\x00").unpack('C*').pack('v*')
|
|
18
|
+
mod_hash = self.ror13_hash(unicode_mod)
|
|
19
|
+
fun_hash = self.ror13_hash(fun + "\x00")
|
|
20
|
+
"0x#{(mod_hash + fun_hash & 0xFFFFFFFF).to_s(16)}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
#
|
|
24
|
+
# Calculate the ROR13 hash of a given string
|
|
25
|
+
#
|
|
26
|
+
# @return [Fixnum]
|
|
27
|
+
def self.ror13_hash(name)
|
|
28
|
+
hash = 0
|
|
29
|
+
name.unpack("C*").each {|c| hash = ror(hash, 13); hash += c }
|
|
30
|
+
hash
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
module Rex
|
|
3
|
+
module Text
|
|
4
|
+
# We are re-opening the module to add these module methods.
|
|
5
|
+
# Breaking them up this way allows us to maintain a little higher
|
|
6
|
+
# degree of organisation and make it easier to find what you're looking for
|
|
7
|
+
# without hanging the underlying calls that we historically rely upon.
|
|
8
|
+
|
|
9
|
+
# @param str [String] Data to checksum
|
|
10
|
+
# @return [Fixnum] 8-bit checksum
|
|
11
|
+
def self.checksum8(str)
|
|
12
|
+
(str.unpack("C*").inject(:+) || 0) % 0x100
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @param str [String] Little-endian data to checksum
|
|
16
|
+
# @return [Fixnum] 16-bit checksum
|
|
17
|
+
def self.checksum16_le(str)
|
|
18
|
+
(str.unpack("v*").inject(:+) || 0) % 0x10000
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param str [String] Big-endian data to checksum
|
|
22
|
+
# @return [Fixnum] 16-bit checksum
|
|
23
|
+
def self.checksum16_be(str)
|
|
24
|
+
(str.unpack("n*").inject(:+) || 0) % 0x10000
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @param str [String] Little-endian data to checksum
|
|
28
|
+
# @return [Fixnum] 32-bit checksum
|
|
29
|
+
def self.checksum32_le(str)
|
|
30
|
+
(str.unpack("V*").inject(:+) || 0) % 0x100000000
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @param str [String] Big-endian data to checksum
|
|
34
|
+
# @return [Fixnum] 32-bit checksum
|
|
35
|
+
def self.checksum32_be(str)
|
|
36
|
+
(str.unpack("N*").inject(:+) || 0) % 0x100000000
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# -*- coding: binary -*-
|
|
2
|
+
module Rex
|
|
3
|
+
module Text
|
|
4
|
+
# We are re-opening the module to add these module methods.
|
|
5
|
+
# Breaking them up this way allows us to maintain a little higher
|
|
6
|
+
# degree of organisation and make it easier to find what you're looking for
|
|
7
|
+
# without hanging the underlying calls that we historically rely upon.
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Compresses a string, eliminating all superfluous whitespace before and
|
|
11
|
+
# after lines and eliminating all lines.
|
|
12
|
+
#
|
|
13
|
+
# @param str [String] The string in which to crunch whitespace
|
|
14
|
+
# @return [String] Just like +str+, but with repeated whitespace characters
|
|
15
|
+
# trimmed down to a single space
|
|
16
|
+
def self.compress(str)
|
|
17
|
+
str.gsub(/\n/m, ' ').gsub(/\s+/, ' ').gsub(/^\s+/, '').gsub(/\s+$/, '')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Returns true if zlib can be used.
|
|
23
|
+
def self.zlib_present?
|
|
24
|
+
begin
|
|
25
|
+
temp = Zlib
|
|
26
|
+
return true
|
|
27
|
+
rescue
|
|
28
|
+
return false
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# backwards compat for just a bit...
|
|
33
|
+
def self.gzip_present?
|
|
34
|
+
self.zlib_present?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# Compresses a string using zlib
|
|
39
|
+
#
|
|
40
|
+
# @param str [String] The string to be compressed
|
|
41
|
+
# @param level [Fixnum] One of the Zlib compression level constants
|
|
42
|
+
# @return [String] The compressed version of +str+
|
|
43
|
+
def self.zlib_deflate(str, level = Zlib::BEST_COMPRESSION)
|
|
44
|
+
if self.zlib_present?
|
|
45
|
+
z = Zlib::Deflate.new(level)
|
|
46
|
+
dst = z.deflate(str, Zlib::FINISH)
|
|
47
|
+
z.close
|
|
48
|
+
return dst
|
|
49
|
+
else
|
|
50
|
+
raise RuntimeError, "Gzip support is not present."
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
#
|
|
55
|
+
# Uncompresses a string using zlib
|
|
56
|
+
#
|
|
57
|
+
# @param str [String] Compressed string to inflate
|
|
58
|
+
# @return [String] The uncompressed version of +str+
|
|
59
|
+
def self.zlib_inflate(str)
|
|
60
|
+
if(self.zlib_present?)
|
|
61
|
+
zstream = Zlib::Inflate.new
|
|
62
|
+
buf = zstream.inflate(str)
|
|
63
|
+
zstream.finish
|
|
64
|
+
zstream.close
|
|
65
|
+
return buf
|
|
66
|
+
else
|
|
67
|
+
raise RuntimeError, "Gzip support is not present."
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#
|
|
72
|
+
# Compresses a string using gzip
|
|
73
|
+
#
|
|
74
|
+
# @param str (see zlib_deflate)
|
|
75
|
+
# @param level [Fixnum] Compression level, 1 (fast) to 9 (best)
|
|
76
|
+
# @return (see zlib_deflate)
|
|
77
|
+
def self.gzip(str, level = 9)
|
|
78
|
+
raise RuntimeError, "Gzip support is not present." if (!zlib_present?)
|
|
79
|
+
raise RuntimeError, "Invalid gzip compression level" if (level < 1 or level > 9)
|
|
80
|
+
|
|
81
|
+
s = ""
|
|
82
|
+
s.force_encoding('ASCII-8BIT') if s.respond_to?(:encoding)
|
|
83
|
+
gz = Zlib::GzipWriter.new(StringIO.new(s, 'wb'), level)
|
|
84
|
+
gz << str
|
|
85
|
+
gz.close
|
|
86
|
+
return s
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
# Uncompresses a string using gzip
|
|
91
|
+
#
|
|
92
|
+
# @param str (see zlib_inflate)
|
|
93
|
+
# @return (see zlib_inflate)
|
|
94
|
+
def self.ungzip(str)
|
|
95
|
+
raise RuntimeError, "Gzip support is not present." if (!zlib_present?)
|
|
96
|
+
|
|
97
|
+
s = ""
|
|
98
|
+
s.force_encoding('ASCII-8BIT') if s.respond_to?(:encoding)
|
|
99
|
+
gz = Zlib::GzipReader.new(StringIO.new(str, 'rb'))
|
|
100
|
+
s << gz.read
|
|
101
|
+
gz.close
|
|
102
|
+
return s
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|