From c9aa8f7a12bbfcdc1a93b7108fd7c17b4d8b304d Mon Sep 17 00:00:00 2001 From: Oskar Eichler Date: Fri, 28 Aug 2026 01:30:11 +0300 Subject: [PATCH] Correct Base64 encoding and decoding documentation examples --- lib/base64.rb | 60 +++++++++++++++++++++++----------------------- sig/base64.rbs | 64 ++++++++++++++++++++++++++------------------------ 2 files changed, 64 insertions(+), 60 deletions(-) diff --git a/lib/base64.rb b/lib/base64.rb index 279e6cd..d5db0c7 100644 --- a/lib/base64.rb +++ b/lib/base64.rb @@ -12,7 +12,7 @@ # - Images in HTML or CSS files, or in URLs. # - Email attachments. # -# A \Base64-encoded string is about one-third larger that its source. +# A \Base64-encoded string is about one-third larger than its source. # See the {Wikipedia article}[https://en.wikipedia.org/wiki/Base64] # for more information. # @@ -29,7 +29,7 @@ # # == \Encoding Character Sets # -# A \Base64-encoded string consists only of characters from a 64-character set: +# A \Base64-encoded string uses the following characters: # # - ('A'..'Z'). # - ('a'..'z'). @@ -71,62 +71,62 @@ # Base64.urlsafe_encode64('s') # => "cw==" # Base64.urlsafe_encode64('s', padding: false) # => "cw" # -# When padding is performed, the encoded string is always of length 4n, +# Ignoring newlines, when padding is performed the encoded string is of length 4n, # where +n+ is a non-negative integer: # # - Input bytes of length 3n generate unpadded output characters # of length 4n: # # # n = 1: 3 bytes => 4 characters. -# Base64.strict_encode64('123') # => "MDEy" +# Base64.strict_encode64('123') # => "MTIz" # # n = 2: 6 bytes => 8 characters. -# Base64.strict_encode64('123456') # => "MDEyMzQ1" +# Base64.strict_encode64('123456') # => "MTIzNDU2" # # - Input bytes of length 3n+1 generate padded output characters # of length 4(n+1), with two padding characters at the end: # # # n = 1: 4 bytes => 8 characters. -# Base64.strict_encode64('1234') # => "MDEyMw==" +# Base64.strict_encode64('1234') # => "MTIzNA==" # # n = 2: 7 bytes => 12 characters. -# Base64.strict_encode64('1234567') # => "MDEyMzQ1Ng==" +# Base64.strict_encode64('1234567') # => "MTIzNDU2Nw==" # # - Input bytes of length 3n+2 generate padded output characters # of length 4(n+1), with one padding character at the end: # # # n = 1: 5 bytes => 8 characters. -# Base64.strict_encode64('12345') # => "MDEyMzQ=" +# Base64.strict_encode64('12345') # => "MTIzNDU=" # # n = 2: 8 bytes => 12 characters. -# Base64.strict_encode64('12345678') # => "MDEyMzQ1Njc=" +# Base64.strict_encode64('12345678') # => "MTIzNDU2Nzg=" # -# When padding is suppressed, for a positive integer n: +# When padding is suppressed, for a non-negative integer n: # # - Input bytes of length 3n generate unpadded output characters # of length 4n: # # # n = 1: 3 bytes => 4 characters. -# Base64.urlsafe_encode64('123', padding: false) # => "MDEy" +# Base64.urlsafe_encode64('123', padding: false) # => "MTIz" # # n = 2: 6 bytes => 8 characters. -# Base64.urlsafe_encode64('123456', padding: false) # => "MDEyMzQ1" +# Base64.urlsafe_encode64('123456', padding: false) # => "MTIzNDU2" # # - Input bytes of length 3n+1 generate unpadded output characters -# of length 4n+2, with two padding characters at the end: +# of length 4n+2, with no padding characters: # # # n = 1: 4 bytes => 6 characters. -# Base64.urlsafe_encode64('1234', padding: false) # => "MDEyMw" +# Base64.urlsafe_encode64('1234', padding: false) # => "MTIzNA" # # n = 2: 7 bytes => 10 characters. -# Base64.urlsafe_encode64('1234567', padding: false) # => "MDEyMzQ1Ng" +# Base64.urlsafe_encode64('1234567', padding: false) # => "MTIzNDU2Nw" # # - Input bytes of length 3n+2 generate unpadded output characters -# of length 4n+3, with one padding character at the end: +# of length 4n+3, with no padding characters: # # # n = 1: 5 bytes => 7 characters. -# Base64.urlsafe_encode64('12345', padding: false) # => "MDEyMzQ" -# # m = 2: 8 bytes => 11 characters. -# Base64.urlsafe_encode64('12345678', padding: false) # => "MDEyMzQ1Njc" +# Base64.urlsafe_encode64('12345', padding: false) # => "MTIzNDU" +# # n = 2: 8 bytes => 11 characters. +# Base64.urlsafe_encode64('12345678', padding: false) # => "MTIzNDU2Nzg" # # Padding in Decode Methods # -# All of the \Base64 decode methods support (but do not require) padding. +# All of the \Base64 decode methods support padded input; their acceptance of unpadded input differs. # # \Method Base64.decode64 does not check the size of the padding: # @@ -160,17 +160,17 @@ # # # Newline at end of short output. # encoded = Base64.encode64("\x00" * 1) -# encoded.size # => 4 +# encoded.size # => 5 # encoded.index("\n") # => 4 # # # Newline at end of longer output. # encoded = Base64.encode64("\x00" * 45) -# encoded.size # => 60 +# encoded.size # => 61 # encoded.index("\n") # => 60 # # # Newlines embedded and at end of still longer output. # encoded = Base64.encode64("\x00" * 46) -# encoded.size # => 65 +# encoded.size # => 66 # encoded.rindex("\n") # => 65 # encoded.split("\n").map {|s| s.size } # => [60, 4] # @@ -235,7 +235,7 @@ def encode64(bin) # # Non-\Base64 characters in +encoded_string+ are ignored; # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: - # these include newline characters and characters - and /: + # these include newline characters and characters - and _: # # Base64.decode64("\x00\n-_") # => "" # @@ -295,7 +295,7 @@ def strict_encode64(bin) # # Non-\Base64 characters in +encoded_string+ are not allowed; # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: - # these include newline characters and characters - and /: + # these include newline characters and characters - and _: # # Base64.strict_decode64("\n") # Raises ArgumentError # Base64.strict_decode64('-') # Raises ArgumentError @@ -353,11 +353,13 @@ def urlsafe_encode64(bin, padding: true) # # Returns the decoding of an RFC-4648-compliant \Base64-encoded string +encoded_string+: # - # +encoded_string+ may not contain non-Base64 characters; - # see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above: + # Both the URL-safe alphabet (- and _) and the standard + # alphabet (+ and /) are accepted, including mixed input. + # Other non-Base64 characters, including newlines, are rejected: # - # Base64.urlsafe_decode64('+') # Raises ArgumentError. - # Base64.urlsafe_decode64('/') # Raises ArgumentError. + # Base64.urlsafe_decode64('____') # => "\xFF\xFF\xFF" + # Base64.urlsafe_decode64('////') # => "\xFF\xFF\xFF" + # Base64.urlsafe_decode64('_/8=') # => "\xFF\xFF" # Base64.urlsafe_decode64("\n") # Raises ArgumentError. # # Padding in +encoded_string+, if present, must be correct: diff --git a/sig/base64.rbs b/sig/base64.rbs index fbe6695..a526d67 100644 --- a/sig/base64.rbs +++ b/sig/base64.rbs @@ -11,7 +11,7 @@ # * Images in HTML or CSS files, or in URLs. # * Email attachments. # -# A Base64-encoded string is about one-third larger that its source. See the +# A Base64-encoded string is about one-third larger than its source. See the # [Wikipedia article](https://en.wikipedia.org/wiki/Base64) for more # information. # @@ -28,7 +28,7 @@ # # ## Encoding Character Sets # -# A Base64-encoded string consists only of characters from a 64-character set: +# A Base64-encoded string uses the following characters: # # * ('A'..'Z'). # * ('a'..'z'). @@ -70,62 +70,63 @@ # Base64.urlsafe_encode64('s') # => "cw==" # Base64.urlsafe_encode64('s', padding: false) # => "cw" # -# When padding is performed, the encoded string is always of length *4n*, where -# `n` is a non-negative integer: +# Ignoring newlines, when padding is performed the encoded string is of length +# *4n*, where `n` is a non-negative integer: # # * Input bytes of length *3n* generate unpadded output characters of length # *4n*: # # # n = 1: 3 bytes => 4 characters. -# Base64.strict_encode64('123') # => "MDEy" +# Base64.strict_encode64('123') # => "MTIz" # # n = 2: 6 bytes => 8 characters. -# Base64.strict_encode64('123456') # => "MDEyMzQ1" +# Base64.strict_encode64('123456') # => "MTIzNDU2" # # * Input bytes of length 3n+1 generate padded output characters of # length 4(n+1), with two padding characters at the end: # # # n = 1: 4 bytes => 8 characters. -# Base64.strict_encode64('1234') # => "MDEyMw==" +# Base64.strict_encode64('1234') # => "MTIzNA==" # # n = 2: 7 bytes => 12 characters. -# Base64.strict_encode64('1234567') # => "MDEyMzQ1Ng==" +# Base64.strict_encode64('1234567') # => "MTIzNDU2Nw==" # # * Input bytes of length 3n+2 generate padded output characters of # length 4(n+1), with one padding character at the end: # # # n = 1: 5 bytes => 8 characters. -# Base64.strict_encode64('12345') # => "MDEyMzQ=" +# Base64.strict_encode64('12345') # => "MTIzNDU=" # # n = 2: 8 bytes => 12 characters. -# Base64.strict_encode64('12345678') # => "MDEyMzQ1Njc=" +# Base64.strict_encode64('12345678') # => "MTIzNDU2Nzg=" # -# When padding is suppressed, for a positive integer *n*: +# When padding is suppressed, for a non-negative integer *n*: # # * Input bytes of length *3n* generate unpadded output characters of length # *4n*: # # # n = 1: 3 bytes => 4 characters. -# Base64.urlsafe_encode64('123', padding: false) # => "MDEy" +# Base64.urlsafe_encode64('123', padding: false) # => "MTIz" # # n = 2: 6 bytes => 8 characters. -# Base64.urlsafe_encode64('123456', padding: false) # => "MDEyMzQ1" +# Base64.urlsafe_encode64('123456', padding: false) # => "MTIzNDU2" # # * Input bytes of length 3n+1 generate unpadded output characters of -# length 4n+2, with two padding characters at the end: +# length 4n+2, with no padding characters: # # # n = 1: 4 bytes => 6 characters. -# Base64.urlsafe_encode64('1234', padding: false) # => "MDEyMw" +# Base64.urlsafe_encode64('1234', padding: false) # => "MTIzNA" # # n = 2: 7 bytes => 10 characters. -# Base64.urlsafe_encode64('1234567', padding: false) # => "MDEyMzQ1Ng" +# Base64.urlsafe_encode64('1234567', padding: false) # => "MTIzNDU2Nw" # # * Input bytes of length 3n+2 generate unpadded output characters of -# length 4n+3, with one padding character at the end: +# length 4n+3, with no padding characters: # # # n = 1: 5 bytes => 7 characters. -# Base64.urlsafe_encode64('12345', padding: false) # => "MDEyMzQ" -# # m = 2: 8 bytes => 11 characters. -# Base64.urlsafe_encode64('12345678', padding: false) # => "MDEyMzQ1Njc" +# Base64.urlsafe_encode64('12345', padding: false) # => "MTIzNDU" +# # n = 2: 8 bytes => 11 characters. +# Base64.urlsafe_encode64('12345678', padding: false) # => "MTIzNDU2Nzg" # # **Padding in Decode Methods** # -# All of the Base64 decode methods support (but do not require) padding. +# All of the Base64 decode methods support padded input; their acceptance of +# unpadded input differs. # # Method Base64.decode64 does not check the size of the padding: # @@ -158,17 +159,17 @@ # # # Newline at end of short output. # encoded = Base64.encode64("\x00" * 1) -# encoded.size # => 4 +# encoded.size # => 5 # encoded.index("\n") # => 4 # # # Newline at end of longer output. # encoded = Base64.encode64("\x00" * 45) -# encoded.size # => 60 +# encoded.size # => 61 # encoded.index("\n") # => 60 # # # Newlines embedded and at end of still longer output. # encoded = Base64.encode64("\x00" * 46) -# encoded.size # => 65 +# encoded.size # => 66 # encoded.rindex("\n") # => 65 # encoded.split("\n").map {|s| s.size } # => [60, 4] # @@ -192,7 +193,7 @@ module Base64 # # Non-Base64 characters in `encoded_string` are ignored; see [Encoding Character # Set](Base64.html#module-Base64-label-Encoding+Character+Sets) above: these - # include newline characters and characters - and /: + # include newline characters and characters - and `_`: # # Base64.decode64("\x00\n-_") # => "" # @@ -252,8 +253,7 @@ module Base64 # # Non-Base64 characters in `encoded_string` are not allowed; see [Encoding # Character Set](Base64.html#module-Base64-label-Encoding+Character+Sets) above: - # these include newline characters and characters - and - # /: + # these include newline characters and characters - and `_`: # # Base64.strict_decode64("\n") # Raises ArgumentError # Base64.strict_decode64('-') # Raises ArgumentError @@ -309,11 +309,13 @@ module Base64 # Returns the decoding of an RFC-4648-compliant Base64-encoded string # `encoded_string`: # - # `encoded_string` may not contain non-Base64 characters; see [Encoding - # Character Set](Base64.html#module-Base64-label-Encoding+Character+Sets) above: + # Both the URL-safe alphabet (- and `_`) and the standard alphabet + # (+ and /) are accepted, including mixed input. Other + # non-Base64 characters, including newlines, are rejected: # - # Base64.urlsafe_decode64('+') # Raises ArgumentError. - # Base64.urlsafe_decode64('/') # Raises ArgumentError. + # Base64.urlsafe_decode64('____') # => "\xFF\xFF\xFF" + # Base64.urlsafe_decode64('////') # => "\xFF\xFF\xFF" + # Base64.urlsafe_decode64('_/8=') # => "\xFF\xFF" # Base64.urlsafe_decode64("\n") # Raises ArgumentError. # # Padding in `encoded_string`, if present, must be correct: see