Ascii85-1.0.3/0000755000004100000410000000000013306475405012757 5ustar www-datawww-dataAscii85-1.0.3/.travis.yml0000644000004100000410000000010413306475405015063 0ustar www-datawww-datalanguage: ruby rvm: - 1.8 - 1.9 - 2.5 - ruby-head - jruby Ascii85-1.0.3/README.md0000644000004100000410000000345413306475405014244 0ustar www-datawww-data**Status**: This project is in maintenance mode. I will not develop new features, but I will address Issues and Pull Requests. # Ascii85 [![Build Status](https://travis-ci.org/DataWraith/ascii85gem.svg?branch=master)](https://travis-ci.org/DataWraith/ascii85gem) ## Description Ascii85 is a simple gem that provides methods for encoding/decoding Adobe's binary-to-text encoding of the same name. See http://www.adobe.com/products/postscript/pdfs/PLRM.pdf page 131 and http://en.wikipedia.org/wiki/Ascii85 for more information about the format. ## Installation `sudo gem install Ascii85` ## Usage ``` require 'rubygems' require 'ascii85' Ascii85.encode("Ruby") => "<~;KZGo~>" Ascii85.decode("<~;KZGo~>") => "Ruby" ``` In addition, Ascii85.encode can take a second parameter that specifies the length of the returned lines. The default is 80; use `false` for unlimited. Ascii85.decode expects the input to be enclosed in <~ and ~> — it ignores everything outside of these. The output of Ascii85.decode will have the ASCII-8BIT encoding, so in Ruby 1.9 you may have to use String#force_encoding to correct the encoding. ## Command-line utility This gem includes `ascii85`, a command-line utility modeled after `base64` from the GNU coreutils. It can be used to encode/decode Ascii85 directly from the command-line: ``` Usage: ascii85 [OPTIONS] [FILE] Encodes or decodes FILE or STDIN using Ascii85 and writes to STDOUT. -w, --wrap COLUMN Wrap lines at COLUMN. Default is 80, use 0 for no wrapping -d, --decode Decode the input -h, --help Display this help and exit --version Output version information ``` ## License Ascii85 is distributed under the MIT License. See the accompanying LICENSE file for details. Ascii85-1.0.3/bin/0000755000004100000410000000000013306475405013527 5ustar www-datawww-dataAscii85-1.0.3/bin/ascii850000755000004100000410000000341313306475405014723 0ustar www-datawww-data#!/usr/bin/env ruby # encoding: utf-8 # # A simple command-line tool to de- and encode Ascii85, modeled after `base64` # from the GNU Coreutils. # require "optparse" require File.join(File.dirname(__FILE__), '..', 'lib', 'ascii85') @options = { :wrap => 80, :decode => false } ARGV.options do |opts| opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [OPTIONS] [FILE]\n" + "Encodes or decodes FILE or STDIN using Ascii85 and writes to STDOUT." opts.on( "-w", "--wrap COLUMN", Integer, "Wrap lines at COLUMN. Default is 80, use 0 for no wrapping") do |opt| @options[:wrap] = opt.abs @options[:wrap] = false if opt.zero? end opts.on( "-d", "--decode", "Decode the input") do @options[:decode] = true end opts.on( "-h", "--help", "Display this help and exit") do puts opts exit end opts.on( "--version", "Output version information") do |opt| puts "Ascii85 v#{Ascii85::VERSION},\nwritten by Johannes Holzfuß" exit end remaining_args = opts.parse! case remaining_args.size when 0 @options[:file] = '-' when 1 @options[:file] = remaining_args.first else abort "Superfluous operand(s): \"#{remaining_args.join('", "')}\"" end end if @options[:file] == '-' @input = $stdin.binmode.read else unless File.exists?(@options[:file]) abort "File not found: \"#{@options[:file]}\"" end unless File.readable_real?(@options[:file]) abort "File is not readable: \"#{@options[:file]}\"" end File.open(@options[:file], 'rb') do |f| @input = f.read end end if @options[:decode] begin print Ascii85.decode(@input) rescue Ascii85::DecodingError => error abort "Decoding Error: #{error.message.to_s}" end else print Ascii85.encode(@input, @options[:wrap]) end Ascii85-1.0.3/spec/0000755000004100000410000000000013306475405013711 5ustar www-datawww-dataAscii85-1.0.3/spec/lib/0000755000004100000410000000000013306475405014457 5ustar www-datawww-dataAscii85-1.0.3/spec/lib/ascii85_spec.rb0000644000004100000410000001432713306475405017272 0ustar www-datawww-data# encoding: utf-8 require 'rubygems' require 'minitest/autorun' # Require implementation require File.expand_path('../../../lib/ascii85', __FILE__) describe Ascii85 do UNSUPPORTED_MSG = "This version of Ruby does not support encodings" TEST_CASES = { "" => "", " " => "<~+9~>", "\0" * 1 => "<~!!~>", "\0" * 2 => "<~!!!~>", "\0" * 3 => "<~!!!!~>", "\0" * 4 => "<~z~>", "\0" * 5 => "<~z!!~>", "A\0\0\0\0" => "<~5l^lb!!~>", # No z-abbreviation! "A" => "<~5l~>", "AB" => "<~5sb~>", "ABC" => "<~5sdp~>", "ABCD" => "<~5sdq,~>", "ABCDE" => "<~5sdq,70~>", "ABCDEF" => "<~5sdq,77I~>", "ABCDEFG" => "<~5sdq,77Kc~>", "ABCDEFGH" => "<~5sdq,77Kd<~>", "ABCDEFGHI" => "<~5sdq,77Kd<8H~>", "Ascii85" => "<~6$$OMBfIs~>", 'Antidisestablishmentarianism' => '<~6#LdYA8-*rF*(i"Ch[s(D.RU,@<-\'jDJ=0/~>', # Dōmo arigatō, Mr. Roboto (according to Wikipedia) 'どうもありがとうミスターロボット' => "<~j+42iJVN3:K&_E6j+<0KJW/W?W8iG`j+EuaK\"9on^Z0sZj+FJoK:LtSKB%T?~>", [Math::PI].pack('G') => "<~5RAV2<(&;T~>", [Math::E].pack('G') => "<~5R\"n0M\\K6,~>" } it "#decode should be the inverse of #encode" do # Generate a random string test_str = "" (1 + rand(255)).times do test_str << rand(256).chr end encoded = Ascii85.encode(test_str) decoded = Ascii85.decode(encoded) decoded.must_equal test_str end describe "#encode" do it "should encode all specified test-cases correctly" do TEST_CASES.each_pair do |input, encoded| Ascii85.encode(input).must_equal encoded end end it "should encode Strings in different encodings correctly" do unless String.new.respond_to?(:encoding) skip(UNSUPPORTED_MSG) end input_EUC_JP = 'どうもありがとうミスターロボット'.encode('EUC-JP') input_binary = input_EUC_JP.force_encoding('ASCII-8BIT') Ascii85.encode(input_EUC_JP).must_equal Ascii85.encode(input_binary) end it "should produce output lines no longer than specified" do test_str = '0123456789' * 30 # # No wrap # Ascii85.encode(test_str, false).count("\n").must_equal 0 # # x characters per line, except for the last one # x = 2 + rand(255) # < test_str.length encoded = Ascii85.encode(test_str, x) # Determine the length of all lines count_arr = [] encoded.each_line do |line| count_arr << line.chomp.length end # The last line is allowed to be shorter than x, so remove it count_arr.pop if count_arr.last <= x # If the end-marker is on a line of its own, the next-to-last line is # allowed to be shorter than specified by exactly one character count_arr.pop if (encoded[-3].chr =~ /[\r\n]/) and (count_arr.last == x-1) # Remove all line-lengths that are of length x from count_arr count_arr.delete_if { |len| len == x } # Now count_arr should be empty count_arr.must_be_empty end it "should not split the end-marker to achieve correct line length" do Ascii85.encode("\0" * 4, 4).must_equal "<~z\n~>" end end describe "#decode" do it "should decode all specified test-cases correctly" do TEST_CASES.each_pair do |decoded, input| if String.new.respond_to?(:encoding) Ascii85.decode(input).must_equal decoded.dup.force_encoding('ASCII-8BIT') else Ascii85.decode(input).must_equal decoded end end end it "should accept valid input in encodings other than the default" do unless String.new.respond_to?(:encoding) skip(UNSUPPORTED_MSG) end input = "Ragnarök τέχνη русский язык I ♥ Ruby" input_ascii85 = Ascii85.encode(input) # Try to encode input_ascii85 in all possible encodings and see if we # do the right thing in #decode. Encoding.list.each do |encoding| next if encoding.dummy? next unless encoding.ascii_compatible? # CP949 is a Microsoft Codepage for Korean, which apparently does not # include a backslash, even though #ascii_compatible? returns true. This # leads to an Ascii85::DecodingError, so we simply skip the encoding. next if encoding.name == "CP949" begin to_test = input_ascii85.encode(encoding) Ascii85.decode(to_test).force_encoding('UTF-8').must_equal input rescue Encoding::ConverterNotFoundError # Ignore this encoding end end end it "should only process data within delimiters" do Ascii85.decode("<~~>").must_be_empty Ascii85.decode("Doesn't contain delimiters").must_be_empty Ascii85.decode("Mismatched ~> delimiters 1").must_be_empty Ascii85.decode("Mismatched <~ delimiters 2").must_be_empty Ascii85.decode("Mismatched ~><~ delimiters 3").must_be_empty Ascii85.decode("<~;KZGo~><~z~>").must_equal "Ruby" Ascii85.decode("FooBar<~z~>BazQux").must_equal "\0\0\0\0" end it "should ignore whitespace" do decoded = Ascii85.decode("<~6 #LdYA\r\08\n \n\n- *rF*(i\"Ch[s \t(D.RU,@ <-\'jDJ=0\f/~>") decoded.must_equal 'Antidisestablishmentarianism' end it "should return ASCII-8BIT encoded strings" do unless String.new.respond_to?(:encoding) skip(UNSUPPORTED_MSG) end Ascii85.decode("<~;KZGo~>").encoding.name.must_equal "ASCII-8BIT" end describe "Error conditions" do it "should raise DecodingError if it encounters a word >= 2**32" do lambda { Ascii85.decode('<~s8W-#~>') }.must_raise(Ascii85::DecodingError) end it "should raise DecodingError if it encounters an invalid character" do lambda { Ascii85.decode('<~!!y!!~>') }.must_raise(Ascii85::DecodingError) end it "should raise DecodingError if the last tuple consists of a single character" do lambda { Ascii85.decode('<~!~>') }.must_raise(Ascii85::DecodingError) end it "should raise DecodingError if a z is found inside a 5-tuple" do lambda { Ascii85.decode('<~!!z!!~>') }.must_raise Ascii85::DecodingError end end end end Ascii85-1.0.3/LICENSE0000644000004100000410000000204513306475405013765 0ustar www-datawww-dataCopyright (c) 2009 Johannes Holzfuß Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Ascii85-1.0.3/History.txt0000644000004100000410000000076213306475405015166 0ustar www-datawww-data=== 1.0.3 / 2018-01-25 * Updated the gem's metadata === 1.0.2 / 2012-09-16 * Changed test runner from RSpec to MiniSpec * Support for rubygems-test * Minor changes to make packaging easier === 1.0.1 / 2011-05-05 * Removed hoe dependency in favor of bundler * Minor corrections in the documentation === 1.0.0 / 2009-12-25 * 2 major enhancements * Ruby 1.9 compatibility * Added command-line en- and decoder === 0.9.0 / 2009-02-17 * 1 major enhancement * Initial release Ascii85-1.0.3/Rakefile0000644000004100000410000000034013306475405014421 0ustar www-datawww-datarequire 'bundler' Bundler::GemHelper.install_tasks require 'rake/testtask' Rake::TestTask.new do |t| t.test_files = FileList['spec/**/*_spec.rb'] end task :specs => :test task :tests => :test task :default => :test Ascii85-1.0.3/lib/0000755000004100000410000000000013306475405013525 5ustar www-datawww-dataAscii85-1.0.3/lib/ascii85.rb0000644000004100000410000001336413306475405015326 0ustar www-datawww-data# encoding: utf-8 # # Ascii85 is an implementation of Adobe's binary-to-text encoding of the # same name in pure Ruby. # # See http://www.adobe.com/products/postscript/pdfs/PLRM.pdf page 131 # and http://en.wikipedia.org/wiki/Ascii85 for more information about # the format. # # Author:: Johannes Holzfuß (johannes@holzfuss.name) # License:: Distributed under the MIT License (see LICENSE file) # module Ascii85 # # Encodes the bytes of the given String as Ascii85. # # If +wrap_lines+ evaluates to +false+, the output will be returned as # a single long line. Otherwise #encode formats the output into lines # of length +wrap_lines+ (minimum is 2). # # Ascii85.encode("Ruby") # => <~;KZGo~> # # Ascii85.encode("Supercalifragilisticexpialidocious", 15) # => <~;g!%jEarNoBkD # BoB5)0rF*),+AU& # 0.@;KXgDe!L"F`R # ~> # # Ascii85.encode("Supercalifragilisticexpialidocious", false) # => <~;g!%jEarNoBkDBoB5)0rF*),+AU&0.@;KXgDe!L"F`R~> # # def self.encode(str, wrap_lines = 80) to_encode = str.to_s return '' if to_encode.empty? # Deal with multi-byte encodings if to_encode.respond_to?(:bytesize) input_size = to_encode.bytesize else input_size = to_encode.size end # Compute number of \0s to pad the message with (0..3) padding_length = (-input_size) % 4 # Extract big-endian integers tuples = (to_encode + ("\0" * padding_length)).unpack('N*') # Encode tuples.map! do |tuple| if tuple == 0 'z' else tmp = "" 5.times do tmp << ((tuple % 85) + 33).chr tuple /= 85 end tmp.reverse end end # We can't use the z-abbreviation if we're going to cut off padding if (padding_length > 0) and (tuples.last == 'z') tuples[-1] = '!!!!!' end # Cut off the padding tuples[-1] = tuples[-1][0..(4 - padding_length)] # If we don't need to wrap the lines, add delimiters and return if (!wrap_lines) return '<~' + tuples.join + '~>' end # Otherwise we wrap the lines line_length = [2, wrap_lines.to_i].max wrapped = [] to_wrap = '<~' + tuples.join 0.step(to_wrap.length, line_length) do |index| wrapped << to_wrap.slice(index, line_length) end # Add end-marker – on a new line if necessary if (wrapped.last.length + 2) > line_length wrapped << '~>' else wrapped[-1] << '~>' end return wrapped.join("\n") end # # Searches through +str+ and decodes the _first_ Ascii85-String found. # # #decode expects an Ascii85-encoded String enclosed in <~ and ~> — it will # ignore all characters outside these markers. The returned strings are always # encoded as ASCII-8BIT. # # Ascii85.decode("<~;KZGo~>") # => "Ruby" # # Ascii85.decode("Foo<~;KZGo~>Bar<~;KZGo~>Baz") # => "Ruby" # # Ascii85.decode("No markers") # => "" # # #decode will raise Ascii85::DecodingError when malformed input is # encountered. # def self.decode(str) input = str.to_s opening_delim = '<~' closing_delim = '~>' # Make sure the delimiter strings have the correct encoding. # # Although I don't think it likely, this may raise encoding # errors if an especially exotic input encoding is introduced. # As of Ruby 1.9.2 all non-dummy encodings work fine though. # if opening_delim.respond_to?(:encode!) opening_delim.encode!(input.encoding) closing_delim.encode!(input.encoding) end # Get the positions of the opening/closing delimiters. If there is # no pair of opening/closing delimiters, return the empty string. (start_pos = input.index(opening_delim)) or return '' (end_pos = input.index(closing_delim, start_pos + 2)) or return '' # Get the string inside the delimiter-pair input = input[(start_pos + 2)...end_pos] # Decode word = 0 count = 0 result = [] input.each_byte do |c| case c.chr when " ", "\t", "\r", "\n", "\f", "\0" # Ignore whitespace next when 'z' if count == 0 # Expand z to 0-word result << 0 else raise(Ascii85::DecodingError, "Found 'z' inside Ascii85 5-tuple") end when '!'..'u' # Decode 5 characters into a 4-byte word word += (c - 33) * 85**(4 - count) count += 1 if count == 5 if word > 0xffffffff raise(Ascii85::DecodingError, "Invalid Ascii85 5-tuple (#{word} >= 2**32)") end result << word word = 0 count = 0 end else raise(Ascii85::DecodingError, "Illegal character inside Ascii85: #{c.chr.dump}") end end # Convert result into a String result = result.pack('N*') if count > 0 # Finish last, partially decoded 32-bit-word if count == 1 raise(Ascii85::DecodingError, "Last 5-tuple consists of single character") end count -= 1 word += 85**(4 - count) result << ((word >> 24) & 255).chr if count >= 1 result << ((word >> 16) & 255).chr if count >= 2 result << ((word >> 8) & 255).chr if count == 3 end return result end # # This error is raised when Ascii85.decode encounters one of the following # problems in the input: # # * An invalid character. Valid characters are '!'..'u' and 'z'. # * A 'z' character inside a 5-tuple. 'z's are only valid on their own. # * An invalid 5-tuple that decodes to >= 2**32 # * The last tuple consisting of a single character. Valid tuples always have # at least two characters. # class DecodingError < StandardError; end end Ascii85-1.0.3/lib/Ascii85/0000755000004100000410000000000013306475405014732 5ustar www-datawww-dataAscii85-1.0.3/lib/Ascii85/version.rb0000644000004100000410000000004713306475405016745 0ustar www-datawww-datamodule Ascii85 VERSION = "1.0.3" end Ascii85-1.0.3/Gemfile0000644000004100000410000000013313306475405014247 0ustar www-datawww-datasource "http://rubygems.org" # Specify your gem's dependencies in Ascii85.gemspec gemspec Ascii85-1.0.3/Ascii85.gemspec0000644000004100000410000000176613306475405015543 0ustar www-datawww-data# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "Ascii85/version" Gem::Specification.new do |s| s.name = "Ascii85" s.version = Ascii85::VERSION s.platform = Gem::Platform::RUBY s.author = "Johannes Holzfuß" s.email = "johannes@holzfuss.name" s.license = 'MIT' s.homepage = "https://github.com/DataWraith/ascii85gem/" s.summary = %q{Ascii85 encoder/decoder} s.description = %q{Ascii85 provides methods to encode/decode Adobe's binary-to-text encoding of the same name.} s.add_development_dependency "bundler", ">= 1.0.0" s.add_development_dependency "minitest",">= 2.6.0" s.add_development_dependency "rake", ">= 0.9.2" s.files = `git ls-files`.split("\n") - ['.gitignore'] s.test_files = `git ls-files -- spec/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] s.extra_rdoc_files = ['README.md', 'LICENSE'] end