safely sent by email, used as parts of URLs, or included as part of an HTTP
POST request.
-.. function:: b64encode(s, altchars=None, *, wrapcol=0)
+.. function:: b64encode(s, altchars=None, *, padded=True, wrapcol=0)
Encode the :term:`bytes-like object` *s* using Base64 and return the encoded
:class:`bytes`.
This allows an application to e.g. generate URL or filesystem safe Base64
strings. The default is ``None``, for which the standard Base64 alphabet is used.
+ If *padded* is true (default), pad the encoded data with the '='
+ character to a size multiple of 4.
+ If *padded* is false, do not add the pad characters.
+
If *wrapcol* is non-zero, insert a newline (``b'\n'``) character
after at most every *wrapcol* characters.
If *wrapcol* is zero (default), do not insert any newlines.
:exc:`TypeError` if *altchars* is not a :term:`bytes-like object`.
.. versionchanged:: 3.15
- Added the *wrapcol* parameter.
+ Added the *padded* and *wrapcol* parameters.
-.. function:: b64decode(s, altchars=None, validate=False)
- b64decode(s, altchars=None, validate=True, *, ignorechars)
+.. function:: b64decode(s, altchars=None, validate=False, *, padded=True)
+ b64decode(s, altchars=None, validate=True, *, ignorechars, padded=True)
Decode the Base64 encoded :term:`bytes-like object` or ASCII string
*s* and return the decoded :class:`bytes`.
of length 2 which specifies the alternative alphabet used instead of the
``+`` and ``/`` characters.
+ If *padded* is true, the last group of 4 base 64 alphabet characters must
+ be padded with the '=' character.
+ If *padded* is false, the '=' character is treated as other non-alphabet
+ characters (depending on the value of *validate* and *ignorechars*).
+
A :exc:`binascii.Error` exception is raised
if *s* is incorrectly padded.
For more information about the strict base64 check, see :func:`binascii.a2b_base64`
.. versionchanged:: 3.15
- Added the *ignorechars* parameter.
+ Added the *ignorechars* and *padded* parameters.
.. deprecated:: 3.15
Accepting the ``+`` and ``/`` characters with an alternative alphabet
Base64 alphabet and return the decoded :class:`bytes`.
-.. function:: urlsafe_b64encode(s)
+.. function:: urlsafe_b64encode(s, *, padded=True)
Encode :term:`bytes-like object` *s* using the
URL- and filesystem-safe alphabet, which
substitutes ``-`` instead of ``+`` and ``_`` instead of ``/`` in the
standard Base64 alphabet, and return the encoded :class:`bytes`. The result
- can still contain ``=``.
+ can still contain ``=`` if *padded* is true (default).
+
+ .. versionchanged:: next
+ Added the *padded* parameter.
-.. function:: urlsafe_b64decode(s)
+.. function:: urlsafe_b64decode(s, *, padded=False)
Decode :term:`bytes-like object` or ASCII string *s*
using the URL- and filesystem-safe
``/`` in the standard Base64 alphabet, and return the decoded
:class:`bytes`.
+ .. versionchanged:: next
+ Added the *padded* parameter.
+ Padding of input is no longer required by default.
+
.. deprecated:: 3.15
Accepting the ``+`` and ``/`` characters is now deprecated.
-.. function:: b32encode(s, *, wrapcol=0)
+.. function:: b32encode(s, *, padded=True, wrapcol=0)
Encode the :term:`bytes-like object` *s* using Base32 and return the
encoded :class:`bytes`.
+ If *padded* is true (default), pad the encoded data with the '='
+ character to a size multiple of 8.
+ If *padded* is false, do not add the pad characters.
+
If *wrapcol* is non-zero, insert a newline (``b'\n'``) character
after at most every *wrapcol* characters.
If *wrapcol* is zero (default), do not add any newlines.
.. versionchanged:: next
- Added the *wrapcol* parameter.
+ Added the *padded* and *wrapcol* parameters.
-.. function:: b32decode(s, casefold=False, map01=None, *, ignorechars=b'')
+.. function:: b32decode(s, casefold=False, map01=None, *, padded=True, ignorechars=b'')
Decode the Base32 encoded :term:`bytes-like object` or ASCII string *s* and
return the decoded :class:`bytes`.
digit 0 is always mapped to the letter O). For security purposes the default is
``None``, so that 0 and 1 are not allowed in the input.
+ If *padded* is true, the last group of 8 base 32 alphabet characters must
+ be padded with the '=' character.
+ If *padded* is false, the '=' character is treated as other non-alphabet
+ characters (depending on the value of *ignorechars*).
+
*ignorechars* should be a :term:`bytes-like object` containing characters
to ignore from the input.
input.
.. versionchanged:: next
- Added the *ignorechars* parameter.
+ Added the *ignorechars* and *padded* parameters.
-.. function:: b32hexencode(s, *, wrapcol=0)
+.. function:: b32hexencode(s, *, padded=True, wrapcol=0)
Similar to :func:`b32encode` but uses the Extended Hex Alphabet, as defined in
:rfc:`4648`.
.. versionadded:: 3.10
.. versionchanged:: next
- Added the *wrapcol* parameter.
+ Added the *padded* and *wrapcol* parameters.
-.. function:: b32hexdecode(s, casefold=False, *, ignorechars=b'')
+.. function:: b32hexdecode(s, casefold=False, *, padded=True, ignorechars=b'')
Similar to :func:`b32decode` but uses the Extended Hex Alphabet, as defined in
:rfc:`4648`.
.. versionadded:: 3.10
.. versionchanged:: next
- Added the *ignorechars* parameter.
+ Added the *ignorechars* and *padded* parameters.
.. function:: b16encode(s, *, wrapcol=0)
Added the *backtick* parameter.
-.. function:: a2b_base64(string, /, *, alphabet=BASE64_ALPHABET, strict_mode=False)
- a2b_base64(string, /, *, ignorechars, alphabet=BASE64_ALPHABET, strict_mode=True)
+.. function:: a2b_base64(string, /, *, padded=True, alphabet=BASE64_ALPHABET, strict_mode=False)
+ a2b_base64(string, /, *, ignorechars, padded=True, alphabet=BASE64_ALPHABET, strict_mode=True)
Convert a block of base64 data back to binary and return the binary data. More
than one line may be passed at a time.
Optional *alphabet* must be a :class:`bytes` object of length 64 which
specifies an alternative alphabet.
+ If *padded* is true, the last group of 4 base 64 alphabet characters must
+ be padded with the '=' character.
+ If *padded* is false, the '=' character is treated as other non-alphabet
+ characters (depending on the value of *strict_mode* and *ignorechars*).
+
If *ignorechars* is specified, it should be a :term:`bytes-like object`
containing characters to ignore from the input when *strict_mode* is true.
If *ignorechars* contains the pad character ``'='``, the pad characters
Added the *strict_mode* parameter.
.. versionchanged:: 3.15
- Added the *alphabet* and *ignorechars* parameters.
+ Added the *alphabet*, *ignorechars* and *padded* parameters.
-.. function:: b2a_base64(data, *, alphabet=BASE64_ALPHABET, wrapcol=0, newline=True)
+.. function:: b2a_base64(data, *, padded=True, alphabet=BASE64_ALPHABET, wrapcol=0, newline=True)
Convert binary data to a line(s) of ASCII characters in base64 coding,
as specified in :rfc:`4648`.
+ If *padded* is true (default), pad the encoded data with the '='
+ character to a size multiple of 4.
+ If *padded* is false, do not add the pad characters.
+
If *wrapcol* is non-zero, insert a newline (``b'\n'``) character
after at most every *wrapcol* characters.
If *wrapcol* is zero (default), do not insert any newlines.
Added the *newline* parameter.
.. versionchanged:: 3.15
- Added the *alphabet* and *wrapcol* parameters.
+ Added the *alphabet*, *padded* and *wrapcol* parameters.
.. function:: a2b_ascii85(string, /, *, foldspaces=False, adobe=False, ignorechars=b'')
.. versionadded:: 3.15
-.. function:: a2b_base32(string, /, *, alphabet=BASE32_ALPHABET, ignorechars=b'')
+.. function:: a2b_base32(string, /, *, padded=True, alphabet=BASE32_ALPHABET, ignorechars=b'')
Convert base32 data back to binary and return the binary data.
Optional *alphabet* must be a :class:`bytes` object of length 32 which
specifies an alternative alphabet.
+ If *padded* is true, the last group of 8 base 32 alphabet characters must
+ be padded with the '=' character.
+ If *padded* is false, the '=' character is treated as other non-alphabet
+ characters (depending on the value of *ignorechars*).
+
*ignorechars* should be a :term:`bytes-like object` containing characters
to ignore from the input.
If *ignorechars* contains the pad character ``'='``, the pad characters
.. versionadded:: next
-.. function:: b2a_base32(data, /, *, alphabet=BASE32_ALPHABET, wrapcol=0)
+.. function:: b2a_base32(data, /, *, padded=True, alphabet=BASE32_ALPHABET, wrapcol=0)
Convert binary data to a line of ASCII characters in base32 coding,
as specified in :rfc:`4648`. The return value is the converted line.
Optional *alphabet* must be a :term:`bytes-like object` of length 32 which
specifies an alternative alphabet.
+ If *padded* is true (default), pad the encoded data with the '='
+ character to a size multiple of 8.
+ If *padded* is false, do not add the pad characters.
+
If *wrapcol* is non-zero, insert a newline (``b'\n'``) character
after at most every *wrapcol* characters.
If *wrapcol* is zero (default), do not insert any newlines.
* Added the *pad* parameter in :func:`~base64.z85encode`.
(Contributed by Hauke Dämpfling in :gh:`143103`.)
+* Added the *padded* parameter in
+ :func:`~base64.b32encode`, :func:`~base64.b32decode`,
+ :func:`~base64.b32hexencode`, :func:`~base64.b32hexdecode`,
+ :func:`~base64.b64encode`, :func:`~base64.b64decode`,
+ :func:`~base64.urlsafe_b64encode`, and :func:`~base64.urlsafe_b64decode`.
+ (Contributed by Serhiy Storchaka in :gh:`73613`.)
+
* Added the *wrapcol* parameter in :func:`~base64.b16encode`,
:func:`~base64.b32encode`, :func:`~base64.b32hexencode`,
:func:`~base64.b64encode`, :func:`~base64.b85encode`, and
(Contributed by James Seo and Serhiy Storchaka in :gh:`101178`.)
+* Added the *padded* parameter in
+ :func:`~binascii.b2a_base32`, :func:`~binascii.a2b_base32`,
+ :func:`~binascii.b2a_base64`, and :func:`~binascii.a2b_base64`.
+ (Contributed by Serhiy Storchaka in :gh:`73613`.)
+
* Added the *wrapcol* parameter in :func:`~binascii.b2a_base64`.
(Contributed by Serhiy Storchaka in :gh:`143214`.)
*dest* is now ``'foo'`` instead of ``'f'``.
Pass an explicit *dest* argument to preserve the old behavior.
(Contributed by Serhiy Storchaka in :gh:`138697`.)
+
+* Padding of input no longer required in :func:`base64.urlsafe_b64decode`.
+ Pass a new argument ``padded=True`` or use :func:`base64.b64decode`
+ with argument ``altchars=b'-_'`` (this works with older Python versions)
+ to make padding required.
+ (Contributed by Serhiy Storchaka in :gh:`73613`.)
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(overlapped));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(owner));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pad));
+ _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(padded));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(pages));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(parameter));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(parent));
STRUCT_FOR_ID(overlapped)
STRUCT_FOR_ID(owner)
STRUCT_FOR_ID(pad)
+ STRUCT_FOR_ID(padded)
STRUCT_FOR_ID(pages)
STRUCT_FOR_ID(parameter)
STRUCT_FOR_ID(parent)
INIT_ID(overlapped), \
INIT_ID(owner), \
INIT_ID(pad), \
+ INIT_ID(padded), \
INIT_ID(pages), \
INIT_ID(parameter), \
INIT_ID(parent), \
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
+ string = &_Py_ID(padded);
+ _PyUnicode_InternStatic(interp, &string);
+ assert(_PyUnicode_CheckConsistency(string, 1));
+ assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(pages);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
# Base64 encoding/decoding uses binascii
-def b64encode(s, altchars=None, *, wrapcol=0):
+def b64encode(s, altchars=None, *, padded=True, wrapcol=0):
"""Encode the bytes-like object s using Base64 and return a bytes object.
Optional altchars should be a byte string of length 2 which specifies an
alternative alphabet for the '+' and '/' characters. This allows an
application to e.g. generate url or filesystem safe Base64 strings.
+ If padded is false, omit padding in the output.
+
If wrapcol is non-zero, insert a newline (b'\\n') character after at most
every wrapcol characters.
"""
if len(altchars) != 2:
raise ValueError(f'invalid altchars: {altchars!r}')
alphabet = binascii.BASE64_ALPHABET[:-2] + altchars
- return binascii.b2a_base64(s, wrapcol=wrapcol, newline=False,
+ return binascii.b2a_base64(s, padded=padded, wrapcol=wrapcol, newline=False,
alphabet=alphabet)
- return binascii.b2a_base64(s, wrapcol=wrapcol, newline=False)
+ return binascii.b2a_base64(s, padded=padded, wrapcol=wrapcol, newline=False)
-def b64decode(s, altchars=None, validate=_NOT_SPECIFIED, *, ignorechars=_NOT_SPECIFIED):
+def b64decode(s, altchars=None, validate=_NOT_SPECIFIED,
+ *, padded=True, ignorechars=_NOT_SPECIFIED):
"""Decode the Base64 encoded bytes-like object or ASCII string s.
Optional altchars must be a bytes-like object or ASCII string of length 2
which specifies the alternative alphabet used instead of the '+' and '/'
characters.
+ If padded is false, padding in input is not required.
+
The result is returned as a bytes object. A binascii.Error is raised if
s is incorrectly padded.
alphabet = binascii.BASE64_ALPHABET[:-2] + altchars
return binascii.a2b_base64(s, strict_mode=validate,
alphabet=alphabet,
- ignorechars=ignorechars)
+ padded=padded, ignorechars=ignorechars)
if ignorechars is _NOT_SPECIFIED:
ignorechars = b''
result = binascii.a2b_base64(s, strict_mode=validate,
- ignorechars=ignorechars)
+ padded=padded, ignorechars=ignorechars)
if badchar is not None:
import warnings
if validate:
_urlsafe_decode_translation = bytes.maketrans(b'-_', b'+/')
-def urlsafe_b64encode(s):
+def urlsafe_b64encode(s, *, padded=True):
"""Encode bytes using the URL- and filesystem-safe Base64 alphabet.
Argument s is a bytes-like object to encode. The result is returned as a
bytes object. The alphabet uses '-' instead of '+' and '_' instead of
'/'.
+
+ If padded is false, omit padding in the output.
"""
- return binascii.b2a_base64(s, newline=False,
+ return binascii.b2a_base64(s, padded=padded, newline=False,
alphabet=binascii.URLSAFE_BASE64_ALPHABET)
-def urlsafe_b64decode(s):
+def urlsafe_b64decode(s, *, padded=False):
"""Decode bytes using the URL- and filesystem-safe Base64 alphabet.
Argument s is a bytes-like object or ASCII string to decode. The result
alphabet, and are not a plus '+' or slash '/', are discarded prior to the
padding check.
+ If padded is false, padding in input is not required.
+
The alphabet uses '-' instead of '+' and '_' instead of '/'.
"""
s = _bytes_from_decode_data(s)
badchar = b
break
s = s.translate(_urlsafe_decode_translation)
- result = binascii.a2b_base64(s, strict_mode=False)
+ result = binascii.a2b_base64(s, strict_mode=False, padded=padded)
if badchar is not None:
import warnings
warnings.warn(f'invalid character {chr(badchar)!a} in URL-safe Base64 data '
_B32_ENCODE_DOCSTRING = '''
Encode the bytes-like objects using {encoding} and return a bytes object.
+If padded is false, omit padding in the output.
+
If wrapcol is non-zero, insert a newline (b'\\n') character after at most
every wrapcol characters.
'''
Optional casefold is a flag specifying whether a lowercase alphabet is
acceptable as input. For security purposes, the default is False.
+If padded is false, padding in input is not required.
+
ignorechars should be a byte string containing characters to ignore
from the input.
{extra_args}
0 and 1 are not allowed in the input.
'''
-def b32encode(s, *, wrapcol=0):
- return binascii.b2a_base32(s, wrapcol=wrapcol)
+def b32encode(s, *, padded=True, wrapcol=0):
+ return binascii.b2a_base32(s, padded=padded, wrapcol=wrapcol)
b32encode.__doc__ = _B32_ENCODE_DOCSTRING.format(encoding='base32')
-def b32decode(s, casefold=False, map01=None, *, ignorechars=b''):
+def b32decode(s, casefold=False, map01=None, *, padded=True, ignorechars=b''):
s = _bytes_from_decode_data(s)
# Handle section 2.4 zero and one mapping. The flag map01 will be either
# False, or the character to map the digit 1 (one) to. It should be
s = s.translate(bytes.maketrans(b'01', b'O' + map01))
if casefold:
s = s.upper()
- return binascii.a2b_base32(s, ignorechars=ignorechars)
+ return binascii.a2b_base32(s, padded=padded, ignorechars=ignorechars)
b32decode.__doc__ = _B32_DECODE_DOCSTRING.format(encoding='base32',
extra_args=_B32_DECODE_MAP01_DOCSTRING)
-def b32hexencode(s, *, wrapcol=0):
- return binascii.b2a_base32(s, wrapcol=wrapcol,
+def b32hexencode(s, *, padded=True, wrapcol=0):
+ return binascii.b2a_base32(s, padded=padded, wrapcol=wrapcol,
alphabet=binascii.BASE32HEX_ALPHABET)
b32hexencode.__doc__ = _B32_ENCODE_DOCSTRING.format(encoding='base32hex')
-def b32hexdecode(s, casefold=False, *, ignorechars=b''):
+def b32hexdecode(s, casefold=False, *, padded=True, ignorechars=b''):
s = _bytes_from_decode_data(s)
# base32hex does not have the 01 mapping
if casefold:
s = s.upper()
return binascii.a2b_base32(s, alphabet=binascii.BASE32HEX_ALPHABET,
- ignorechars=ignorechars)
+ padded=padded, ignorechars=ignorechars)
b32hexdecode.__doc__ = _B32_DECODE_DOCSTRING.format(encoding='base32hex',
extra_args='')
"""
return binascii.b2a_base85(b, wrapcol=wrapcol, pad=pad)
-def b85decode(b, *, ignorechars=b''):\r
+def b85decode(b, *, ignorechars=b''):
"""Decode the base85-encoded bytes-like object or ASCII string b
The result is returned as a bytes object.
return binascii.b2a_base85(s, wrapcol=wrapcol, pad=pad,
alphabet=binascii.Z85_ALPHABET)
-def z85decode(s, *, ignorechars=b''):\r
+def z85decode(s, *, ignorechars=b''):
"""Decode the z85-encoded bytes-like object or ASCII string b
The result is returned as a bytes object.
b'\xd3V\xbeo\xf7\x1d', b'01a-b_cd')
self.check_encode_type_errors(base64.urlsafe_b64encode)
+ def test_b64encode_padded(self):
+ b64encode = base64.b64encode
+ self.assertEqual(b64encode(b'', padded=False), b'')
+ self.assertEqual(b64encode(b'a', padded=False), b'YQ')
+ self.assertEqual(b64encode(b'ab', padded=False), b'YWI')
+ self.assertEqual(b64encode(b'abc', padded=False), b'YWJj')
+ self.assertEqual(b64encode(b'\xfb', padded=False, altchars=b'-_'), b'-w')
+ self.assertEqual(b64encode(b'\xfb\xff', padded=False, altchars=b'-_'),
+ b'-_8')
+ self.assertEqual(b64encode(b'\xfb\xff\xbf', padded=False, altchars=b'-_'),
+ b'-_-_')
+
+ urlsafe_b64encode = base64.urlsafe_b64encode
+ self.assertEqual(urlsafe_b64encode(b'', padded=False), b'')
+ self.assertEqual(urlsafe_b64encode(b'\xfb', padded=False), b'-w')
+ self.assertEqual(urlsafe_b64encode(b'\xfb\xff', padded=False), b'-_8')
+ self.assertEqual(urlsafe_b64encode(b'\xfb\xff\xbf', padded=False),
+ b'-_-_')
+
def _common_test_wrapcol(self, func, data):
eq = self.assertEqual
expected = func(data)
self.assertRaises(binascii.Error, base64.b64decode, b'abc')
self.assertRaises(binascii.Error, base64.b64decode, 'abc')
+ def test_b64decode_padded(self):
+ b64decode = base64.b64decode
+ urlsafe_b64decode = base64.urlsafe_b64decode
+ def check(data, expected, padded=0):
+ if b'=' in data:
+ with self.assertRaisesRegex(binascii.Error, 'Padding not allowed'):
+ b64decode(data, padded=False, validate=True)
+ self.assertEqual(b64decode(data, padded=False, ignorechars=b'='),
+ expected)
+ self.assertEqual(urlsafe_b64decode(data, padded=True), expected)
+ self.assertEqual(urlsafe_b64decode(data, padded=False), expected)
+ data = data.replace(b'=', b'')
+ self.assertEqual(b64decode(data, padded=False), expected)
+ self.assertEqual(b64decode(data, padded=False, validate=True),
+ expected)
+ self.assertEqual(urlsafe_b64decode(data), expected)
+
+ check(b'', b'')
+ check(b'YQ==', b'a')
+ check(b'YWI=', b'ab')
+ check(b'YWJj', b'abc')
+ check(b'Y=WJj', b'abc')
+ check(b'YW=Jj', b'abc')
+ check(b'YWJ=j', b'abc')
+
+ with self.assertRaisesRegex(binascii.Error, 'Incorrect padding'):
+ urlsafe_b64decode(b'YQ', padded=True)
+ with self.assertRaisesRegex(binascii.Error, 'Incorrect padding'):
+ urlsafe_b64decode(b'YWI', padded=True)
+
def _common_test_ignorechars(self, func):
eq = self.assertEqual
eq(func(b'', ignorechars=b' \n'), b'')
self.check_other_types(base64.b32encode, b'abcd', b'MFRGGZA=')
self.check_encode_type_errors(base64.b32encode)
+ def test_b32encode_padded(self):
+ b32encode = base64.b32encode
+ self.assertEqual(b32encode(b'', padded=False), b'')
+ self.assertEqual(b32encode(b'a', padded=False), b'ME')
+ self.assertEqual(b32encode(b'ab', padded=False), b'MFRA')
+ self.assertEqual(b32encode(b'abc', padded=False), b'MFRGG')
+ self.assertEqual(b32encode(b'abcd', padded=False), b'MFRGGZA')
+ self.assertEqual(b32encode(b'abcde', padded=False), b'MFRGGZDF')
+
def test_b32encode_wrapcol(self):
eq = self.assertEqual
b = b'www.python.org'
eq(base64.b32decode(b'M%c023456' % map01, map01=map01), res)
eq(base64.b32decode(b'M%cO23456' % map01, map01=map01), res)
+ def test_b32decode_padded(self):
+ b32decode = base64.b32decode
+ def check(data, expected):
+ if b'=' in data:
+ with self.assertRaisesRegex(binascii.Error, 'Padding not allowed'):
+ b32decode(data, padded=False)
+ self.assertEqual(b32decode(data, padded=False, ignorechars=b'='),
+ expected)
+ data = data.replace(b'=', b'')
+ self.assertEqual(b32decode(data, padded=False), expected)
+
+ check(b'', b'')
+ check(b'ME======', b'a')
+ check(b'MFRA====', b'ab')
+ check(b'MFRGG===', b'abc')
+ check(b'MFRGGZA=', b'abcd')
+ check(b'MFRGGZDF', b'abcde')
+ check(b'M=FRGGZDF', b'abcde')
+ check(b'MF=RGGZDF', b'abcde')
+ check(b'MFR=GGZDF', b'abcde')
+ check(b'MFRG=GZDF', b'abcde')
+ check(b'MFRGG=ZDF', b'abcde')
+ check(b'MFRGGZ=DF', b'abcde')
+ check(b'MFRGGZD=F', b'abcde')
+
def test_b32decode_ignorechars(self):
self._common_test_ignorechars(base64.b32decode)
eq = self.assertEqual
for to_encode, expected in test_cases:
with self.subTest(to_decode=to_encode):
self.assertEqual(base64.b32hexencode(to_encode), expected)
+ self.assertEqual(base64.b32hexencode(to_encode, padded=False),
+ expected.rstrip(b'='))
def test_b32hexencode_other_types(self):
self.check_other_types(base64.b32hexencode, b'abcd', b'C5H66P0=')
self.check_other_types(base64.b32hexdecode, b'C5H66===', b'abc')
self.check_decode_type_errors(base64.b32hexdecode)
+ def test_b32hexdecode_padded(self):
+ b32hexdecode = base64.b32hexdecode
+ def check(data, expected):
+ if b'=' in data:
+ with self.assertRaisesRegex(binascii.Error, 'Padding not allowed'):
+ b32hexdecode(data, padded=False)
+ self.assertEqual(b32hexdecode(data, padded=False, ignorechars=b'='),
+ expected)
+ data = data.replace(b'=', b'')
+ self.assertEqual(b32hexdecode(data, padded=False), expected)
+
+ check(b'', b'')
+ check(b'C4======', b'a')
+ check(b'C5H0====', b'ab')
+ check(b'C5H66===', b'abc')
+ check(b'C5H66P0=', b'abcd')
+ check(b'C5H66P35', b'abcde')
+ check(b'C=5H66P35', b'abcde')
+ check(b'C5=H66P35', b'abcde')
+ check(b'C5H=66P35', b'abcde')
+ check(b'C5H6=6P35', b'abcde')
+ check(b'C5H66=P35', b'abcde')
+ check(b'C5H66P=35', b'abcde')
+ check(b'C5H66P3=5', b'abcde')
+
def test_b32hexdecode_ignorechars(self):
self._common_test_ignorechars(base64.b32hexdecode)
eq = self.assertEqual
assertExcessPadding(b'abcd====efgh', b'i\xb7\x1dy\xf8!')
assertExcessPadding(b'abcd=====efgh', b'i\xb7\x1dy\xf8!')
+ def test_a2b_base64_padded(self):
+ a2b_base64 = binascii.a2b_base64
+ t = self.type2test
+ def check(data, expected):
+ if b'=' in data:
+ with self.assertRaisesRegex(binascii.Error, 'Padding not allowed'):
+ a2b_base64(t(data), padded=False, strict_mode=True)
+ self.assertEqual(a2b_base64(t(data), padded=False, ignorechars=b'='),
+ expected)
+ data = data.replace(b'=', b'')
+ self.assertEqual(a2b_base64(t(data), padded=False), expected)
+ self.assertEqual(a2b_base64(t(data), padded=False, strict_mode=True),
+ expected)
+
+ check(b'', b'')
+ check(b'YQ==', b'a')
+ check(b'YWI=', b'ab')
+ check(b'YWJj', b'abc')
+ check(b'Y=WJj', b'abc')
+ check(b'YW=Jj', b'abc')
+ check(b'YWJ=j', b'abc')
+
def _common_test_ignorechars(self, func):
eq = self.assertEqual
empty = self.type2test(b'')
assertInvalidLength(b" ABC=====", ignorechars=b' ')
assertInvalidLength(b" ABCDEF==", ignorechars=b' ')
+ def test_a2b_base32_padded(self):
+ a2b_base32 = binascii.a2b_base32
+ t = self.type2test
+ def check(data, expected):
+ if b'=' in data:
+ with self.assertRaisesRegex(binascii.Error, 'Padding not allowed'):
+ a2b_base32(t(data), padded=False)
+ self.assertEqual(a2b_base32(t(data), padded=False, ignorechars=b'='),
+ expected)
+ data = data.replace(b'=', b'')
+ self.assertEqual(a2b_base32(t(data), padded=False), expected)
+
+ check(b'', b'')
+ check(b'ME======', b'a')
+ check(b'MFRA====', b'ab')
+ check(b'MFRGG===', b'abc')
+ check(b'MFRGGZA=', b'abcd')
+ check(b'MFRGGZDF', b'abcde')
+ check(b'M=FRGGZDF', b'abcde')
+ check(b'MF=RGGZDF', b'abcde')
+ check(b'MFR=GGZDF', b'abcde')
+ check(b'MFRG=GZDF', b'abcde')
+ check(b'MFRGG=ZDF', b'abcde')
+ check(b'MFRGGZ=DF', b'abcde')
+ check(b'MFRGGZD=F', b'abcde')
+
+ def test_b2a_base32_padded(self):
+ b2a_base32 = binascii.b2a_base32
+ t = self.type2test
+ self.assertEqual(b2a_base32(t(b''), padded=False), b'')
+ self.assertEqual(b2a_base32(t(b'a'), padded=False), b'ME')
+ self.assertEqual(b2a_base32(t(b'ab'), padded=False), b'MFRA')
+ self.assertEqual(b2a_base32(t(b'abc'), padded=False), b'MFRGG')
+ self.assertEqual(b2a_base32(t(b'abcd'), padded=False), b'MFRGGZA')
+ self.assertEqual(b2a_base32(t(b'abcde'), padded=False), b'MFRGGZDF')
+
def test_base32_wrapcol(self):
self._common_test_wrapcol(binascii.b2a_base32)
b = self.type2test(b'www.python.org')
self.assertEqual(binascii.b2a_base64(b, newline=True), b'\n')
self.assertEqual(binascii.b2a_base64(b, newline=False), b'')
+ def test_b2a_base64_padded(self):
+ b2a_base64 = binascii.b2a_base64
+ t = self.type2test
+ self.assertEqual(b2a_base64(t(b''), padded=False), b'\n')
+ self.assertEqual(b2a_base64(t(b'a'), padded=False), b'YQ\n')
+ self.assertEqual(b2a_base64(t(b'ab'), padded=False), b'YWI\n')
+ self.assertEqual(b2a_base64(t(b'abc'), padded=False), b'YWJj\n')
+
def test_b2a_base64_wrapcol(self):
self._common_test_wrapcol(binascii.b2a_base64)
b = self.type2test(b'www.python.org')
--- /dev/null
+Add the *padded* parameter in functions related to Base32 and Base64 codecs
+in the :mod:`binascii` and :mod:`base64` modules.
+In the encoding functions it controls whether the pad character can be added
+in the output, in the decoding functions it controls whether padding is
+required in input.
+Padding of input no longer required in :func:`base64.urlsafe_b64decode`
+by default.
When set to true, bytes that are not part of the base64 standard are
not allowed. The same applies to excess data after padding (= / ==).
Set to True by default if ignorechars is specified, False otherwise.
+ padded: bool = True
+ When set to false, padding in input is not required.
alphabet: PyBytesObject(c_default="NULL") = BASE64_ALPHABET
ignorechars: Py_buffer = NULL
A byte string containing characters to ignore from the input when
static PyObject *
binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode,
- PyBytesObject *alphabet, Py_buffer *ignorechars)
-/*[clinic end generated code: output=72f15fcc0681d666 input=195c8d60b03aaa6f]*/
+ int padded, PyBytesObject *alphabet,
+ Py_buffer *ignorechars)
+/*[clinic end generated code: output=525d840a299ff132 input=74a53dd3b23474b3]*/
{
assert(data->len >= 0);
/* Check for pad sequences and ignore
** the invalid ones.
*/
- if (this_ch == BASE64_PAD) {
+ if (padded && this_ch == BASE64_PAD) {
pads++;
if (quad_pos >= 2 && quad_pos + pads <= 4) {
continue;
if (strict_mode && !ignorechar(this_ch, ignorechars, ignorecache)) {
state = get_binascii_state(module);
if (state) {
- PyErr_SetString(state->Error, "Only base64 data is allowed");
+ PyErr_SetString(state->Error,
+ (this_ch == BASE64_PAD)
+ ? "Padding not allowed"
+ : "Only base64 data is allowed");
}
goto error_end;
}
goto error_end;
}
- if (quad_pos != 0 && quad_pos + pads < 4) {
+ if (padded && quad_pos != 0 && quad_pos + pads < 4) {
state = get_binascii_state(module);
if (state) {
PyErr_SetString(state->Error, "Incorrect padding");
data: Py_buffer
/
*
+ padded: bool = True
+ When set to false, omit padding in the output.
wrapcol: size_t = 0
newline: bool = True
alphabet: Py_buffer(c_default="{NULL, NULL}") = BASE64_ALPHABET
[clinic start generated code]*/
static PyObject *
-binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, size_t wrapcol,
- int newline, Py_buffer *alphabet)
-/*[clinic end generated code: output=9d9657e5fbe28c64 input=ffa3af8520c312ac]*/
+binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int padded,
+ size_t wrapcol, int newline, Py_buffer *alphabet)
+/*[clinic end generated code: output=a2057b906dc201ab input=cfa33ad73051d3f7]*/
{
const unsigned char *table_b2a = table_b2a_base64;
const unsigned char *bin_data = data->buf;
* Use unsigned integer arithmetic to avoid signed integer overflow.
*/
size_t out_len = ((size_t)bin_len + 2u) / 3u * 4u;
+ unsigned int pads = (3 - (bin_len % 3)) % 3 * 4 / 3;
+ if (!padded) {
+ out_len -= pads;
+ pads = 0;
+ }
if (wrapcol && out_len) {
/* Each line should encode a whole number of bytes. */
wrapcol = wrapcol < 4 ? 4 : wrapcol / 4 * 4;
/* Handle remaining 0-2 bytes */
if (bin_len == 1) {
/* 1 byte remaining: produces 2 base64 chars + 2 padding */
+ assert(!padded || pads == 2);
unsigned int val = bin_data[0];
*ascii_data++ = table_b2a[(val >> 2) & 0x3f];
*ascii_data++ = table_b2a[(val << 4) & 0x3f];
- *ascii_data++ = BASE64_PAD;
- *ascii_data++ = BASE64_PAD;
}
else if (bin_len == 2) {
/* 2 bytes remaining: produces 3 base64 chars + 1 padding */
+ assert(!padded || pads == 1);
unsigned int val = ((unsigned int)bin_data[0] << 8) | bin_data[1];
*ascii_data++ = table_b2a[(val >> 10) & 0x3f];
*ascii_data++ = table_b2a[(val >> 4) & 0x3f];
*ascii_data++ = table_b2a[(val << 2) & 0x3f];
+ }
+ else {
+ assert(pads == 0);
+ }
+ for (; pads; pads--) {
*ascii_data++ = BASE64_PAD;
}
data: ascii_buffer
/
*
+ padded: bool = True
+ When set to false, padding in input is not required.
alphabet: PyBytesObject(c_default="NULL") = BASE32_ALPHABET
ignorechars: Py_buffer = b''
A byte string containing characters to ignore from the input.
[clinic start generated code]*/
static PyObject *
-binascii_a2b_base32_impl(PyObject *module, Py_buffer *data,
+binascii_a2b_base32_impl(PyObject *module, Py_buffer *data, int padded,
PyBytesObject *alphabet, Py_buffer *ignorechars)
-/*[clinic end generated code: output=2cf7c8c9e6e98b88 input=b0333508aad1b3ac]*/
+/*[clinic end generated code: output=7dbbaa816d956b1c input=07a3721acdf9b688]*/
{
const unsigned char *ascii_data = data->buf;
Py_ssize_t ascii_len = data->len;
unsigned char this_ch = *ascii_data;
/* Check for pad sequences. They may only occur at certain positions. */
- if (this_ch == BASE32_PAD) {
+ if (padded && this_ch == BASE32_PAD) {
pads++;
if ((octa_pos == 2 || octa_pos == 4 || octa_pos == 5 || octa_pos == 7)
if (!ignorechar(this_ch, ignorechars, ignorecache)) {
state = get_binascii_state(module);
if (state) {
- PyErr_SetString(state->Error, "Only base32 data is allowed");
+ PyErr_SetString(state->Error,
+ (this_ch == BASE32_PAD)
+ ? "Padding not allowed"
+ : "Only base32 data is allowed");
}
goto error;
}
goto error;
}
- if (octa_pos != 0 && octa_pos + pads < 8) {
+ if (padded && octa_pos != 0 && octa_pos + pads < 8) {
state = get_binascii_state(module);
if (state) {
PyErr_SetString(state->Error, "Incorrect padding");
data: Py_buffer
/
*
+ padded: bool = True
+ When set to false, omit padding in the output.
wrapcol: size_t = 0
alphabet: Py_buffer(c_default="{NULL, NULL}") = BASE32_ALPHABET
[clinic start generated code]*/
static PyObject *
-binascii_b2a_base32_impl(PyObject *module, Py_buffer *data, size_t wrapcol,
- Py_buffer *alphabet)
-/*[clinic end generated code: output=d41fafbdaf29e280 input=a3d93b73836f2879]*/
+binascii_b2a_base32_impl(PyObject *module, Py_buffer *data, int padded,
+ size_t wrapcol, Py_buffer *alphabet)
+/*[clinic end generated code: output=acc09e685569aab9 input=1889b0c497a1d3c2]*/
{
const unsigned char *table_b2a = table_b2a_base32;
const unsigned char *bin_data = data->buf;
* Use unsigned integer arithmetic to avoid signed integer overflow.
*/
size_t ascii_len = ((size_t)bin_len + 4u) / 5u * 8u;
+ unsigned int pads = (5 - (bin_len % 5)) % 5 * 8 / 5;
+ if (!padded) {
+ ascii_len -= pads;
+ pads = 0;
+ }
if (wrapcol && ascii_len) {
/* Each line should encode a whole number of bytes. */
wrapcol = wrapcol < 8 ? 8 : wrapcol / 8 * 8;
/* Handle the remaining 0-4 bytes. */
if (bin_len == 1) {
/* 1 byte remaining: produces 2 encoded + 6 padding chars. */
+ assert(!padded || pads == 6);
uint32_t val = bin_data[0];
*ascii_data++ = table_b2a[(val >> 3) & 0x1f];
*ascii_data++ = table_b2a[(val << 2) & 0x1f];
- *ascii_data++ = BASE32_PAD;
- *ascii_data++ = BASE32_PAD;
- *ascii_data++ = BASE32_PAD;
- *ascii_data++ = BASE32_PAD;
- *ascii_data++ = BASE32_PAD;
- *ascii_data++ = BASE32_PAD;
}
else if (bin_len == 2) {
/* 2 bytes remaining: produces 4 encoded + 4 padding chars. */
+ assert(!padded || pads == 4);
uint32_t val = ((uint32_t)bin_data[0] << 8) | bin_data[1];
*ascii_data++ = table_b2a[(val >> 11) & 0x1f];
*ascii_data++ = table_b2a[(val >> 6) & 0x1f];
*ascii_data++ = table_b2a[(val >> 1) & 0x1f];
*ascii_data++ = table_b2a[(val << 4) & 0x1f];
- *ascii_data++ = BASE32_PAD;
- *ascii_data++ = BASE32_PAD;
- *ascii_data++ = BASE32_PAD;
- *ascii_data++ = BASE32_PAD;
}
else if (bin_len == 3) {
/* 3 bytes remaining: produces 5 encoded + 3 padding chars. */
+ assert(!padded || pads == 3);
uint32_t val = ((uint32_t)bin_data[0] << 16)
| ((uint32_t)bin_data[1] << 8)
| bin_data[2];
*ascii_data++ = table_b2a[(val >> 9) & 0x1f];
*ascii_data++ = table_b2a[(val >> 4) & 0x1f];
*ascii_data++ = table_b2a[(val << 1) & 0x1f];
- *ascii_data++ = BASE32_PAD;
- *ascii_data++ = BASE32_PAD;
- *ascii_data++ = BASE32_PAD;
}
else if (bin_len == 4) {
/* 4 bytes remaining: produces 7 encoded + 1 padding chars. */
+ assert(!padded || pads == 1);
uint32_t val = ((uint32_t)bin_data[0] << 24)
| ((uint32_t)bin_data[1] << 16)
| ((uint32_t)bin_data[2] << 8)
*ascii_data++ = table_b2a[(val >> 7) & 0x1f];
*ascii_data++ = table_b2a[(val >> 2) & 0x1f];
*ascii_data++ = table_b2a[(val << 3) & 0x1f];
+ }
+ else {
+ assert(pads == 0);
+ }
+ for (; pads; pads--) {
*ascii_data++ = BASE32_PAD;
}
PyDoc_STRVAR(binascii_a2b_base64__doc__,
"a2b_base64($module, data, /, *, strict_mode=<unrepresentable>,\n"
-" alphabet=BASE64_ALPHABET, ignorechars=<unrepresentable>)\n"
+" padded=True, alphabet=BASE64_ALPHABET,\n"
+" ignorechars=<unrepresentable>)\n"
"--\n"
"\n"
"Decode a line of base64 data.\n"
" When set to true, bytes that are not part of the base64 standard are\n"
" not allowed. The same applies to excess data after padding (= / ==).\n"
" Set to True by default if ignorechars is specified, False otherwise.\n"
+" padded\n"
+" When set to false, padding in input is not required.\n"
" ignorechars\n"
" A byte string containing characters to ignore from the input when\n"
" strict_mode is true.");
static PyObject *
binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode,
- PyBytesObject *alphabet, Py_buffer *ignorechars);
+ int padded, PyBytesObject *alphabet,
+ Py_buffer *ignorechars);
static PyObject *
binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 3
+ #define NUM_KEYWORDS 4
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(strict_mode), &_Py_ID(alphabet), &_Py_ID(ignorechars), },
+ .ob_item = { &_Py_ID(strict_mode), &_Py_ID(padded), &_Py_ID(alphabet), &_Py_ID(ignorechars), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"", "strict_mode", "alphabet", "ignorechars", NULL};
+ static const char * const _keywords[] = {"", "strict_mode", "padded", "alphabet", "ignorechars", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "a2b_base64",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[4];
+ PyObject *argsbuf[5];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
Py_buffer data = {NULL, NULL};
int strict_mode = -1;
+ int padded = 1;
PyBytesObject *alphabet = NULL;
Py_buffer ignorechars = {NULL, NULL};
}
}
if (args[2]) {
- if (!PyBytes_Check(args[2])) {
- _PyArg_BadArgument("a2b_base64", "argument 'alphabet'", "bytes", args[2]);
+ padded = PyObject_IsTrue(args[2]);
+ if (padded < 0) {
goto exit;
}
- alphabet = (PyBytesObject *)args[2];
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
- if (PyObject_GetBuffer(args[3], &ignorechars, PyBUF_SIMPLE) != 0) {
+ if (args[3]) {
+ if (!PyBytes_Check(args[3])) {
+ _PyArg_BadArgument("a2b_base64", "argument 'alphabet'", "bytes", args[3]);
+ goto exit;
+ }
+ alphabet = (PyBytesObject *)args[3];
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
+ }
+ if (PyObject_GetBuffer(args[4], &ignorechars, PyBUF_SIMPLE) != 0) {
goto exit;
}
skip_optional_kwonly:
- return_value = binascii_a2b_base64_impl(module, &data, strict_mode, alphabet, &ignorechars);
+ return_value = binascii_a2b_base64_impl(module, &data, strict_mode, padded, alphabet, &ignorechars);
exit:
/* Cleanup for data */
}
PyDoc_STRVAR(binascii_b2a_base64__doc__,
-"b2a_base64($module, data, /, *, wrapcol=0, newline=True,\n"
+"b2a_base64($module, data, /, *, padded=True, wrapcol=0, newline=True,\n"
" alphabet=BASE64_ALPHABET)\n"
"--\n"
"\n"
-"Base64-code line of data.");
+"Base64-code line of data.\n"
+"\n"
+" padded\n"
+" When set to false, omit padding in the output.");
#define BINASCII_B2A_BASE64_METHODDEF \
{"b2a_base64", _PyCFunction_CAST(binascii_b2a_base64), METH_FASTCALL|METH_KEYWORDS, binascii_b2a_base64__doc__},
static PyObject *
-binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, size_t wrapcol,
- int newline, Py_buffer *alphabet);
+binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, int padded,
+ size_t wrapcol, int newline, Py_buffer *alphabet);
static PyObject *
binascii_b2a_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 3
+ #define NUM_KEYWORDS 4
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(wrapcol), &_Py_ID(newline), &_Py_ID(alphabet), },
+ .ob_item = { &_Py_ID(padded), &_Py_ID(wrapcol), &_Py_ID(newline), &_Py_ID(alphabet), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"", "wrapcol", "newline", "alphabet", NULL};
+ static const char * const _keywords[] = {"", "padded", "wrapcol", "newline", "alphabet", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "b2a_base64",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[4];
+ PyObject *argsbuf[5];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
Py_buffer data = {NULL, NULL};
+ int padded = 1;
size_t wrapcol = 0;
int newline = 1;
Py_buffer alphabet = {NULL, NULL};
goto skip_optional_kwonly;
}
if (args[1]) {
- if (!_PyLong_Size_t_Converter(args[1], &wrapcol)) {
+ padded = PyObject_IsTrue(args[1]);
+ if (padded < 0) {
goto exit;
}
if (!--noptargs) {
}
}
if (args[2]) {
- newline = PyObject_IsTrue(args[2]);
+ if (!_PyLong_Size_t_Converter(args[2], &wrapcol)) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
+ }
+ if (args[3]) {
+ newline = PyObject_IsTrue(args[3]);
if (newline < 0) {
goto exit;
}
goto skip_optional_kwonly;
}
}
- if (PyObject_GetBuffer(args[3], &alphabet, PyBUF_SIMPLE) != 0) {
+ if (PyObject_GetBuffer(args[4], &alphabet, PyBUF_SIMPLE) != 0) {
goto exit;
}
skip_optional_kwonly:
- return_value = binascii_b2a_base64_impl(module, &data, wrapcol, newline, &alphabet);
+ return_value = binascii_b2a_base64_impl(module, &data, padded, wrapcol, newline, &alphabet);
exit:
/* Cleanup for data */
}
PyDoc_STRVAR(binascii_a2b_base32__doc__,
-"a2b_base32($module, data, /, *, alphabet=BASE32_ALPHABET,\n"
+"a2b_base32($module, data, /, *, padded=True, alphabet=BASE32_ALPHABET,\n"
" ignorechars=b\'\')\n"
"--\n"
"\n"
"Decode a line of base32 data.\n"
"\n"
+" padded\n"
+" When set to false, padding in input is not required.\n"
" ignorechars\n"
" A byte string containing characters to ignore from the input.");
{"a2b_base32", _PyCFunction_CAST(binascii_a2b_base32), METH_FASTCALL|METH_KEYWORDS, binascii_a2b_base32__doc__},
static PyObject *
-binascii_a2b_base32_impl(PyObject *module, Py_buffer *data,
+binascii_a2b_base32_impl(PyObject *module, Py_buffer *data, int padded,
PyBytesObject *alphabet, Py_buffer *ignorechars);
static PyObject *
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(alphabet), &_Py_ID(ignorechars), },
+ .ob_item = { &_Py_ID(padded), &_Py_ID(alphabet), &_Py_ID(ignorechars), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"", "alphabet", "ignorechars", NULL};
+ static const char * const _keywords[] = {"", "padded", "alphabet", "ignorechars", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "a2b_base32",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[3];
+ PyObject *argsbuf[4];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
Py_buffer data = {NULL, NULL};
+ int padded = 1;
PyBytesObject *alphabet = NULL;
Py_buffer ignorechars = {.buf = "", .obj = NULL, .len = 0};
goto skip_optional_kwonly;
}
if (args[1]) {
- if (!PyBytes_Check(args[1])) {
- _PyArg_BadArgument("a2b_base32", "argument 'alphabet'", "bytes", args[1]);
+ padded = PyObject_IsTrue(args[1]);
+ if (padded < 0) {
goto exit;
}
- alphabet = (PyBytesObject *)args[1];
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
- if (PyObject_GetBuffer(args[2], &ignorechars, PyBUF_SIMPLE) != 0) {
+ if (args[2]) {
+ if (!PyBytes_Check(args[2])) {
+ _PyArg_BadArgument("a2b_base32", "argument 'alphabet'", "bytes", args[2]);
+ goto exit;
+ }
+ alphabet = (PyBytesObject *)args[2];
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
+ }
+ if (PyObject_GetBuffer(args[3], &ignorechars, PyBUF_SIMPLE) != 0) {
goto exit;
}
skip_optional_kwonly:
- return_value = binascii_a2b_base32_impl(module, &data, alphabet, &ignorechars);
+ return_value = binascii_a2b_base32_impl(module, &data, padded, alphabet, &ignorechars);
exit:
/* Cleanup for data */
}
PyDoc_STRVAR(binascii_b2a_base32__doc__,
-"b2a_base32($module, data, /, *, wrapcol=0, alphabet=BASE32_ALPHABET)\n"
+"b2a_base32($module, data, /, *, padded=True, wrapcol=0,\n"
+" alphabet=BASE32_ALPHABET)\n"
"--\n"
"\n"
-"Base32-code line of data.");
+"Base32-code line of data.\n"
+"\n"
+" padded\n"
+" When set to false, omit padding in the output.");
#define BINASCII_B2A_BASE32_METHODDEF \
{"b2a_base32", _PyCFunction_CAST(binascii_b2a_base32), METH_FASTCALL|METH_KEYWORDS, binascii_b2a_base32__doc__},
static PyObject *
-binascii_b2a_base32_impl(PyObject *module, Py_buffer *data, size_t wrapcol,
- Py_buffer *alphabet);
+binascii_b2a_base32_impl(PyObject *module, Py_buffer *data, int padded,
+ size_t wrapcol, Py_buffer *alphabet);
static PyObject *
binascii_b2a_base32(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
- #define NUM_KEYWORDS 2
+ #define NUM_KEYWORDS 3
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
- .ob_item = { &_Py_ID(wrapcol), &_Py_ID(alphabet), },
+ .ob_item = { &_Py_ID(padded), &_Py_ID(wrapcol), &_Py_ID(alphabet), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
- static const char * const _keywords[] = {"", "wrapcol", "alphabet", NULL};
+ static const char * const _keywords[] = {"", "padded", "wrapcol", "alphabet", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "b2a_base32",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
- PyObject *argsbuf[3];
+ PyObject *argsbuf[4];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
Py_buffer data = {NULL, NULL};
+ int padded = 1;
size_t wrapcol = 0;
Py_buffer alphabet = {NULL, NULL};
goto skip_optional_kwonly;
}
if (args[1]) {
- if (!_PyLong_Size_t_Converter(args[1], &wrapcol)) {
+ padded = PyObject_IsTrue(args[1]);
+ if (padded < 0) {
goto exit;
}
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
- if (PyObject_GetBuffer(args[2], &alphabet, PyBUF_SIMPLE) != 0) {
+ if (args[2]) {
+ if (!_PyLong_Size_t_Converter(args[2], &wrapcol)) {
+ goto exit;
+ }
+ if (!--noptargs) {
+ goto skip_optional_kwonly;
+ }
+ }
+ if (PyObject_GetBuffer(args[3], &alphabet, PyBUF_SIMPLE) != 0) {
goto exit;
}
skip_optional_kwonly:
- return_value = binascii_b2a_base32_impl(module, &data, wrapcol, &alphabet);
+ return_value = binascii_b2a_base32_impl(module, &data, padded, wrapcol, &alphabet);
exit:
/* Cleanup for data */
return return_value;
}
-/*[clinic end generated code: output=197a0f70aa392d39 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=2acab1ceb0058b1a input=a9049054013a1b77]*/