base85 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 328dd90db168fa41b46bfe68fbee1fecf63547fa31cdae25a9405753c58cb8f3
4
- data.tar.gz: 631040e522c72ec2191b709d024334f98a0c1caf1a71067ae3c63563d4eedc6b
3
+ metadata.gz: 4f8a6088b3843d55dae49087d58126a5527c36804fbcee912db569db9950ab40
4
+ data.tar.gz: 5da6748b35556b5723052547d4c10cc0e55a5c1f85ab88f29df32760e164c4ce
5
5
  SHA512:
6
- metadata.gz: 74fd0e3d3a76477ae6598e6665499150b3c874dc2e052d9797dc884a82a4736724a28647a16f7873cf502d8893f733b22b0cafb544097090de1ece7d81f0c6f2
7
- data.tar.gz: 7d34cdcd2606ad5ed01f95875c4b1b3d183af6855dd0fda9f543fe179c63ac0d556f4ac500765f8b5cfd55bf3eacb762aece0f87bb29991d5721c42273ae220b
6
+ metadata.gz: 6e63afeb1c585b407dc2bb154ecc1a363e28919b7a354a9ae1c355293c5ed7b3e91c51a98f4adc8bd88c84391f47b4ccf825a545017a96fbb263d0863e5935c9
7
+ data.tar.gz: d0e243fb0f19e05733836879cb47577b0127439e5145f5e11939eb3fab34837ebcba486681061a3f2a53cb8c5d3a161bac73e11b4184a64e937a3c46b749e738
data/.rubocop.yml CHANGED
@@ -10,6 +10,9 @@ AllCops:
10
10
  Layout/LineLength:
11
11
  Max: 120
12
12
 
13
+ Metrics/MethodLength:
14
+ Max: 20
15
+
13
16
  RSpec/DescribedClass:
14
17
  Enabled: false
15
18
 
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
- ## [Unreleased]
1
+ # Changelog
2
+
3
+ ## [0.2.0] - 20025-06-25
4
+
5
+ - Add Z85 and RFC1924 alphabets
2
6
 
3
7
  ## [0.1.0] - 2025-06-14
4
8
 
data/README.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  Base85 is a pure Ruby gem to encode/decode data using Base85 encoding.
4
4
 
5
+ It handles mulitple alphabets:
6
+
7
+ * standard (original) one,
8
+ * Z85 from [ZeroMQ](https://github.com/zeromq/libzmq),
9
+ * [RFC1924](https://www.rfc-editor.org/rfc/rfc1924).
10
+
5
11
  ## Installation
6
12
 
7
13
  Install the gem and add to the application's Gemfile by executing:
@@ -19,7 +25,15 @@ To encode a string:
19
25
  ```ruby
20
26
  require "base85"
21
27
 
28
+ # Use standard alphabet
22
29
  Base85.encode("test1") #=> "FCfN80`"
30
+ Base85.encode("test1", alphabet: :standard) #=> "FCfN80`"
31
+
32
+ # Use Z85 alphabet
33
+ Base85.encode("test1", alphabet: :z85) #=> "By/Jnf-"
34
+
35
+ # Use RFC1924 alphabet
36
+ Base85.encode("test1", alphabet: :rfc1924) #=> "bY*jNF#"
23
37
  ```
24
38
 
25
39
  To decode a string:
@@ -27,7 +41,15 @@ To decode a string:
27
41
  ```ruby
28
42
  require "base85"
29
43
 
30
- Base85.decode("!!!!!") #=> "\u0000\u0000\u0000\u0000"
44
+ # Use standard alphabet
45
+ Base85.decode("ASu!rA7]9") #=> "encoded"
46
+ Base85.decode("ASu!rA7]9", alphabet: :standard) #=> "encoded"
47
+
48
+ # Use Z85 alphabet
49
+ Base85.decode("wO#0@wmYo", alphabet: :z85) #=> "encoded"
50
+
51
+ # Use RFC1924 alphabet
52
+ Base85.decode("Wo~0{WMyO", alphabet: :rfc1924) #=> "encoded"
31
53
  ```
32
54
 
33
55
  ## Development
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Base85
4
+ # Module handling common module methods to all encodings
5
+ # @author sd77
6
+ module ModuleMethods
7
+ # @private
8
+ LUT = (0..4).map { |count| 85**(4 - count) }.freeze
9
+
10
+ # @private
11
+ # Encode a single word
12
+ # @param [Integer] word
13
+ # @param [Integer] byte_count byte count of word. Must be in range 1..4
14
+ def encode_word(word, byte_count: 4)
15
+ encoded = "~" * 5
16
+ 5.times do |i|
17
+ word, r = word.divmod(85)
18
+ encoded[-i - 1] = encode_value(r)
19
+ end
20
+ encoded[..byte_count]
21
+ end
22
+
23
+ # Encode data using standard base85 encoding
24
+ # @param [String] data
25
+ # @return [String]
26
+ def encode(data)
27
+ result = +""
28
+ data.unpack("N*").each do |word|
29
+ result << encode_word(word)
30
+ end
31
+
32
+ last_count = data.length % 4
33
+ return result if last_count.zero?
34
+
35
+ last_chars = data[-last_count..] << ("\x00" * (4 - last_count))
36
+ result << encode_word(last_chars.unpack1("N"), byte_count: last_count)
37
+ end
38
+
39
+ # Decode data using standard base85 encoding
40
+ # @param [String] data
41
+ # @return [String]
42
+ # @raise [DecodeError] unknown character or invalid tuple
43
+ def decode(data)
44
+ result = +""
45
+ word = 0
46
+ count = 0
47
+ data.each_char do |c|
48
+ idx = decode_char(c)
49
+ p c if idx.nil?
50
+
51
+ word += idx * LUT[count]
52
+ count += 1
53
+
54
+ if (count == 5) && (word > 0xffffffff)
55
+ raise DecodeError, "invalid tuple"
56
+ elsif count == 5
57
+ wordbuf = " " * 4
58
+ 3.downto(0) do |i|
59
+ wordbuf.setbyte(i, word & 0xff)
60
+ word >>= 8
61
+ end
62
+ result << wordbuf
63
+ count = 0
64
+ word = 0
65
+ end
66
+ end
67
+
68
+ return result if count.zero?
69
+
70
+ count -= 1
71
+ word += LUT[count]
72
+ result << ((word >> 24) & 0xff).chr if count >= 1
73
+ result << ((word >> 16) & 0xff).chr if count >= 2
74
+ result << ((word >> 8) & 0xff).chr if count == 3
75
+ result
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Base85
4
+ # RFC 1924 base85 encoding
5
+ # # @author sd77
6
+ module Rfc1924
7
+ extend ModuleMethods
8
+
9
+ # RFC1924 alphabet
10
+ ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
11
+
12
+ # Encode a value (0..84 integer) to a RFC 1924 character
13
+ # @param [Integer] value
14
+ # @return [String]
15
+ def self.encode_value(value)
16
+ ALPHABET[value]
17
+ end
18
+
19
+ # Decode a character from RFC 1924 alphabet and give its index in alphabet
20
+ # @param [String] char a acharacter from base85 alphabet
21
+ # @return [Integer] index of this character in alphabet
22
+ # @raise DecodeError +char+ is not known in alphabet
23
+ def self.decode_char(char)
24
+ case char
25
+ when "0".."9"
26
+ char.ord - 48
27
+ when "A".."Z"
28
+ char.ord - 55 # - 65 + 10
29
+ when "a".."z"
30
+ char.ord - 61 # - 97 + 36
31
+ when "!", "#".."&", "(".."+", "-", ";".."@", "^".."`", "{".."~"
32
+ ALPHABET.index(char)
33
+ else
34
+ raise DecodeError, "unknown character '#{char}'"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -4,81 +4,29 @@ module Base85
4
4
  # Standard base85 encoding. This encoding uses '!' to 'u' ASCII characters to encode data.
5
5
  # @author sd77
6
6
  module Standard
7
+ extend ModuleMethods
8
+
7
9
  # ASCII value for character '!'
8
10
  BASE_ASCII_VALUE = "!".ord
9
- # @private
10
- LUT = (0..4).map { |count| 85**(4 - count) }.freeze
11
-
12
- # @private
13
- # Encode a single word
14
- # @param [Integer] word
15
- # @param [Integer] byte_count byte count of word. Must be in range 1..4
16
- def self.encode_word(word, byte_count: 4)
17
- encoded = "~" * 5
18
- 5.times do |i|
19
- word, r = word.divmod(85)
20
- encoded[-i - 1] = (BASE_ASCII_VALUE + r).chr
21
- end
22
- encoded[..byte_count]
23
- end
24
11
 
25
- # Encode data using standard base85 encoding
26
- # @param [String] data
12
+ # Encode a value (0..84 integer) to a standard base85 character
13
+ # @param [Integer] value
27
14
  # @return [String]
28
- def self.encode(data)
29
- result = +""
30
- data.unpack("N*").each do |word|
31
- result << encode_word(word)
32
- end
33
-
34
- last_count = data.length % 4
35
- return result if last_count.zero?
36
-
37
- last_chars = data[-last_count..] << ("\x00" * (4 - last_count))
38
- result << encode_word(last_chars.unpack1("N"), byte_count: last_count)
15
+ def self.encode_value(value)
16
+ (BASE_ASCII_VALUE + value).chr
39
17
  end
40
18
 
41
- # Decode data using standard base85 encoding
42
- # @param [String] data
43
- # @return [String]
44
- # @raise [DecodeError] unknown character or invalid tuple
45
- def self.decode(data)
46
- result = +""
47
- word = 0
48
- count = 0
49
- data.each_char do |c|
50
- case c
51
- when "!".."u" # rubocop:disable Lint/MixedCaseRange
52
- idx = c.ord - BASE_ASCII_VALUE
53
- else
54
- raise DecodeError, "unknown character '#{c}'"
55
- end
56
-
57
- word += idx * LUT[count]
58
- count += 1
59
-
60
- if (count == 5) && (word > 0xffffffff)
61
- raise DecodeError, "invalid tuple"
62
- elsif count == 5
63
- wordbuf = " " * 4
64
- 3.downto(0) do |i|
65
- wordbuf.setbyte(i, word & 0xff)
66
- word >>= 8
67
- end
68
- result << wordbuf
69
- count = 0
70
- word = 0
71
- end
19
+ # Decode a character from standard base85 and give its index in alphabet
20
+ # @param [String] char a acharacter from base85 alphabet
21
+ # @return [Integer] index of this character in alphabet
22
+ # @raise DecodeError +char+ is not known in alphabet
23
+ def self.decode_char(char)
24
+ case char
25
+ when "!".."u" # rubocop:disable Lint/MixedCaseRange
26
+ char.ord - BASE_ASCII_VALUE
27
+ else
28
+ raise DecodeError, "unknown character '#{char}'"
72
29
  end
73
-
74
- return result if count.zero?
75
-
76
- count -= 1
77
- word += LUT[count]
78
- result << ((word >> 24) & 0xff).chr if count >= 1
79
- result << ((word >> 16) & 0xff).chr if count >= 2
80
- result << ((word >> 8) & 0xff).chr if count == 3
81
- result
82
30
  end
83
31
  end
84
32
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Base85
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/base85/z85.rb ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Base85
4
+ # ZeroMQ (Z85) encoding
5
+ module Z85
6
+ extend ModuleMethods
7
+
8
+ # Z85 alphabet
9
+ ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#"
10
+
11
+ # Encode a value (0..84 integer) to a Z85 character
12
+ # @param [Integer] value
13
+ # @return [String]
14
+ def self.encode_value(value)
15
+ ALPHABET[value]
16
+ end
17
+
18
+ # Decode a character from Z85 and give its index in alphabet
19
+ # @param [String] char a acharacter from base85 alphabet
20
+ # @return [Integer] index of this character in alphabet
21
+ # @raise DecodeError +char+ is not known in alphabet
22
+ def self.decode_char(char)
23
+ case char
24
+ when "0".."9"
25
+ char.ord - 48
26
+ when "a".."z"
27
+ char.ord - 87 # - 97 + 10
28
+ when "A".."Z"
29
+ char.ord - 29 # - 65 + 26
30
+ when "!", "#".."&", "(".."+", "-".."/", ":", "<".."@", "[", "]", "^", "{".."}"
31
+ ALPHABET.index(char)
32
+ else
33
+ raise DecodeError, "unknown character '#{char}'"
34
+ end
35
+ end
36
+ end
37
+ end
data/lib/base85.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "base85/version"
4
+ require_relative "base85/module_methods"
4
5
  require_relative "base85/standard"
6
+ require_relative "base85/z85"
7
+ require_relative "base85/rfc1924"
5
8
 
6
9
  # Provide methods to encode/decode Base85 formatted data
7
10
  # @author sd77
@@ -31,6 +34,10 @@ module Base85
31
34
  case alphabet
32
35
  when :standard
33
36
  Standard.encode(data)
37
+ when :z85
38
+ Z85.encode(data)
39
+ when :rfc1924
40
+ Rfc1924.encode(data)
34
41
  else
35
42
  raise UnknownAlphabetError.new(alphabet)
36
43
  end
@@ -40,6 +47,10 @@ module Base85
40
47
  case alphabet
41
48
  when :standard
42
49
  Standard.decode(data)
50
+ when :z85
51
+ Z85.decode(data)
52
+ when :rfc1924
53
+ Rfc1924.decode(data)
43
54
  else
44
55
  raise UnknownAlphabetError.new(alphabet)
45
56
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: base85
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sd77
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-06-14 00:00:00.000000000 Z
11
+ date: 2025-06-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Encode and decode base85 data. Multiple alphabets are supported (standard,
14
14
  Z85 or rfc1924)
@@ -25,8 +25,11 @@ files:
25
25
  - README.md
26
26
  - Rakefile
27
27
  - lib/base85.rb
28
+ - lib/base85/module_methods.rb
29
+ - lib/base85/rfc1924.rb
28
30
  - lib/base85/standard.rb
29
31
  - lib/base85/version.rb
32
+ - lib/base85/z85.rb
30
33
  - sig/base85.rbs
31
34
  homepage: https://codeberg.org/sd77/base85
32
35
  licenses: