gh-145980: Add support for alternative alphabets in the binascii module (GH-145981)

* Add the alphabet parameter in functions b2a_base64(), a2b_base64(),
  b2a_base85(), and a2b_base85().
* And a number of "*_ALPHABET" constants.
* Remove b2a_z85() and a2b_z85().
This commit is contained in:
Serhiy Storchaka
2026-03-20 13:07:00 +02:00
committed by GitHub
parent d357a7dbf3
commit 4507d496b4
11 changed files with 500 additions and 379 deletions
+64 -36
View File
@@ -48,12 +48,15 @@ The :mod:`!binascii` module defines the following functions:
Added the *backtick* parameter.
.. function:: a2b_base64(string, /, *, strict_mode=False)
a2b_base64(string, /, *, strict_mode=True, ignorechars)
.. function:: a2b_base64(string, /, *, alphabet=BASE64_ALPHABET, strict_mode=False)
a2b_base64(string, /, *, ignorechars, 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 *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
@@ -76,10 +79,10 @@ The :mod:`!binascii` module defines the following functions:
Added the *strict_mode* parameter.
.. versionchanged:: 3.15
Added the *ignorechars* parameter.
Added the *alphabet* and *ignorechars* parameters.
.. function:: b2a_base64(data, *, wrapcol=0, newline=True)
.. function:: b2a_base64(data, *, 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`.
@@ -95,7 +98,7 @@ The :mod:`!binascii` module defines the following functions:
Added the *newline* parameter.
.. versionchanged:: 3.15
Added the *wrapcol* parameter.
Added the *alphabet* and *wrapcol* parameters.
.. function:: a2b_ascii85(string, /, *, foldspaces=False, adobe=False, ignorechars=b"")
@@ -148,7 +151,7 @@ The :mod:`!binascii` module defines the following functions:
.. versionadded:: 3.15
.. function:: a2b_base85(string, /)
.. function:: a2b_base85(string, /, *, alphabet=BASE85_ALPHABET)
Convert Base85 data back to binary and return the binary data.
More than one line may be passed at a time.
@@ -158,49 +161,25 @@ The :mod:`!binascii` module defines the following functions:
characters). Each group encodes 32 bits of binary data in the range from
``0`` to ``2 ** 32 - 1``, inclusive.
Optional *alphabet* must be a :class:`bytes` object of length 85 which
specifies an alternative alphabet.
Invalid Base85 data will raise :exc:`binascii.Error`.
.. versionadded:: 3.15
.. function:: b2a_base85(data, /, *, pad=False)
.. function:: b2a_base85(data, /, *, alphabet=BASE85_ALPHABET, pad=False)
Convert binary data to a line of ASCII characters in Base85 coding.
The return value is the converted line.
If *pad* is true, the input is padded with ``b'\0'`` so its length is a
multiple of 4 bytes before encoding.
.. versionadded:: 3.15
.. function:: a2b_z85(string, /)
Convert Z85 data back to binary and return the binary data.
More than one line may be passed at a time.
Valid Z85 data contains characters from the Z85 alphabet in groups
of five (except for the final group, which may have from two to five
characters). Each group encodes 32 bits of binary data in the range from
``0`` to ``2 ** 32 - 1``, inclusive.
See `Z85 specification <https://rfc.zeromq.org/spec/32/>`_ for more information.
Invalid Z85 data will raise :exc:`binascii.Error`.
.. versionadded:: 3.15
.. function:: b2a_z85(data, /, *, pad=False)
Convert binary data to a line of ASCII characters in Z85 coding.
The return value is the converted line.
Optional *alphabet* must be a :term:`bytes-like object` of length 85 which
specifies an alternative alphabet.
If *pad* is true, the input is padded with ``b'\0'`` so its length is a
multiple of 4 bytes before encoding.
See `Z85 specification <https://rfc.zeromq.org/spec/32/>`_ for more information.
.. versionadded:: 3.15
@@ -300,6 +279,55 @@ The :mod:`!binascii` module defines the following functions:
but may be handled by reading a little more data and trying again.
.. data:: BASE64_ALPHABET
The Base 64 alphabet according to :rfc:`4648`.
.. versionadded:: next
.. data:: URLSAFE_BASE64_ALPHABET
The "URL and filename safe" Base 64 alphabet according to :rfc:`4648`.
.. versionadded:: next
.. data:: UU_ALPHABET
The uuencoding alphabet.
.. versionadded:: next
.. data:: CRYPT_ALPHABET
The Base 64 alphabet used in the :manpage:`crypt(3)` routine and in the GEDCOM format.
.. versionadded:: next
.. data:: BINHEX_ALPHABET
The Base 64 alphabet used in BinHex 4 (HQX) within the classic Mac OS.
.. versionadded:: next
.. data:: BASE85_ALPHABET
The Base85 alphabet.
.. versionadded:: next
.. data:: ASCII85_ALPHABET
The Ascii85 alphabet.
.. versionadded:: next
.. data:: Z85_ALPHABET
The `Z85 <https://rfc.zeromq.org/spec/32/>`_ alphabet.
.. versionadded:: next
.. seealso::
Module :mod:`base64`
+4 -1
View File
@@ -649,13 +649,16 @@ binascii
- :func:`~binascii.b2a_ascii85` and :func:`~binascii.a2b_ascii85`
- :func:`~binascii.b2a_base85` and :func:`~binascii.a2b_base85`
- :func:`~binascii.b2a_z85` and :func:`~binascii.a2b_z85`
(Contributed by James Seo and Serhiy Storchaka in :gh:`101178`.)
* Added the *wrapcol* parameter in :func:`~binascii.b2a_base64`.
(Contributed by Serhiy Storchaka in :gh:`143214`.)
* Added the *alphabet* parameter in :func:`~binascii.b2a_base64` and
:func:`~binascii.a2b_base64`.
(Contributed by Serhiy Storchaka in :gh:`145980`.)
* Added the *ignorechars* parameter in :func:`~binascii.a2b_base64`.
(Contributed by Serhiy Storchaka in :gh:`144001`.)
+1
View File
@@ -1584,6 +1584,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(all));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(all_threads));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(allow_code));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(alphabet));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(any));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(append));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(arg));
+1
View File
@@ -307,6 +307,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(all)
STRUCT_FOR_ID(all_threads)
STRUCT_FOR_ID(allow_code)
STRUCT_FOR_ID(alphabet)
STRUCT_FOR_ID(any)
STRUCT_FOR_ID(append)
STRUCT_FOR_ID(arg)
+1
View File
@@ -1582,6 +1582,7 @@ extern "C" {
INIT_ID(all), \
INIT_ID(all_threads), \
INIT_ID(allow_code), \
INIT_ID(alphabet), \
INIT_ID(any), \
INIT_ID(append), \
INIT_ID(arg), \
+4
View File
@@ -1008,6 +1008,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(alphabet);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(any);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
+14 -17
View File
@@ -56,11 +56,13 @@ def b64encode(s, altchars=None, *, wrapcol=0):
If wrapcol is non-zero, insert a newline (b'\\n') character after at most
every wrapcol characters.
"""
encoded = binascii.b2a_base64(s, wrapcol=wrapcol, newline=False)
if altchars is not None:
assert len(altchars) == 2, repr(altchars)
return encoded.translate(bytes.maketrans(b'+/', altchars))
return encoded
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,
alphabet=alphabet)
return binascii.b2a_base64(s, wrapcol=wrapcol, newline=False)
def b64decode(s, altchars=None, validate=_NOT_SPECIFIED, *, ignorechars=_NOT_SPECIFIED):
@@ -100,15 +102,10 @@ def b64decode(s, altchars=None, validate=_NOT_SPECIFIED, *, ignorechars=_NOT_SPE
break
s = s.translate(bytes.maketrans(altchars, b'+/'))
else:
trans_in = set(b'+/') - set(altchars)
if len(trans_in) == 2:
# we can't use the reqult of unordered sets here
trans = bytes.maketrans(altchars + b'+/', b'+/' + altchars)
else:
trans = bytes.maketrans(altchars + bytes(trans_in),
b'+/' + bytes(set(altchars) - set(b'+/')))
s = s.translate(trans)
ignorechars = ignorechars.translate(trans)
alphabet = binascii.BASE64_ALPHABET[:-2] + altchars
return binascii.a2b_base64(s, strict_mode=validate,
alphabet=alphabet,
ignorechars=ignorechars)
if ignorechars is _NOT_SPECIFIED:
ignorechars = b''
result = binascii.a2b_base64(s, strict_mode=validate,
@@ -146,7 +143,6 @@ def standard_b64decode(s):
return b64decode(s)
_urlsafe_encode_translation = bytes.maketrans(b'+/', b'-_')
_urlsafe_decode_translation = bytes.maketrans(b'-_', b'+/')
def urlsafe_b64encode(s):
@@ -156,7 +152,8 @@ def urlsafe_b64encode(s):
bytes object. The alphabet uses '-' instead of '+' and '_' instead of
'/'.
"""
return b64encode(s).translate(_urlsafe_encode_translation)
return binascii.b2a_base64(s, newline=False,
alphabet=binascii.URLSAFE_BASE64_ALPHABET)
def urlsafe_b64decode(s):
"""Decode bytes using the URL- and filesystem-safe Base64 alphabet.
@@ -399,14 +396,14 @@ def b85decode(b):
def z85encode(s, pad=False):
"""Encode bytes-like object b in z85 format and return a bytes object."""
return binascii.b2a_z85(s, pad=pad)
return binascii.b2a_base85(s, pad=pad, alphabet=binascii.Z85_ALPHABET)
def z85decode(s):
"""Decode the z85-encoded bytes-like object or ASCII string b
The result is returned as a bytes object.
"""
return binascii.a2b_z85(s)
return binascii.a2b_base85(s, alphabet=binascii.Z85_ALPHABET)
# Legacy interface. This code could be cleaned up since I don't believe
# binascii has any line length limitations. It just doesn't seem worth it
+82 -67
View File
@@ -10,10 +10,10 @@ from test.support.hypothesis_helper import hypothesis
# Note: "*_hex" functions are aliases for "(un)hexlify"
b2a_functions = ['b2a_ascii85', 'b2a_base64', 'b2a_base85', 'b2a_z85',
b2a_functions = ['b2a_ascii85', 'b2a_base64', 'b2a_base85',
'b2a_hex', 'b2a_qp', 'b2a_uu',
'hexlify']
a2b_functions = ['a2b_ascii85', 'a2b_base64', 'a2b_base85', 'a2b_z85',
a2b_functions = ['a2b_ascii85', 'a2b_base64', 'a2b_base85',
'a2b_hex', 'a2b_qp', 'a2b_uu',
'unhexlify']
all_functions = a2b_functions + b2a_functions + ['crc32', 'crc_hqx']
@@ -46,6 +46,35 @@ class BinASCIITest(unittest.TestCase):
self.assertIsSubclass(binascii.Error, Exception)
self.assertIsSubclass(binascii.Incomplete, Exception)
def test_constants(self):
self.assertEqual(binascii.BASE64_ALPHABET,
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b'abcdefghijklmnopqrstuvwxyz'
b'0123456789+/')
self.assertEqual(binascii.URLSAFE_BASE64_ALPHABET,
binascii.BASE64_ALPHABET[:-2] + b'-_')
self.assertEqual(binascii.UU_ALPHABET, bytes(range(32, 32+64)))
self.assertEqual(binascii.CRYPT_ALPHABET,
b'./0123456789'
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b'abcdefghijklmnopqrstuvwxyz')
self.assertEqual(binascii.BINHEX_ALPHABET,
b'!"#$%&\'()*+,-012345689'
b'@ABCDEFGHIJKLMNPQRSTUVXYZ['
b'`abcdefhijklmpqr')
self.assertEqual(binascii.BASE85_ALPHABET,
b'0123456789'
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b'abcdefghijklmnopqrstuvwxyz'
b'!#$%&()*+-;<=>?@^_`{|}~')
self.assertEqual(binascii.ASCII85_ALPHABET, bytes(range(33, 33+85)))
self.assertEqual(binascii.Z85_ALPHABET,
b'0123456789'
b'abcdefghijklmnopqrstuvwxyz'
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
b'.-:+=^!/*?&<>()[]{}@%$#')
def test_functions(self):
# Check presence of all functions
for name in all_functions:
@@ -302,6 +331,33 @@ class BinASCIITest(unittest.TestCase):
assertInvalidLength(b'A\tB\nC ??DE', # only 5 valid characters
strict_mode=False)
def test_base64_alphabet(self):
alphabet = (b'!"#$%&\'()*+,-012345689@'
b'ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr')
data = self.type2test(self.rawdata)
encoded = binascii.b2a_base64(data, alphabet=alphabet)
trans = bytes.maketrans(binascii.BASE64_ALPHABET, alphabet)
expected = binascii.b2a_base64(data).translate(trans)
self.assertEqual(encoded, expected)
self.assertEqual(binascii.a2b_base64(encoded, alphabet=alphabet), self.rawdata)
self.assertEqual(binascii.b2a_base64(data, alphabet=self.type2test(alphabet)), expected)
data = self.type2test(b'')
self.assertEqual(binascii.b2a_base64(data, alphabet=alphabet), b'\n')
self.assertEqual(binascii.a2b_base64(data, alphabet=alphabet), b'')
for func in binascii.b2a_base64, binascii.a2b_base64:
with self.assertRaises(TypeError):
func(data, alphabet=None)
with self.assertRaises(TypeError):
func(data, alphabet=alphabet.decode())
with self.assertRaises(ValueError):
func(data, alphabet=alphabet[:-1])
with self.assertRaises(ValueError):
func(data, alphabet=alphabet+b'?')
with self.assertRaises(TypeError):
binascii.a2b_base64(data, alphabet=bytearray(alphabet))
def test_ascii85_valid(self):
# Test Ascii85 with valid data
ASCII85_PREFIX = b"<~"
@@ -587,73 +643,32 @@ class BinASCIITest(unittest.TestCase):
b_pad_expected = b + b"\0" * padding
self.assertEqual(b_pad, b_pad_expected)
def test_z85_valid(self):
# Test Z85 with valid data
lines, i = [], 0
for k in range(1, len(self.rawdata) + 1):
b = self.type2test(self.rawdata[i:i + k])
a = binascii.b2a_z85(b)
lines.append(a)
i += k
if i >= len(self.rawdata):
break
res = bytes()
for line in lines:
a = self.type2test(line)
b = binascii.a2b_z85(a)
res += b
self.assertEqual(res, self.rawdata)
def test_base85_alphabet(self):
alphabet = (b'0123456789abcdefghijklmnopqrstuvwxyz'
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#')
data = self.type2test(self.rawdata)
encoded = binascii.b2a_base85(data, alphabet=alphabet)
trans = bytes.maketrans(binascii.BASE85_ALPHABET, alphabet)
expected = binascii.b2a_base85(data).translate(trans)
self.assertEqual(encoded, expected)
self.assertEqual(binascii.a2b_base85(encoded, alphabet=alphabet), self.rawdata)
self.assertEqual(binascii.b2a_base85(data, alphabet=self.type2test(alphabet)), expected)
# Test decoding inputs with different length
self.assertEqual(binascii.a2b_z85(self.type2test(b'')), b'')
self.assertEqual(binascii.a2b_z85(self.type2test(b'a')), b'')
self.assertEqual(binascii.a2b_z85(self.type2test(b'ab')), b'\x1f')
self.assertEqual(binascii.a2b_z85(self.type2test(b'abc')),
b'\x1f\x85')
self.assertEqual(binascii.a2b_z85(self.type2test(b'abcd')),
b'\x1f\x85\x9a')
self.assertEqual(binascii.a2b_z85(self.type2test(b'abcde')),
b'\x1f\x85\x9a$')
self.assertEqual(binascii.a2b_z85(self.type2test(b'abcdef')),
b'\x1f\x85\x9a$')
self.assertEqual(binascii.a2b_z85(self.type2test(b'abcdefg')),
b'\x1f\x85\x9a$/')
data = self.type2test(b'')
self.assertEqual(binascii.b2a_base85(data, alphabet=alphabet), b'')
self.assertEqual(binascii.a2b_base85(data, alphabet=alphabet), b'')
def test_z85_errors(self):
def _assertRegexTemplate(assert_regex, data, **kwargs):
with self.assertRaisesRegex(binascii.Error, assert_regex):
binascii.a2b_z85(self.type2test(data), **kwargs)
def assertNonZ85Data(data):
_assertRegexTemplate(r"(?i)bad z85 character", data)
def assertOverflow(data):
_assertRegexTemplate(r"(?i)z85 overflow", data)
assertNonZ85Data(b"\xda")
assertNonZ85Data(b"00\0\0")
assertNonZ85Data(b"z !/")
assertNonZ85Data(b"By/JnB0hYQ\n")
# Test Z85 with out-of-range encoded value
assertOverflow(b"%")
assertOverflow(b"%n")
assertOverflow(b"%nS")
assertOverflow(b"%nSc")
assertOverflow(b"%nSc1")
assertOverflow(b"%nSc0$")
assertOverflow(b"%nSc0%nSc0%nSD0")
def test_z85_pad(self):
# Test Z85 with encode padding
rawdata = b"n1n3Tee\n ch@rAc\te\r$"
for i in range(1, len(rawdata) + 1):
padding = -i % 4
b = rawdata[:i]
a_pad = binascii.b2a_z85(self.type2test(b), pad=True)
b_pad = binascii.a2b_z85(self.type2test(a_pad))
b_pad_expected = b + b"\0" * padding
self.assertEqual(b_pad, b_pad_expected)
for func in binascii.b2a_base85, binascii.a2b_base85:
with self.assertRaises(TypeError):
func(data, alphabet=None)
with self.assertRaises(TypeError):
func(data, alphabet=alphabet.decode())
with self.assertRaises(ValueError):
func(data, alphabet=alphabet[:-1])
with self.assertRaises(ValueError):
func(data, alphabet=alphabet+b'?')
with self.assertRaises(TypeError):
binascii.a2b_base64(data, alphabet=bytearray(alphabet))
def test_uu(self):
MAX_UU = 45
@@ -0,0 +1,5 @@
Added the *alphabet* parameter in :func:`~binascii.b2a_base64`,
:func:`~binascii.a2b_base64`, :func:`~binascii.b2a_base85` and
:func:`~binascii.a2b_base85` and a number of ``*_ALPHABET`` constants in the
:mod:`binascii` module. Removed :func:`!b2a_z85` and
:func:`!a2b_z85`.
+207 -116
View File
@@ -67,6 +67,7 @@
typedef struct binascii_state {
PyObject *Error;
PyObject *Incomplete;
PyObject *reverse_table_cache;
} binascii_state;
static inline binascii_state *
@@ -228,26 +229,6 @@ static const unsigned char table_a2b_base85_a85[] Py_ALIGNED(64) = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
};
static const unsigned char table_a2b_base85_z85[] Py_ALIGNED(64) = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,68,-1,84, 83,82,72,-1, 75,76,70,65, -1,63,62,69,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,64,-1, 73,66,74,71,
81,36,37,38, 39,40,41,42, 43,44,45,46, 47,48,49,50,
51,52,53,54, 55,56,57,58, 59,60,61,77, -1,78,67,-1,
-1,10,11,12, 13,14,15,16, 17,18,19,20, 21,22,23,24,
25,26,27,28, 29,30,31,32, 33,34,35,79, -1,80,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
};
static const unsigned char table_b2a_base85[] Py_ALIGNED(64) =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
@@ -256,9 +237,6 @@ static const unsigned char table_b2a_base85_a85[] Py_ALIGNED(64) =
"!\"#$%&\'()*+,-./0123456789:;<=>?@" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu";
static const unsigned char table_b2a_base85_z85[] Py_ALIGNED(64) =
"0123456789abcdefghijklmnopqrstuvwxyz" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/\x2a?&<>()[]{}@%$#"; /* clinic doesn't like '/' followed by '*' */
#define BASE85_A85_PREFIX '<'
#define BASE85_A85_AFFIX '~'
@@ -547,6 +525,52 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick)
return PyBytesWriter_FinishWithPointer(writer, ascii_data);
}
static PyObject *
get_reverse_table(binascii_state *state, PyObject *alphabet, int size, int padchar)
{
PyObject *reverse_table;
if (state == NULL) {
return NULL;
}
if (PyBytes_GET_SIZE(alphabet) != size) {
PyErr_Format(PyExc_ValueError, "alphabet must have length %d", size);
return NULL;
}
if (PyDict_GetItemRef(state->reverse_table_cache, alphabet, &reverse_table) < 0) {
return NULL;
}
if (reverse_table == NULL) {
unsigned char out[256];
memset(out, (unsigned char)-1, 256);
const unsigned char *in = (const unsigned char *)PyBytes_AS_STRING(alphabet);
for (int i = 0; i < size; i++) {
out[in[i]] = i;
}
if (padchar >= 0) {
assert(padchar < 256);
out[padchar] = size;
}
reverse_table = PyBytes_FromStringAndSize((char *)out, 256);
if (reverse_table == NULL) {
return NULL;
}
if (PyDict_SetItem(state->reverse_table_cache, alphabet, reverse_table) < 0) {
Py_DECREF(reverse_table);
return NULL;
}
}
else {
if (!PyBytes_Check(reverse_table)
|| PyBytes_GET_SIZE(reverse_table) != 256)
{
PyErr_SetString(PyExc_RuntimeError, "Broken binascii cache");
Py_DECREF(reverse_table);
return NULL;
}
}
return reverse_table;
}
typedef unsigned char ignorecache_t[32];
static int
@@ -576,6 +600,7 @@ binascii.a2b_base64
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.
alphabet: PyBytesObject(c_default="NULL") = BASE64_ALPHABET
ignorechars: Py_buffer = NULL
A byte string containing characters to ignore from the input when
strict_mode is true.
@@ -585,14 +610,16 @@ Decode a line of base64 data.
static PyObject *
binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode,
Py_buffer *ignorechars)
/*[clinic end generated code: output=eab37aea4cfa6daa input=d2d238abf13822ed]*/
PyBytesObject *alphabet, Py_buffer *ignorechars)
/*[clinic end generated code: output=72f15fcc0681d666 input=195c8d60b03aaa6f]*/
{
assert(data->len >= 0);
const unsigned char *ascii_data = data->buf;
size_t ascii_len = data->len;
binascii_state *state = NULL;
PyObject *table_obj = NULL;
const unsigned char *table_a2b = table_a2b_base64;
if (strict_mode == -1) {
strict_mode = (ignorechars->buf != NULL);
@@ -605,10 +632,20 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode,
memset(ignorecache, 0, sizeof(ignorecache));
}
if (alphabet != NULL) {
state = get_binascii_state(module);
table_obj = get_reverse_table(state, (PyObject *)alphabet, 64, BASE64_PAD);
if (table_obj == NULL) {
return NULL;
}
table_a2b = (const unsigned char *)PyBytes_AS_STRING(table_obj);
}
/* Allocate the buffer */
Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */
PyBytesWriter *writer = PyBytesWriter_Create(bin_len);
if (writer == NULL) {
Py_XDECREF(table_obj);
return NULL;
}
unsigned char *bin_data = PyBytesWriter_GetData(writer);
@@ -620,7 +657,7 @@ fastpath:
*/
if (ascii_len >= 4) {
Py_ssize_t fast_chars = base64_decode_fast(ascii_data, (Py_ssize_t)ascii_len,
bin_data, table_a2b_base64);
bin_data, table_a2b);
if (fast_chars > 0) {
ascii_data += fast_chars;
ascii_len -= fast_chars;
@@ -672,7 +709,7 @@ fastpath:
}
}
unsigned char v = table_a2b_base64[this_ch];
unsigned char v = table_a2b[this_ch];
if (v >= 64) {
if (strict_mode && !ignorechar(this_ch, ignorechars, ignorecache)) {
state = get_binascii_state(module);
@@ -749,9 +786,11 @@ fastpath:
}
done:
Py_XDECREF(table_obj);
return PyBytesWriter_FinishWithPointer(writer, bin_data);
error_end:
Py_XDECREF(table_obj);
PyBytesWriter_Discard(writer);
return NULL;
}
@@ -765,19 +804,28 @@ binascii.b2a_base64
*
wrapcol: size_t = 0
newline: bool = True
alphabet: Py_buffer(c_default="{NULL, NULL}") = BASE64_ALPHABET
Base64-code line of data.
[clinic start generated code]*/
static PyObject *
binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, size_t wrapcol,
int newline)
/*[clinic end generated code: output=2edc7311a9515eac input=2ee4214e6d489e2e]*/
int newline, Py_buffer *alphabet)
/*[clinic end generated code: output=9d9657e5fbe28c64 input=ffa3af8520c312ac]*/
{
const unsigned char *table_b2a = table_b2a_base64;
const unsigned char *bin_data = data->buf;
Py_ssize_t bin_len = data->len;
assert(bin_len >= 0);
if (alphabet->buf != NULL) {
if (alphabet->len != 64) {
PyErr_SetString(PyExc_ValueError, "alphabet must have length 64");
return NULL;
}
table_b2a = alphabet->buf;
}
/* Each group of 3 bytes (rounded up) gets encoded as 4 characters,
* not counting newlines.
* Note that 'b' gets encoded as 'Yg==' (1 in, 4 out).
@@ -809,7 +857,7 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, size_t wrapcol,
/* Use the optimized fast path for complete 3-byte groups */
Py_ssize_t fast_bytes = base64_encode_fast(bin_data, bin_len, ascii_data,
table_b2a_base64);
table_b2a);
bin_data += fast_bytes;
ascii_data += (fast_bytes / 3) * 4;
bin_len -= fast_bytes;
@@ -818,17 +866,17 @@ binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, size_t wrapcol,
if (bin_len == 1) {
/* 1 byte remaining: produces 2 base64 chars + 2 padding */
unsigned int val = bin_data[0];
*ascii_data++ = table_b2a_base64[(val >> 2) & 0x3f];
*ascii_data++ = table_b2a_base64[(val << 4) & 0x3f];
*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 */
unsigned int val = ((unsigned int)bin_data[0] << 8) | bin_data[1];
*ascii_data++ = table_b2a_base64[(val >> 10) & 0x3f];
*ascii_data++ = table_b2a_base64[(val >> 4) & 0x3f];
*ascii_data++ = table_b2a_base64[(val << 2) & 0x3f];
*ascii_data++ = table_b2a[(val >> 10) & 0x3f];
*ascii_data++ = table_b2a[(val >> 4) & 0x3f];
*ascii_data++ = table_b2a[(val << 2) & 0x3f];
*ascii_data++ = BASE64_PAD;
}
@@ -1123,13 +1171,36 @@ binascii_b2a_ascii85_impl(PyObject *module, Py_buffer *data, int foldspaces,
return PyBytesWriter_FinishWithPointer(writer, ascii_data);
}
/*[clinic input]
binascii.a2b_base85
data: ascii_buffer
/
*
alphabet: PyBytesObject(c_default="NULL") = BASE85_ALPHABET
Decode a line of Base85 data.
[clinic start generated code]*/
static PyObject *
base85_decode_impl(PyObject *module, Py_buffer *data,
const unsigned char table_a2b[], const char *name)
binascii_a2b_base85_impl(PyObject *module, Py_buffer *data,
PyBytesObject *alphabet)
/*[clinic end generated code: output=3e114af53812e8ff input=0b6b83b38ad4497c]*/
{
const unsigned char *ascii_data = data->buf;
Py_ssize_t ascii_len = data->len;
binascii_state *state = NULL;
PyObject *table_obj = NULL;
const unsigned char *table_a2b = table_a2b_base85;
if (alphabet != NULL) {
state = get_binascii_state(module);
table_obj = get_reverse_table(state, (PyObject *)alphabet, 85, -1);
if (table_obj == NULL) {
return NULL;
}
table_a2b = (const unsigned char *)PyBytes_AS_STRING(table_obj);
}
assert(ascii_len >= 0);
@@ -1137,6 +1208,7 @@ base85_decode_impl(PyObject *module, Py_buffer *data,
size_t bin_len = ((size_t)ascii_len + 4) / 5 * 4;
PyBytesWriter *writer = PyBytesWriter_Create(bin_len);
if (writer == NULL) {
Py_XDECREF(table_obj);
return NULL;
}
unsigned char *bin_data = PyBytesWriter_GetData(writer);
@@ -1162,8 +1234,8 @@ base85_decode_impl(PyObject *module, Py_buffer *data,
state = get_binascii_state(module);
if (state != NULL) {
PyErr_Format(state->Error,
"%s overflow in hunk starting at byte %d",
name, (data->len - ascii_len) / 5 * 5);
"Base85 overflow in hunk starting at byte %d",
(data->len - ascii_len) / 5 * 5);
}
goto error;
}
@@ -1173,8 +1245,8 @@ base85_decode_impl(PyObject *module, Py_buffer *data,
else {
state = get_binascii_state(module);
if (state != NULL) {
PyErr_Format(state->Error, "bad %s character at position %d",
name, data->len - ascii_len);
PyErr_Format(state->Error, "bad Base85 character at position %d",
data->len - ascii_len);
}
goto error;
}
@@ -1194,19 +1266,44 @@ base85_decode_impl(PyObject *module, Py_buffer *data,
leftchar = 0;
}
Py_XDECREF(table_obj);
return PyBytesWriter_FinishWithPointer(writer, bin_data);
error:
PyBytesWriter_Discard(writer);
Py_XDECREF(table_obj);
return NULL;
}
/*[clinic input]
binascii.b2a_base85
data: Py_buffer
/
*
pad: bool = False
Pad input to a multiple of 4 before encoding.
alphabet: Py_buffer(c_default="{NULL, NULL}") = BASE85_ALPHABET
Base85-code line of data.
[clinic start generated code]*/
static PyObject *
base85_encode_impl(PyObject *module, Py_buffer *data, int pad,
const unsigned char table_b2a[], const char *name)
binascii_b2a_base85_impl(PyObject *module, Py_buffer *data, int pad,
Py_buffer *alphabet)
/*[clinic end generated code: output=a59f4f2ff6f0e69f input=30f545c6ff554db7]*/
{
const unsigned char *bin_data = data->buf;
Py_ssize_t bin_len = data->len;
const unsigned char *table_b2a = table_b2a_base85;
if (alphabet->buf != NULL) {
if (alphabet->len != 85) {
PyErr_SetString(PyExc_ValueError, "alphabet must have length 85");
return NULL;
}
table_b2a = alphabet->buf;
}
assert(bin_len >= 0);
@@ -1220,7 +1317,7 @@ base85_encode_impl(PyObject *module, Py_buffer *data, int pad,
if (state == NULL) {
return NULL;
}
PyErr_Format(state->Error, "Too much data for %s", name);
PyErr_SetString(state->Error, "Too much data for Base85");
return NULL;
}
@@ -1270,76 +1367,6 @@ base85_encode_impl(PyObject *module, Py_buffer *data, int pad,
return PyBytesWriter_FinishWithPointer(writer, ascii_data);
}
/*[clinic input]
binascii.a2b_base85
data: ascii_buffer
/
Decode a line of Base85 data.
[clinic start generated code]*/
static PyObject *
binascii_a2b_base85_impl(PyObject *module, Py_buffer *data)
/*[clinic end generated code: output=c2db6ab9181b0089 input=06c9d595352b5a2b]*/
{
return base85_decode_impl(module, data, table_a2b_base85, "Base85");
}
/*[clinic input]
binascii.b2a_base85
data: Py_buffer
/
*
pad: bool = False
Pad input to a multiple of 4 before encoding.
Base85-code line of data.
[clinic start generated code]*/
static PyObject *
binascii_b2a_base85_impl(PyObject *module, Py_buffer *data, int pad)
/*[clinic end generated code: output=b317adb36a57740d input=89fde81b96dcec06]*/
{
return base85_encode_impl(module, data, pad, table_b2a_base85, "Base85");
}
/*[clinic input]
binascii.a2b_z85
data: ascii_buffer
/
Decode a line of Z85 data.
[clinic start generated code]*/
static PyObject *
binascii_a2b_z85_impl(PyObject *module, Py_buffer *data)
/*[clinic end generated code: output=57d8260bb5267a98 input=c54baff4d81510a4]*/
{
return base85_decode_impl(module, data, table_a2b_base85_z85, "Z85");
}
/*[clinic input]
binascii.b2a_z85
data: Py_buffer
/
*
pad: bool = False
Pad input to a multiple of 4 before encoding.
Z85-code line of data.
[clinic start generated code]*/
static PyObject *
binascii_b2a_z85_impl(PyObject *module, Py_buffer *data, int pad)
/*[clinic end generated code: output=88284835e332c9cf input=51d070a5a6cf82d8]*/
{
return base85_encode_impl(module, data, pad, table_b2a_base85_z85, "Z85");
}
/*[clinic input]
binascii.crc_hqx
@@ -2001,8 +2028,6 @@ static struct PyMethodDef binascii_module_methods[] = {
BINASCII_A2B_ASCII85_METHODDEF
BINASCII_A2B_BASE85_METHODDEF
BINASCII_B2A_BASE85_METHODDEF
BINASCII_A2B_Z85_METHODDEF
BINASCII_B2A_Z85_METHODDEF
BINASCII_A2B_HEX_METHODDEF
BINASCII_B2A_HEX_METHODDEF
BINASCII_HEXLIFY_METHODDEF
@@ -2036,6 +2061,70 @@ binascii_exec(PyObject *module)
return -1;
}
if (PyModule_Add(module, "BASE64_ALPHABET",
PyBytes_FromStringAndSize((const char *)table_b2a_base64, 64)) < 0)
{
return -1;
}
if (PyModule_Add(module, "URLSAFE_BASE64_ALPHABET",
PyBytes_FromString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789-_")) < 0)
{
return -1;
}
if (PyModule_Add(module, "CRYPT_ALPHABET",
PyBytes_FromString("./0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz")) < 0)
{
return -1;
}
if (PyModule_Add(module, "UU_ALPHABET",
PyBytes_FromString(" !\"#$%&'()*+,-./"
"0123456789:;<=>?@"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"[\\]^_")) < 0)
{
return -1;
}
if (PyModule_Add(module, "BINHEX_ALPHABET",
PyBytes_FromString("!\"#$%&'()*+,-012345689@"
"ABCDEFGHIJKLMNPQRSTUVXYZ[`"
"abcdefhijklmpqr")) < 0)
{
return -1;
}
if (PyModule_Add(module, "BASE85_ALPHABET",
PyBytes_FromStringAndSize((const char *)table_b2a_base85, 85)) < 0)
{
return -1;
}
if (PyModule_Add(module, "ASCII85_ALPHABET",
PyBytes_FromStringAndSize((const char *)table_b2a_base85_a85, 85)) < 0)
{
return -1;
}
if (PyModule_Add(module, "Z85_ALPHABET",
PyBytes_FromString("0123456789"
"abcdefghijklmnopqrstuvwxyz"
/* clinic doesn't like '/' followed by '*' */
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
".-:+=^!/\x2a?&<>()[]{}@%$#")) < 0)
{
return -1;
}
state->reverse_table_cache = PyDict_New();
if (state->reverse_table_cache == NULL) {
return -1;
}
state->reverse_table_cache = PyDict_New();
if (state->reverse_table_cache == NULL) {
return -1;
}
return 0;
}
@@ -2052,6 +2141,7 @@ binascii_traverse(PyObject *module, visitproc visit, void *arg)
binascii_state *state = get_binascii_state(module);
Py_VISIT(state->Error);
Py_VISIT(state->Incomplete);
Py_VISIT(state->reverse_table_cache);
return 0;
}
@@ -2061,6 +2151,7 @@ binascii_clear(PyObject *module)
binascii_state *state = get_binascii_state(module);
Py_CLEAR(state->Error);
Py_CLEAR(state->Incomplete);
Py_CLEAR(state->reverse_table_cache);
return 0;
}
+117 -142
View File
@@ -117,7 +117,7 @@ exit:
PyDoc_STRVAR(binascii_a2b_base64__doc__,
"a2b_base64($module, data, /, *, strict_mode=<unrepresentable>,\n"
" ignorechars=<unrepresentable>)\n"
" alphabet=BASE64_ALPHABET, ignorechars=<unrepresentable>)\n"
"--\n"
"\n"
"Decode a line of base64 data.\n"
@@ -135,7 +135,7 @@ PyDoc_STRVAR(binascii_a2b_base64__doc__,
static PyObject *
binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode,
Py_buffer *ignorechars);
PyBytesObject *alphabet, Py_buffer *ignorechars);
static PyObject *
binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -143,7 +143,7 @@ binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
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
@@ -152,7 +152,7 @@ binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
.ob_item = { &_Py_ID(strict_mode), &_Py_ID(ignorechars), },
.ob_item = { &_Py_ID(strict_mode), &_Py_ID(alphabet), &_Py_ID(ignorechars), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -161,17 +161,18 @@ binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"", "strict_mode", "ignorechars", NULL};
static const char * const _keywords[] = {"", "strict_mode", "alphabet", "ignorechars", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "a2b_base64",
.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 strict_mode = -1;
PyBytesObject *alphabet = NULL;
Py_buffer ignorechars = {NULL, NULL};
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
@@ -194,11 +195,21 @@ binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
goto skip_optional_kwonly;
}
}
if (PyObject_GetBuffer(args[2], &ignorechars, PyBUF_SIMPLE) != 0) {
if (args[2]) {
if (!PyBytes_Check(args[2])) {
_PyArg_BadArgument("a2b_base64", "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_base64_impl(module, &data, strict_mode, &ignorechars);
return_value = binascii_a2b_base64_impl(module, &data, strict_mode, alphabet, &ignorechars);
exit:
/* Cleanup for data */
@@ -213,7 +224,8 @@ exit:
}
PyDoc_STRVAR(binascii_b2a_base64__doc__,
"b2a_base64($module, data, /, *, wrapcol=0, newline=True)\n"
"b2a_base64($module, data, /, *, wrapcol=0, newline=True,\n"
" alphabet=BASE64_ALPHABET)\n"
"--\n"
"\n"
"Base64-code line of data.");
@@ -223,7 +235,7 @@ PyDoc_STRVAR(binascii_b2a_base64__doc__,
static PyObject *
binascii_b2a_base64_impl(PyObject *module, Py_buffer *data, size_t wrapcol,
int newline);
int newline, Py_buffer *alphabet);
static PyObject *
binascii_b2a_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -231,7 +243,7 @@ binascii_b2a_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
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
@@ -240,7 +252,7 @@ binascii_b2a_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
.ob_item = { &_Py_ID(wrapcol), &_Py_ID(newline), },
.ob_item = { &_Py_ID(wrapcol), &_Py_ID(newline), &_Py_ID(alphabet), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -249,18 +261,19 @@ binascii_b2a_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"", "wrapcol", "newline", NULL};
static const char * const _keywords[] = {"", "wrapcol", "newline", "alphabet", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "b2a_base64",
.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};
size_t wrapcol = 0;
int newline = 1;
Py_buffer alphabet = {NULL, NULL};
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -281,18 +294,30 @@ binascii_b2a_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
goto skip_optional_kwonly;
}
}
newline = PyObject_IsTrue(args[2]);
if (newline < 0) {
if (args[2]) {
newline = PyObject_IsTrue(args[2]);
if (newline < 0) {
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_base64_impl(module, &data, wrapcol, newline);
return_value = binascii_b2a_base64_impl(module, &data, wrapcol, newline, &alphabet);
exit:
/* Cleanup for data */
if (data.obj) {
PyBuffer_Release(&data);
}
/* Cleanup for alphabet */
if (alphabet.obj) {
PyBuffer_Release(&alphabet);
}
return return_value;
}
@@ -519,27 +544,72 @@ exit:
}
PyDoc_STRVAR(binascii_a2b_base85__doc__,
"a2b_base85($module, data, /)\n"
"a2b_base85($module, data, /, *, alphabet=BASE85_ALPHABET)\n"
"--\n"
"\n"
"Decode a line of Base85 data.");
#define BINASCII_A2B_BASE85_METHODDEF \
{"a2b_base85", (PyCFunction)binascii_a2b_base85, METH_O, binascii_a2b_base85__doc__},
{"a2b_base85", _PyCFunction_CAST(binascii_a2b_base85), METH_FASTCALL|METH_KEYWORDS, binascii_a2b_base85__doc__},
static PyObject *
binascii_a2b_base85_impl(PyObject *module, Py_buffer *data);
binascii_a2b_base85_impl(PyObject *module, Py_buffer *data,
PyBytesObject *alphabet);
static PyObject *
binascii_a2b_base85(PyObject *module, PyObject *arg)
binascii_a2b_base85(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
Py_buffer data = {NULL, NULL};
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
if (!ascii_buffer_converter(arg, &data)) {
#define NUM_KEYWORDS 1
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
Py_hash_t ob_hash;
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
.ob_item = { &_Py_ID(alphabet), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
#else // !Py_BUILD_CORE
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"", "alphabet", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "a2b_base85",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
Py_buffer data = {NULL, NULL};
PyBytesObject *alphabet = NULL;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!args) {
goto exit;
}
return_value = binascii_a2b_base85_impl(module, &data);
if (!ascii_buffer_converter(args[0], &data)) {
goto exit;
}
if (!noptargs) {
goto skip_optional_kwonly;
}
if (!PyBytes_Check(args[1])) {
_PyArg_BadArgument("a2b_base85", "argument 'alphabet'", "bytes", args[1]);
goto exit;
}
alphabet = (PyBytesObject *)args[1];
skip_optional_kwonly:
return_value = binascii_a2b_base85_impl(module, &data, alphabet);
exit:
/* Cleanup for data */
@@ -550,7 +620,7 @@ exit:
}
PyDoc_STRVAR(binascii_b2a_base85__doc__,
"b2a_base85($module, data, /, *, pad=False)\n"
"b2a_base85($module, data, /, *, pad=False, alphabet=BASE85_ALPHABET)\n"
"--\n"
"\n"
"Base85-code line of data.\n"
@@ -562,7 +632,8 @@ PyDoc_STRVAR(binascii_b2a_base85__doc__,
{"b2a_base85", _PyCFunction_CAST(binascii_b2a_base85), METH_FASTCALL|METH_KEYWORDS, binascii_b2a_base85__doc__},
static PyObject *
binascii_b2a_base85_impl(PyObject *module, Py_buffer *data, int pad);
binascii_b2a_base85_impl(PyObject *module, Py_buffer *data, int pad,
Py_buffer *alphabet);
static PyObject *
binascii_b2a_base85(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -570,7 +641,7 @@ binascii_b2a_base85(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
PyObject *return_value = NULL;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 1
#define NUM_KEYWORDS 2
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
@@ -579,7 +650,7 @@ binascii_b2a_base85(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
.ob_item = { &_Py_ID(pad), },
.ob_item = { &_Py_ID(pad), &_Py_ID(alphabet), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -588,17 +659,18 @@ binascii_b2a_base85(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"", "pad", NULL};
static const char * const _keywords[] = {"", "pad", "alphabet", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "b2a_base85",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[2];
PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
Py_buffer data = {NULL, NULL};
int pad = 0;
Py_buffer alphabet = {NULL, NULL};
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
@@ -611,126 +683,29 @@ binascii_b2a_base85(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P
if (!noptargs) {
goto skip_optional_kwonly;
}
pad = PyObject_IsTrue(args[1]);
if (pad < 0) {
if (args[1]) {
pad = PyObject_IsTrue(args[1]);
if (pad < 0) {
goto exit;
}
if (!--noptargs) {
goto skip_optional_kwonly;
}
}
if (PyObject_GetBuffer(args[2], &alphabet, PyBUF_SIMPLE) != 0) {
goto exit;
}
skip_optional_kwonly:
return_value = binascii_b2a_base85_impl(module, &data, pad);
return_value = binascii_b2a_base85_impl(module, &data, pad, &alphabet);
exit:
/* Cleanup for data */
if (data.obj) {
PyBuffer_Release(&data);
}
return return_value;
}
PyDoc_STRVAR(binascii_a2b_z85__doc__,
"a2b_z85($module, data, /)\n"
"--\n"
"\n"
"Decode a line of Z85 data.");
#define BINASCII_A2B_Z85_METHODDEF \
{"a2b_z85", (PyCFunction)binascii_a2b_z85, METH_O, binascii_a2b_z85__doc__},
static PyObject *
binascii_a2b_z85_impl(PyObject *module, Py_buffer *data);
static PyObject *
binascii_a2b_z85(PyObject *module, PyObject *arg)
{
PyObject *return_value = NULL;
Py_buffer data = {NULL, NULL};
if (!ascii_buffer_converter(arg, &data)) {
goto exit;
}
return_value = binascii_a2b_z85_impl(module, &data);
exit:
/* Cleanup for data */
if (data.obj)
PyBuffer_Release(&data);
return return_value;
}
PyDoc_STRVAR(binascii_b2a_z85__doc__,
"b2a_z85($module, data, /, *, pad=False)\n"
"--\n"
"\n"
"Z85-code line of data.\n"
"\n"
" pad\n"
" Pad input to a multiple of 4 before encoding.");
#define BINASCII_B2A_Z85_METHODDEF \
{"b2a_z85", _PyCFunction_CAST(binascii_b2a_z85), METH_FASTCALL|METH_KEYWORDS, binascii_b2a_z85__doc__},
static PyObject *
binascii_b2a_z85_impl(PyObject *module, Py_buffer *data, int pad);
static PyObject *
binascii_b2a_z85(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 1
static struct {
PyGC_Head _this_is_not_used;
PyObject_VAR_HEAD
Py_hash_t ob_hash;
PyObject *ob_item[NUM_KEYWORDS];
} _kwtuple = {
.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
.ob_hash = -1,
.ob_item = { &_Py_ID(pad), },
};
#undef NUM_KEYWORDS
#define KWTUPLE (&_kwtuple.ob_base.ob_base)
#else // !Py_BUILD_CORE
# define KWTUPLE NULL
#endif // !Py_BUILD_CORE
static const char * const _keywords[] = {"", "pad", NULL};
static _PyArg_Parser _parser = {
.keywords = _keywords,
.fname = "b2a_z85",
.kwtuple = KWTUPLE,
};
#undef KWTUPLE
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
Py_buffer data = {NULL, NULL};
int pad = 0;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
/*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
if (!args) {
goto exit;
}
if (PyObject_GetBuffer(args[0], &data, PyBUF_SIMPLE) != 0) {
goto exit;
}
if (!noptargs) {
goto skip_optional_kwonly;
}
pad = PyObject_IsTrue(args[1]);
if (pad < 0) {
goto exit;
}
skip_optional_kwonly:
return_value = binascii_b2a_z85_impl(module, &data, pad);
exit:
/* Cleanup for data */
if (data.obj) {
PyBuffer_Release(&data);
/* Cleanup for alphabet */
if (alphabet.obj) {
PyBuffer_Release(&alphabet);
}
return return_value;
@@ -1281,4 +1256,4 @@ exit:
return return_value;
}
/*[clinic end generated code: output=5c53e7e185700742 input=a9049054013a1b77]*/
/*[clinic end generated code: output=84c97096b0fb3819 input=a9049054013a1b77]*/