mirror of https://github.com/python/cpython
Issue #25357: Add an optional newline paramer to binascii.b2a_base64().
base64.b64encode() uses it to avoid a memory copy.
This commit is contained in:
parent
5df7fddc0c
commit
e84c976568
|
@ -52,11 +52,16 @@ The :mod:`binascii` module defines the following functions:
|
||||||
than one line may be passed at a time.
|
than one line may be passed at a time.
|
||||||
|
|
||||||
|
|
||||||
.. function:: b2a_base64(data)
|
.. function:: b2a_base64(data, \*, newline=True)
|
||||||
|
|
||||||
Convert binary data to a line of ASCII characters in base64 coding. The return
|
Convert binary data to a line of ASCII characters in base64 coding. The return
|
||||||
value is the converted line, including a newline char. The length of *data*
|
value is the converted line, including a newline char if *newline* is
|
||||||
should be at most 57 to adhere to the base64 standard.
|
true. The length of *data* should be at most 57 to adhere to the
|
||||||
|
base64 standard.
|
||||||
|
|
||||||
|
|
||||||
|
.. versionchanged:: 3.6
|
||||||
|
Added the *newline* parameter.
|
||||||
|
|
||||||
|
|
||||||
.. function:: a2b_qp(data, header=False)
|
.. function:: a2b_qp(data, header=False)
|
||||||
|
|
|
@ -58,8 +58,7 @@ def b64encode(s, altchars=None):
|
||||||
|
|
||||||
The encoded byte string is returned.
|
The encoded byte string is returned.
|
||||||
"""
|
"""
|
||||||
# Strip off the trailing newline
|
encoded = binascii.b2a_base64(s, newline=False)
|
||||||
encoded = binascii.b2a_base64(s)[:-1]
|
|
||||||
if altchars is not None:
|
if altchars is not None:
|
||||||
assert len(altchars) == 2, repr(altchars)
|
assert len(altchars) == 2, repr(altchars)
|
||||||
return encoded.translate(bytes.maketrans(b'+/', altchars))
|
return encoded.translate(bytes.maketrans(b'+/', altchars))
|
||||||
|
|
|
@ -262,6 +262,16 @@ class BinASCIITest(unittest.TestCase):
|
||||||
# non-ASCII string
|
# non-ASCII string
|
||||||
self.assertRaises(ValueError, a2b, "\x80")
|
self.assertRaises(ValueError, a2b, "\x80")
|
||||||
|
|
||||||
|
def test_b2a_base64_newline(self):
|
||||||
|
# Issue #25357: test newline parameter
|
||||||
|
b = self.type2test(b'hello')
|
||||||
|
self.assertEqual(binascii.b2a_base64(b),
|
||||||
|
b'aGVsbG8=\n')
|
||||||
|
self.assertEqual(binascii.b2a_base64(b, newline=True),
|
||||||
|
b'aGVsbG8=\n')
|
||||||
|
self.assertEqual(binascii.b2a_base64(b, newline=False),
|
||||||
|
b'aGVsbG8=')
|
||||||
|
|
||||||
|
|
||||||
class ArrayBinASCIITest(BinASCIITest):
|
class ArrayBinASCIITest(BinASCIITest):
|
||||||
def type2test(self, s):
|
def type2test(self, s):
|
||||||
|
|
|
@ -51,6 +51,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #25357: Add an optional newline paramer to binascii.b2a_base64().
|
||||||
|
base64.b64encode() uses it to avoid a memory copy.
|
||||||
|
|
||||||
- Issue #24164: Objects that need calling ``__new__`` with keyword arguments,
|
- Issue #24164: Objects that need calling ``__new__`` with keyword arguments,
|
||||||
can now be pickled using pickle protocols older than protocol version 4.
|
can now be pickled using pickle protocols older than protocol version 4.
|
||||||
|
|
||||||
|
|
|
@ -528,21 +528,22 @@ binascii_a2b_base64_impl(PyModuleDef *module, Py_buffer *data)
|
||||||
binascii.b2a_base64
|
binascii.b2a_base64
|
||||||
|
|
||||||
data: Py_buffer
|
data: Py_buffer
|
||||||
/
|
*
|
||||||
|
newline: int(c_default="1") = True
|
||||||
|
|
||||||
Base64-code line of data.
|
Base64-code line of data.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data)
|
binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data, int newline)
|
||||||
/*[clinic end generated code: output=3cd61fbee2913285 input=14ec4e47371174a9]*/
|
/*[clinic end generated code: output=19e1dd719a890b50 input=7b2ea6fa38d8924c]*/
|
||||||
{
|
{
|
||||||
unsigned char *ascii_data, *bin_data;
|
unsigned char *ascii_data, *bin_data;
|
||||||
int leftbits = 0;
|
int leftbits = 0;
|
||||||
unsigned char this_ch;
|
unsigned char this_ch;
|
||||||
unsigned int leftchar = 0;
|
unsigned int leftchar = 0;
|
||||||
PyObject *rv;
|
PyObject *rv;
|
||||||
Py_ssize_t bin_len;
|
Py_ssize_t bin_len, out_len;
|
||||||
|
|
||||||
bin_data = data->buf;
|
bin_data = data->buf;
|
||||||
bin_len = data->len;
|
bin_len = data->len;
|
||||||
|
@ -555,9 +556,12 @@ binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We're lazy and allocate too much (fixed up later).
|
/* We're lazy and allocate too much (fixed up later).
|
||||||
"+3" leaves room for up to two pad characters and a trailing
|
"+2" leaves room for up to two pad characters.
|
||||||
newline. Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */
|
Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */
|
||||||
if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len*2 + 3)) == NULL )
|
out_len = bin_len*2 + 2;
|
||||||
|
if (newline)
|
||||||
|
out_len++;
|
||||||
|
if ( (rv=PyBytes_FromStringAndSize(NULL, out_len)) == NULL )
|
||||||
return NULL;
|
return NULL;
|
||||||
ascii_data = (unsigned char *)PyBytes_AS_STRING(rv);
|
ascii_data = (unsigned char *)PyBytes_AS_STRING(rv);
|
||||||
|
|
||||||
|
@ -581,6 +585,7 @@ binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data)
|
||||||
*ascii_data++ = table_b2a_base64[(leftchar&0xf) << 2];
|
*ascii_data++ = table_b2a_base64[(leftchar&0xf) << 2];
|
||||||
*ascii_data++ = BASE64_PAD;
|
*ascii_data++ = BASE64_PAD;
|
||||||
}
|
}
|
||||||
|
if (newline)
|
||||||
*ascii_data++ = '\n'; /* Append a courtesy newline */
|
*ascii_data++ = '\n'; /* Append a courtesy newline */
|
||||||
|
|
||||||
if (_PyBytes_Resize(&rv,
|
if (_PyBytes_Resize(&rv,
|
||||||
|
|
|
@ -93,26 +93,29 @@ exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(binascii_b2a_base64__doc__,
|
PyDoc_STRVAR(binascii_b2a_base64__doc__,
|
||||||
"b2a_base64($module, data, /)\n"
|
"b2a_base64($module, /, data, *, newline=True)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Base64-code line of data.");
|
"Base64-code line of data.");
|
||||||
|
|
||||||
#define BINASCII_B2A_BASE64_METHODDEF \
|
#define BINASCII_B2A_BASE64_METHODDEF \
|
||||||
{"b2a_base64", (PyCFunction)binascii_b2a_base64, METH_O, binascii_b2a_base64__doc__},
|
{"b2a_base64", (PyCFunction)binascii_b2a_base64, METH_VARARGS|METH_KEYWORDS, binascii_b2a_base64__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data);
|
binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data, int newline);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
binascii_b2a_base64(PyModuleDef *module, PyObject *arg)
|
binascii_b2a_base64(PyModuleDef *module, PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
|
static char *_keywords[] = {"data", "newline", NULL};
|
||||||
Py_buffer data = {NULL, NULL};
|
Py_buffer data = {NULL, NULL};
|
||||||
|
int newline = 1;
|
||||||
|
|
||||||
if (!PyArg_Parse(arg, "y*:b2a_base64", &data))
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|$i:b2a_base64", _keywords,
|
||||||
|
&data, &newline))
|
||||||
goto exit;
|
goto exit;
|
||||||
return_value = binascii_b2a_base64_impl(module, &data);
|
return_value = binascii_b2a_base64_impl(module, &data, newline);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
/* Cleanup for data */
|
/* Cleanup for data */
|
||||||
|
@ -516,4 +519,4 @@ exit:
|
||||||
|
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=b1a3cbf7660ebaa5 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=b15a24350d105251 input=a9049054013a1b77]*/
|
||||||
|
|
Loading…
Reference in New Issue