Ascii85 0.9.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.
Binary file
@@ -0,0 +1,5 @@
1
+ === 0.9.0 / 2009-02-17
2
+
3
+ * 1 major enhancement
4
+
5
+ * Initial release
@@ -0,0 +1,6 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/ascii85.rb
6
+ spec/ascii85_spec.rb
@@ -0,0 +1,59 @@
1
+ = Ascii85
2
+
3
+ * http://ascii85.rubyforge.org
4
+
5
+ == DESCRIPTION:
6
+
7
+ Ascii85 is a simple gem that provides methods for encoding/decoding Adobe's
8
+ binary-to-text encoding of the same name.
9
+
10
+ See http://www.adobe.com/products/postscript/pdfs/PLRM.pdf page 131 and
11
+ http://en.wikipedia.org/wiki/Ascii85 for more information about the format.
12
+
13
+
14
+ == SYNOPSIS:
15
+
16
+ require 'rubygems'
17
+ require 'ascii85'
18
+
19
+ Ascii85::encode("Ruby")
20
+ => "<~;KZGo~>"
21
+
22
+ Ascii85::decode("<~;KZGo~>")
23
+ => "Ruby"
24
+
25
+ In addition, Ascii85::encode can take a second parameter that specifies the
26
+ length of the returned lines. The default is 80; use +false+ for unlimited.
27
+
28
+ Ascii85::decode expects the input to be enclosed in <~ and ~>. It ignores
29
+ everything outside of these.
30
+
31
+
32
+ == INSTALL:
33
+
34
+ * sudo gem install ascii85
35
+
36
+
37
+ == LICENSE:
38
+
39
+ (The MIT License)
40
+
41
+ Copyright (c) 2009 Johannes Holzfuß
42
+
43
+ Permission is hereby granted, free of charge, to any person obtaining a
44
+ copy of this software and associated documentation files (the "Software"),
45
+ to deal in the Software without restriction, including without limitation the
46
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
47
+ sell copies of the Software, and to permit persons to whom the Software is
48
+ furnished to do so, subject to the following conditions:
49
+
50
+ The above copyright notice and this permission notice shall be included in
51
+ all copies or substantial portions of the Software.
52
+
53
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
56
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
59
+ THE SOFTWARE.
@@ -0,0 +1,43 @@
1
+
2
+ require 'rubygems'
3
+
4
+ require 'hoe'
5
+ require 'rake'
6
+ require 'rake/clean'
7
+ require 'rake/rdoctask'
8
+ require 'spec/rake/spectask'
9
+
10
+ require 'lib/ascii85.rb'
11
+
12
+
13
+ # rspec
14
+
15
+ desc "Run specs"
16
+ Spec::Rake::SpecTask.new do |t|
17
+ t.spec_opts = ["--color"]
18
+ end
19
+
20
+ desc "Show specdoc"
21
+ Spec::Rake::SpecTask.new('specdoc') do |t|
22
+ t.spec_opts = ["--color", "--format=specdoc"]
23
+ end
24
+
25
+
26
+ # Hoe
27
+
28
+ Hoe.new('Ascii85', Ascii85::VERSION) do |p|
29
+ p.author = "Johannes Holzfuß"
30
+ p.email = "Drangon@gmx.de"
31
+ p.summary = "Ascii85 encoder/decoder"
32
+
33
+ p.description = "Ascii85 provides methods to encode/decode Adobe's binary-to-text encoding of the same name."
34
+
35
+ p.remote_rdoc_dir = ''
36
+
37
+ p.testlib = "spec"
38
+ p.test_globs = "spec/ascii85_spec.rb"
39
+ end
40
+
41
+
42
+ # default task is spec
43
+ task :default => :spec
@@ -0,0 +1,205 @@
1
+ #
2
+ # Ascii85 is an implementation of Adobe's binary-to-text encoding of the same
3
+ # name in pure Ruby.
4
+ #
5
+ # See http://www.adobe.com/products/postscript/pdfs/PLRM.pdf page 131 and
6
+ # http://en.wikipedia.org/wiki/Ascii85 for more information about the format.
7
+ #
8
+ # Author:: Johannes Holzfuß (Drangon@gmx.de)
9
+ # License:: Distributed under the MIT License (see README.txt)
10
+ #
11
+
12
+
13
+ module Ascii85
14
+ # The gem version number
15
+ VERSION = '0.9.0' # :nodoc:
16
+
17
+ #
18
+ # Encodes the given String as Ascii85.
19
+ #
20
+ # If +wrap_lines+ evaluates to +false+, the output will be returned as a
21
+ # single long line. Otherwise #encode formats the output into lines of
22
+ # length +wrap_lines+ (minimum is 2).
23
+ #
24
+ # Ascii85::encode("Ruby")
25
+ # => <~;KZGo~>
26
+ #
27
+ # Ascii85::encode("Supercalifragilisticexpialidocious", 15)
28
+ # => <~;g!%jEarNoBkD
29
+ # BoB5)0rF*),+AU&
30
+ # 0.@;KXgDe!L"F`R
31
+ # ~>
32
+ #
33
+ # Ascii85::encode("Supercalifragilisticexpialidocious", false)
34
+ # => <~;g!%jEarNoBkDBoB5)0rF*),+AU&0.@;KXgDe!L"F`R~>
35
+ #
36
+ #
37
+ def self.encode(str, wrap_lines = 80)
38
+
39
+ return '' if str.to_s.empty?
40
+
41
+ # Compute number of \0s to pad the message with (0..3)
42
+ padding_length = (-str.to_s.length) % 4
43
+
44
+ # Extract big-endian integers
45
+ tuples = (str.to_s + ("\0" * padding_length)).unpack('N*')
46
+
47
+ # Encode
48
+ tuples.map! do |tuple|
49
+ if tuple == 0
50
+ 'z'
51
+ else
52
+ tmp = ""
53
+ 5.times do
54
+ tmp += ((tuple % 85) + 33).chr
55
+ tuple /= 85
56
+ end
57
+ tmp.reverse
58
+ end
59
+ end
60
+
61
+ # We can't use the z-abbreviation if we're going to cut off padding
62
+ if (padding_length > 0) and (tuples.last == 'z')
63
+ tuples[-1] = '!!!!!'
64
+ end
65
+
66
+ # Cut off the padding
67
+ tuples[-1] = tuples[-1][0..(4 - padding_length)]
68
+
69
+ # Add start-marker and join into a String
70
+ result = '<~' + tuples.join
71
+
72
+ # If we don't need to wrap the lines to a certain length, add ~> and return
73
+ if (!wrap_lines)
74
+ return result + '~>'
75
+ end
76
+
77
+ # Otherwise we wrap the lines
78
+
79
+ line_length = [2, wrap_lines.to_i].max
80
+
81
+ wrapped = []
82
+ 0.step(result.length, line_length) do |index|
83
+ wrapped << result.slice(index, line_length)
84
+ end
85
+
86
+ # Add end-marker -- on a new line if necessary
87
+ if (wrapped.last.length + 2) > line_length
88
+ wrapped << '~>'
89
+ else
90
+ wrapped[-1] += '~>'
91
+ end
92
+
93
+ return wrapped.join("\n")
94
+ end
95
+
96
+ #
97
+ # Searches through +str+ and decodes the _first_ Ascii85-String found.
98
+ #
99
+ # #decode expects an Ascii85-encoded String enclosed in <~ and ~>. It will
100
+ # ignore all characters outside these markers.
101
+ #
102
+ # Ascii85::decode("<~;KZGo~>")
103
+ # => "Ruby"
104
+ #
105
+ # Ascii85::decode("Foo<~;KZGo~>Bar<~;KZGo~>Baz")
106
+ # => "Ruby"
107
+ #
108
+ # Ascii85::decode("No markers")
109
+ # => ""
110
+ #
111
+ # #decode will raise Ascii85::DecodingError when malformed input is
112
+ # encountered.
113
+ #
114
+ def self.decode(str)
115
+
116
+ # Find the Ascii85 encoded data between <~ and ~>
117
+ input = str.to_s.match(/<~.*?~>/mn)
118
+
119
+ return '' if input.nil?
120
+
121
+ # Remove the delimiters
122
+ input = input.to_s[2..-3]
123
+
124
+ return '' if input.empty?
125
+
126
+ # Decode
127
+ result = []
128
+
129
+ count = 0
130
+ word = 0
131
+
132
+ input.each_byte do |c|
133
+
134
+ case c.chr
135
+ when /[ \t\r\n\f\0]/
136
+ # Ignore whitespace
137
+ next
138
+
139
+ when 'z'
140
+ if count == 0
141
+ # Expand z to 0-word
142
+ result << 0
143
+ else
144
+ raise(Ascii85::DecodingError, "Found 'z' inside Ascii85 5-tuple")
145
+ end
146
+
147
+ when '!'..'u'
148
+ # Decode 5 characters into a 4-byte word
149
+ word += (c - 33) * 85**(4 - count)
150
+ count += 1
151
+
152
+ if count == 5
153
+
154
+ if word >= 2**32
155
+ raise(Ascii85::DecodingError,
156
+ "Invalid Ascii85 5-tuple (#{word} >= 2**32)")
157
+ end
158
+
159
+ result << word
160
+ word = 0
161
+ count = 0
162
+ end
163
+
164
+ else
165
+ raise(Ascii85::DecodingError,
166
+ "Illegal character inside Ascii85: #{c.chr.dump}")
167
+ end
168
+
169
+ end
170
+
171
+ # Convert result into a String
172
+ result = result.pack('N*')
173
+
174
+ if count > 0
175
+ # Finish last, partially decoded 32-bit-word
176
+
177
+ if count == 1
178
+ raise(Ascii85::DecodingError,
179
+ "Last 5-tuple consists of single character")
180
+ end
181
+
182
+ count -= 1
183
+ word += 85**(4 - count)
184
+
185
+ result += ((word >> 24) & 255).chr if count >= 1
186
+ result += ((word >> 16) & 255).chr if count >= 2
187
+ result += ((word >> 8) & 255).chr if count == 3
188
+ end
189
+
190
+ return result
191
+ end
192
+
193
+ #
194
+ # This error is raised when Ascii85::decode encounters one of the following
195
+ # problems in the input:
196
+ #
197
+ # * An invalid character. Valid characters are '!'..'u' and 'z'.
198
+ # * A 'z' character inside a 5-tuple. 'z's are only valid on their own.
199
+ # * An invalid 5-tuple that decodes to >= 2**32
200
+ # * The last tuple consisting of a single character. Valid tuples always have
201
+ # at least two characters.
202
+ #
203
+ class DecodingError < StandardError; end
204
+
205
+ end
@@ -0,0 +1,152 @@
1
+ # encoding: utf-8
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+
5
+ require 'ascii85'
6
+
7
+ describe Ascii85 do
8
+
9
+ TEST_CASES = {
10
+
11
+ "" => "",
12
+ " " => "<~+9~>",
13
+
14
+ "\0" * 1 => "<~!!~>",
15
+ "\0" * 2 => "<~!!!~>",
16
+ "\0" * 3 => "<~!!!!~>",
17
+ "\0" * 4 => "<~z~>",
18
+ "\0" * 5 => "<~z!!~>",
19
+ "A\0\0\0\0" => "<~5l^lb!!~>", # No z-abbreviation!
20
+
21
+ "A" => "<~5l~>",
22
+ "AB" => "<~5sb~>",
23
+ "ABC" => "<~5sdp~>",
24
+ "ABCD" => "<~5sdq,~>",
25
+ "ABCDE" => "<~5sdq,70~>",
26
+ "ABCDEF" => "<~5sdq,77I~>",
27
+ "ABCDEFG" => "<~5sdq,77Kc~>",
28
+ "ABCDEFGH" => "<~5sdq,77Kd<~>",
29
+ "ABCDEFGHI" => "<~5sdq,77Kd<8H~>",
30
+ "Ascii85" => "<~6$$OMBfIs~>",
31
+
32
+ 'Antidisestablishmentarianism' => '<~6#LdYA8-*rF*(i"Ch[s(D.RU,@<-\'jDJ=0/~>',
33
+
34
+ # Dōmo arigatō, Mr. Roboto (according to Wikipedia)
35
+ 'どうもありがとうミスターロボット' =>
36
+ "<~j+42iJVN3:K&_E6j+<0KJW/W?W8iG`j+EuaK\"9on^Z0sZj+FJoK:LtSKB%T?~>",
37
+
38
+ [Math::PI].pack('G') => "<~5RAV2<(&;T~>",
39
+ [Math::E].pack('G') => "<~5R\"n0M\\K6,~>"
40
+ }
41
+
42
+ it "#decode should be the inverse of #encode" do
43
+
44
+ # Generate a random string
45
+ test_str = ""
46
+ (1 + rand(255)).times do
47
+ test_str += rand(256).chr
48
+ end
49
+
50
+ encoded = Ascii85::encode(test_str)
51
+ decoded = Ascii85::decode(encoded)
52
+
53
+ decoded.should == test_str
54
+ end
55
+
56
+ describe "#encode" do
57
+
58
+ it "should encode all specified test-cases correctly" do
59
+ TEST_CASES.each_pair do |input, encoded|
60
+ Ascii85::encode(input).should == encoded
61
+ end
62
+ end
63
+
64
+ it "should produce output lines no longer than specified" do
65
+ test_str = '0123456789' * 30
66
+
67
+ #
68
+ # No wrap
69
+ #
70
+ Ascii85::encode(test_str, false).count("\n").should == 0
71
+
72
+ #
73
+ # x characters per line, except for the last one
74
+ #
75
+ x = 2 + rand(255) # < test_str.length
76
+ encoded = Ascii85::encode(test_str, x)
77
+
78
+ # Determine the length of all lines
79
+ count_arr = []
80
+ encoded.each_line do |line|
81
+ count_arr << line.chomp.length
82
+ end
83
+
84
+ # The last line is allowed to be shorter than x, so remove it
85
+ count_arr.pop if count_arr.last <= x
86
+
87
+ # If the end-marker is on a line of its own, the next-to-last line is
88
+ # allowed to be shorter than specified by exactly one character
89
+ count_arr.pop if (encoded[-3].chr =~ /[\r\n]/) and (count_arr.last == x-1)
90
+
91
+ # Remove all line-lengths that are of length x from count_arr
92
+ count_arr.delete_if { |len| len == x }
93
+
94
+ # Now count_arr should be empty
95
+ count_arr.should be_empty
96
+ end
97
+
98
+ it "should not split the end-marker to achieve correct line length" do
99
+ Ascii85::encode("\0" * 4, 4).should == "<~z\n~>"
100
+ end
101
+
102
+ end
103
+
104
+ describe "#decode" do
105
+
106
+ it "should decode all specified test-cases correctly" do
107
+ TEST_CASES.each_pair do |decoded, input|
108
+ Ascii85::decode(input).should == decoded
109
+ end
110
+ end
111
+
112
+ it "should ignore everything before/after the delimiter-pairs" do
113
+ Ascii85::decode("Doesn't contain delimiters").should == ''
114
+ Ascii85::decode("FooBar<~z~>BazQux").should == ("\0" * 4)
115
+ end
116
+
117
+ it "should ignore whitespace" do
118
+ decoded = Ascii85::decode("<~6 #LdYA\r\08\n \n\n- *rF*(i\"Ch[s \t(D.RU,@ <-\'jDJ=0\f/~>")
119
+ decoded.should == 'Antidisestablishmentarianism'
120
+ end
121
+
122
+ describe "Error conditions" do
123
+
124
+ it "should raise DecodingError if it encounters a word >= 2**32" do
125
+ lambda {
126
+ Ascii85::decode('<~s8W-#~>')
127
+ }.should raise_error Ascii85::DecodingError
128
+ end
129
+
130
+ it "should raise DecodingError if it encounters an invalid character" do
131
+ lambda {
132
+ Ascii85::decode('<~!!y!!~>')
133
+ }.should raise_error Ascii85::DecodingError
134
+ end
135
+
136
+ it "should raise DecodingError if the last tuple consists of a single character" do
137
+ lambda {
138
+ Ascii85::decode('<~!~>')
139
+ }.should raise_error Ascii85::DecodingError
140
+ end
141
+
142
+ it "should raise DecodingError if a z is found inside a 5-tuple" do
143
+ lambda {
144
+ Ascii85::decode('<~!!z!!~>')
145
+ }.should raise_error Ascii85::DecodingError
146
+ end
147
+
148
+ end
149
+
150
+ end
151
+
152
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: Ascii85
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - "Johannes Holzfu\xC3\x9F"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDKjCCAhKgAwIBAgIBADANBgkqhkiG9w0BAQUFADA7MRAwDgYDVQQDDAdfcmFu
14
+ Z29uMRMwEQYKCZImiZPyLGQBGRYDZ214MRIwEAYKCZImiZPyLGQBGRYCZGUwHhcN
15
+ MDkwMjE0MTgxNDM5WhcNMTAwMjE0MTgxNDM5WjA7MRAwDgYDVQQDDAdfcmFuZ29u
16
+ MRMwEQYKCZImiZPyLGQBGRYDZ214MRIwEAYKCZImiZPyLGQBGRYCZGUwggEiMA0G
17
+ CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa7HRW1pPBbx8k9GLOzYBwHNLAOvHc
18
+ kWfq5E99plLhxKobF7xSValm2csTPQqF8549JJUADGrmeSyFx4z241JtDATjFdYI
19
+ 5LaBXqvxR/c6BfPqPOIuZqc6o1VEpMEVsgKqcL0wjmOaNXMDL7vWj2+LyizWqMXJ
20
+ Y2Hj6GlR6kYzoUyOoAPO+FG363YT++tFvOaOmba314dL40r/Spc730gr1utS8pHA
21
+ t8Gl+Z0EC5gmcUvfDT2sVAF8k9qQhGGqOuOM2HDP+ZrJ368UJznVBxp9YhUveGc2
22
+ MPXvntkrN2XLfGjV2Tr418v7OBP+0IgnZVBM8O7q+iMJmuv/yt2M53H/AgMBAAGj
23
+ OTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBT83GfQpOoJZm8B
24
+ gY6lweCTOsu0QTANBgkqhkiG9w0BAQUFAAOCAQEAAT33NPbPZVy3tgPsl1TicU9q
25
+ eBen2WkXfrCO8jP1ivuFQqMHl5b+MpG2LIwEB45QLLnoXmcW+C4ihGdkYG078uor
26
+ ZskHRETlHJ791l6PyGw5j1oFSwbeYwYIFBWcRrq0KdcZO4CZb7rln2S06ZJWQIMg
27
+ 930O6/WuJyRQLr1PaTJcUGoHUC9cd4CE7ARuck3V38vNR4azjAznCa01mgSkp9UQ
28
+ xPVAMuP9qOp6+OFiuL7DDCHgGI52vDFlUSU+hMcsSSDbYSFcilSPlZ3WLTlOhM4d
29
+ 5FGhYN16QZS8VKLApBtxxP9XmwFASMyJLNizTN2q6hCCy/MjoTzHWzodPaWm0Q==
30
+ -----END CERTIFICATE-----
31
+
32
+ date: 2009-02-17 00:00:00 +01:00
33
+ default_executable:
34
+ dependencies:
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.8.3
44
+ version:
45
+ description: Ascii85 provides methods to encode/decode Adobe's binary-to-text encoding of the same name.
46
+ email: Drangon@gmx.de
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - History.txt
53
+ - Manifest.txt
54
+ - README.txt
55
+ files:
56
+ - History.txt
57
+ - Manifest.txt
58
+ - README.txt
59
+ - Rakefile
60
+ - lib/ascii85.rb
61
+ - spec/ascii85_spec.rb
62
+ has_rdoc: true
63
+ homepage: http://ascii85.rubyforge.org
64
+ post_install_message:
65
+ rdoc_options:
66
+ - --main
67
+ - README.txt
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ requirements: []
83
+
84
+ rubyforge_project: ascii85
85
+ rubygems_version: 1.3.1
86
+ signing_key:
87
+ specification_version: 2
88
+ summary: Ascii85 encoder/decoder
89
+ test_files:
90
+ - spec/ascii85_spec.rb
Binary file