[Python-checkins] python/dist/src/Modules binascii.c,2.35,2.36
tim_one@users.sourceforge.net
tim_one@users.sourceforge.net
Tue, 02 Jul 2002 15:24:52 -0700
Update of /cvsroot/python/python/dist/src/Modules
In directory usw-pr-cvs1:/tmp/cvs-serv19094/python/Modules
Modified Files:
binascii.c
Log Message:
Another stab at SF 576327: zipfile when sizeof(long) == 8
binascii_crc32(): The previous patch forced this to return the same
result across platforms. This patch deals with that, on a 64-bit box,
the *entry* value may have "unexpected" bits in the high four bytes.
Bugfix candidate.
Index: binascii.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/binascii.c,v
retrieving revision 2.35
retrieving revision 2.36
diff -C2 -d -r2.35 -r2.36
*** binascii.c 2 Jul 2002 20:20:08 -0000 2.35
--- binascii.c 2 Jul 2002 22:24:50 -0000 2.36
***************
*** 43,53 ****
**
** Jack Jansen, CWI, July 1995.
! **
** Added support for quoted-printable encoding, based on rfc 1521 et al
! ** quoted-printable encoding specifies that non printable characters (anything
** below 32 and above 126) be encoded as =XX where XX is the hexadecimal value
** of the character. It also specifies some other behavior to enable 8bit data
! ** in a mail message with little difficulty (maximum line sizes, protecting
! ** some cases of whitespace, etc).
**
** Brandon Long, September 2001.
--- 43,53 ----
**
** Jack Jansen, CWI, July 1995.
! **
** Added support for quoted-printable encoding, based on rfc 1521 et al
! ** quoted-printable encoding specifies that non printable characters (anything
** below 32 and above 126) be encoded as =XX where XX is the hexadecimal value
** of the character. It also specifies some other behavior to enable 8bit data
! ** in a mail message with little difficulty (maximum line sizes, protecting
! ** some cases of whitespace, etc).
**
** Brandon Long, September 2001.
***************
*** 191,195 ****
PyObject *rv;
int ascii_len, bin_len;
!
if ( !PyArg_ParseTuple(args, "t#:a2b_uu", &ascii_data, &ascii_len) )
return NULL;
--- 191,195 ----
PyObject *rv;
int ascii_len, bin_len;
!
if ( !PyArg_ParseTuple(args, "t#:a2b_uu", &ascii_data, &ascii_len) )
return NULL;
***************
*** 203,207 ****
return NULL;
bin_data = (unsigned char *)PyString_AsString(rv);
!
for( ; bin_len > 0 ; ascii_len--, ascii_data++ ) {
this_ch = *ascii_data;
--- 203,207 ----
return NULL;
bin_data = (unsigned char *)PyString_AsString(rv);
!
for( ; bin_len > 0 ; ascii_len--, ascii_data++ ) {
this_ch = *ascii_data;
***************
*** 256,260 ****
PyDoc_STRVAR(doc_b2a_uu, "(bin) -> ascii. Uuencode line of data");
!
static PyObject *
binascii_b2a_uu(PyObject *self, PyObject *args)
--- 256,260 ----
PyDoc_STRVAR(doc_b2a_uu, "(bin) -> ascii. Uuencode line of data");
!
static PyObject *
binascii_b2a_uu(PyObject *self, PyObject *args)
***************
*** 266,270 ****
PyObject *rv;
int bin_len;
!
if ( !PyArg_ParseTuple(args, "s#:b2a_uu", &bin_data, &bin_len) )
return NULL;
--- 266,270 ----
PyObject *rv;
int bin_len;
!
if ( !PyArg_ParseTuple(args, "s#:b2a_uu", &bin_data, &bin_len) )
return NULL;
***************
*** 282,286 ****
/* Store the length */
*ascii_data++ = ' ' + (bin_len & 077);
!
for( ; bin_len > 0 || leftbits != 0 ; bin_len--, bin_data++ ) {
/* Shift the data (or padding) into our buffer */
--- 282,286 ----
/* Store the length */
*ascii_data++ = ' ' + (bin_len & 077);
!
for( ; bin_len > 0 || leftbits != 0 ; bin_len--, bin_data++ ) {
/* Shift the data (or padding) into our buffer */
***************
*** 299,303 ****
}
*ascii_data++ = '\n'; /* Append a courtesy newline */
!
_PyString_Resize(&rv, (ascii_data -
(unsigned char *)PyString_AsString(rv)));
--- 299,303 ----
}
*ascii_data++ = '\n'; /* Append a courtesy newline */
!
_PyString_Resize(&rv, (ascii_data -
(unsigned char *)PyString_AsString(rv)));
***************
*** 309,313 ****
binascii_find_valid(unsigned char *s, int slen, int num)
{
! /* Finds & returns the (num+1)th
** valid character for base64, or -1 if none.
*/
--- 309,313 ----
binascii_find_valid(unsigned char *s, int slen, int num)
{
! /* Finds & returns the (num+1)th
** valid character for base64, or -1 if none.
*/
***************
*** 343,347 ****
int ascii_len, bin_len;
int quad_pos = 0;
!
if ( !PyArg_ParseTuple(args, "t#:a2b_base64", &ascii_data, &ascii_len) )
return NULL;
--- 343,347 ----
int ascii_len, bin_len;
int quad_pos = 0;
!
if ( !PyArg_ParseTuple(args, "t#:a2b_base64", &ascii_data, &ascii_len) )
return NULL;
***************
*** 419,423 ****
PyDoc_STRVAR(doc_b2a_base64, "(bin) -> ascii. Base64-code line of data");
!
static PyObject *
binascii_b2a_base64(PyObject *self, PyObject *args)
--- 419,423 ----
PyDoc_STRVAR(doc_b2a_base64, "(bin) -> ascii. Base64-code line of data");
!
static PyObject *
binascii_b2a_base64(PyObject *self, PyObject *args)
***************
*** 429,433 ****
PyObject *rv;
int bin_len;
!
if ( !PyArg_ParseTuple(args, "s#:b2a_base64", &bin_data, &bin_len) )
return NULL;
--- 429,433 ----
PyObject *rv;
int bin_len;
!
if ( !PyArg_ParseTuple(args, "s#:b2a_base64", &bin_data, &bin_len) )
return NULL;
***************
*** 436,440 ****
return NULL;
}
!
/* We're lazy and allocate too much (fixed up later).
"+3" leaves room for up to two pad characters and a trailing
--- 436,440 ----
return NULL;
}
!
/* We're lazy and allocate too much (fixed up later).
"+3" leaves room for up to two pad characters and a trailing
***************
*** 463,469 ****
*ascii_data++ = table_b2a_base64[(leftchar&0xf) << 2];
*ascii_data++ = BASE64_PAD;
! }
*ascii_data++ = '\n'; /* Append a courtesy newline */
!
_PyString_Resize(&rv, (ascii_data -
(unsigned char *)PyString_AsString(rv)));
--- 463,469 ----
*ascii_data++ = table_b2a_base64[(leftchar&0xf) << 2];
*ascii_data++ = BASE64_PAD;
! }
*ascii_data++ = '\n'; /* Append a courtesy newline */
!
_PyString_Resize(&rv, (ascii_data -
(unsigned char *)PyString_AsString(rv)));
***************
*** 483,487 ****
int len;
int done = 0;
!
if ( !PyArg_ParseTuple(args, "t#:a2b_hqx", &ascii_data, &len) )
return NULL;
--- 483,487 ----
int len;
int done = 0;
!
if ( !PyArg_ParseTuple(args, "t#:a2b_hqx", &ascii_data, &len) )
return NULL;
***************
*** 517,521 ****
}
}
!
if ( leftbits && !done ) {
PyErr_SetString(Incomplete,
--- 517,521 ----
}
}
!
if ( leftbits && !done ) {
PyErr_SetString(Incomplete,
***************
*** 544,548 ****
unsigned char ch;
int in, inend, len;
!
if ( !PyArg_ParseTuple(args, "s#:rlecode_hqx", &in_data, &len) )
return NULL;
--- 544,548 ----
unsigned char ch;
int in, inend, len;
!
if ( !PyArg_ParseTuple(args, "s#:rlecode_hqx", &in_data, &len) )
return NULL;
***************
*** 552,556 ****
return NULL;
out_data = (unsigned char *)PyString_AsString(rv);
!
for( in=0; in<len; in++) {
ch = in_data[in];
--- 552,556 ----
return NULL;
out_data = (unsigned char *)PyString_AsString(rv);
!
for( in=0; in<len; in++) {
ch = in_data[in];
***************
*** 583,587 ****
PyDoc_STRVAR(doc_b2a_hqx, "Encode .hqx data");
!
static PyObject *
binascii_b2a_hqx(PyObject *self, PyObject *args)
--- 583,587 ----
PyDoc_STRVAR(doc_b2a_hqx, "Encode .hqx data");
!
static PyObject *
binascii_b2a_hqx(PyObject *self, PyObject *args)
***************
*** 593,597 ****
PyObject *rv;
int len;
!
if ( !PyArg_ParseTuple(args, "s#:b2a_hqx", &bin_data, &len) )
return NULL;
--- 593,597 ----
PyObject *rv;
int len;
!
if ( !PyArg_ParseTuple(args, "s#:b2a_hqx", &bin_data, &len) )
return NULL;
***************
*** 601,605 ****
return NULL;
ascii_data = (unsigned char *)PyString_AsString(rv);
!
for( ; len > 0 ; len--, bin_data++ ) {
/* Shift into our buffer, and output any 6bits ready */
--- 601,605 ----
return NULL;
ascii_data = (unsigned char *)PyString_AsString(rv);
!
for( ; len > 0 ; len--, bin_data++ ) {
/* Shift into our buffer, and output any 6bits ready */
***************
*** 623,627 ****
PyDoc_STRVAR(doc_rledecode_hqx, "Decode hexbin RLE-coded string");
!
static PyObject *
binascii_rledecode_hqx(PyObject *self, PyObject *args)
--- 623,627 ----
PyDoc_STRVAR(doc_rledecode_hqx, "Decode hexbin RLE-coded string");
!
static PyObject *
binascii_rledecode_hqx(PyObject *self, PyObject *args)
***************
*** 659,663 ****
b = *in_data++; \
} while(0)
!
#define OUTBYTE(b) \
do { \
--- 659,663 ----
b = *in_data++; \
} while(0)
!
#define OUTBYTE(b) \
do { \
***************
*** 693,697 ****
OUTBYTE(in_byte);
}
!
while( in_len > 0 ) {
INBYTE(in_byte);
--- 693,697 ----
OUTBYTE(in_byte);
}
!
while( in_len > 0 ) {
INBYTE(in_byte);
***************
*** 727,731 ****
unsigned int crc;
int len;
!
if ( !PyArg_ParseTuple(args, "s#i:crc_hqx", &bin_data, &len, &crc) )
return NULL;
--- 727,731 ----
unsigned int crc;
int len;
!
if ( !PyArg_ParseTuple(args, "s#i:crc_hqx", &bin_data, &len, &crc) )
return NULL;
***************
*** 759,805 ****
Copyright (C) 1986 Gary S. Brown. You may use this program, or
code or tables extracted from it, as desired without restriction.
-
- First, the polynomial itself and its table of feedback terms. The
- polynomial is
- X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
- Note that we take it "backwards" and put the highest-order term in
- the lowest-order bit. The X^32 term is "implied"; the LSB is the
- X^31 term, etc. The X^0 term (usually shown as "+1") results in
- the MSB being 1.
! Note that the usual hardware shift register implementation, which
! is what we're using (we're merely optimizing it by doing eight-bit
! chunks at a time) shifts bits into the lowest-order term. In our
! implementation, that means shifting towards the right. Why do we
! do it this way? Because the calculated CRC must be transmitted in
! order from highest-order term to lowest-order term. UARTs transmit
! characters in order from LSB to MSB. By storing the CRC this way,
! we hand it to the UART in the order low-byte to high-byte; the UART
! sends each low-bit to hight-bit; and the result is transmission bit
! by bit from highest- to lowest-order term without requiring any bit
! shuffling on our part. Reception works similarly.
! The feedback terms table consists of 256, 32-bit entries. Notes:
!
! 1. The table can be generated at runtime if desired; code to do so
! is shown later. It might not be obvious, but the feedback
! terms simply represent the results of eight shift/xor opera-
! tions for all combinations of data and CRC register values.
!
! 2. The CRC accumulation logic is the same for all CRC polynomials,
! be they sixteen or thirty-two bits wide. You simply choose the
! appropriate table. Alternatively, because the table can be
! generated at runtime, you can start by generating the table for
! the polynomial in question and use exactly the same "updcrc",
! if your application needn't simultaneously handle two CRC
! polynomials. (Note, however, that XMODEM is strange.)
!
! 3. For 16-bit CRCs, the table entries need be only 16 bits wide;
! of course, 32-bit entries work OK if the high 16 bits are zero.
!
! 4. The values must be right-shifted by eight bits by the "updcrc"
! logic; the shift must be unsigned (bring in zeroes). On some
! hardware you could probably optimize the shift in assembler by
! using byte-swap instructions.
********************************************************************/
--- 759,805 ----
Copyright (C) 1986 Gary S. Brown. You may use this program, or
code or tables extracted from it, as desired without restriction.
! First, the polynomial itself and its table of feedback terms. The
! polynomial is
! X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
! Note that we take it "backwards" and put the highest-order term in
! the lowest-order bit. The X^32 term is "implied"; the LSB is the
! X^31 term, etc. The X^0 term (usually shown as "+1") results in
! the MSB being 1.
! Note that the usual hardware shift register implementation, which
! is what we're using (we're merely optimizing it by doing eight-bit
! chunks at a time) shifts bits into the lowest-order term. In our
! implementation, that means shifting towards the right. Why do we
! do it this way? Because the calculated CRC must be transmitted in
! order from highest-order term to lowest-order term. UARTs transmit
! characters in order from LSB to MSB. By storing the CRC this way,
! we hand it to the UART in the order low-byte to high-byte; the UART
! sends each low-bit to hight-bit; and the result is transmission bit
! by bit from highest- to lowest-order term without requiring any bit
! shuffling on our part. Reception works similarly.
!
! The feedback terms table consists of 256, 32-bit entries. Notes:
!
! 1. The table can be generated at runtime if desired; code to do so
! is shown later. It might not be obvious, but the feedback
! terms simply represent the results of eight shift/xor opera-
! tions for all combinations of data and CRC register values.
!
! 2. The CRC accumulation logic is the same for all CRC polynomials,
! be they sixteen or thirty-two bits wide. You simply choose the
! appropriate table. Alternatively, because the table can be
! generated at runtime, you can start by generating the table for
! the polynomial in question and use exactly the same "updcrc",
! if your application needn't simultaneously handle two CRC
! polynomials. (Note, however, that XMODEM is strange.)
!
! 3. For 16-bit CRCs, the table entries need be only 16 bits wide;
! of course, 32-bit entries work OK if the high 16 bits are zero.
!
! 4. The values must be right-shifted by eight bits by the "updcrc"
! logic; the shift must be unsigned (bring in zeroes). On some
! hardware you could probably optimize the shift in assembler by
! using byte-swap instructions.
********************************************************************/
***************
*** 866,886 ****
int len;
long result;
!
if ( !PyArg_ParseTuple(args, "s#|l:crc32", &bin_data, &len, &crc) )
return NULL;
! crc = crc ^ 0xFFFFFFFFUL;
! while(len--)
crc = crc_32_tab[(crc ^ *bin_data++) & 0xffUL] ^ (crc >> 8);
/* Note: (crc >> 8) MUST zero fill on left */
result = (long)(crc ^ 0xFFFFFFFFUL);
! /* If long is > 32 bits, extend the sign bit. This is one way to
! * ensure the result is the same across platforms. The other way
! * would be to return an unbounded long, but the evidence suggests
! * that lots of code outside this treats the result as if it were
! * a signed 4-byte integer.
*/
result |= -(result & (1L << 31));
return PyInt_FromLong(result);
}
--- 866,892 ----
int len;
long result;
!
if ( !PyArg_ParseTuple(args, "s#|l:crc32", &bin_data, &len, &crc) )
return NULL;
! crc = ~ crc;
! #if SIZEOF_LONG > 4
! /* only want the trailing 32 bits */
! crc &= 0xFFFFFFFFUL;
! #endif
! while (len--)
crc = crc_32_tab[(crc ^ *bin_data++) & 0xffUL] ^ (crc >> 8);
/* Note: (crc >> 8) MUST zero fill on left */
result = (long)(crc ^ 0xFFFFFFFFUL);
! #if SIZEOF_LONG > 4
! /* Extend the sign bit. This is one way to ensure the result is the
! * same across platforms. The other way would be to return an
! * unbounded unsigned long, but the evidence suggests that lots of
! * code outside this treats the result as if it were a signed 4-byte
! * integer.
*/
result |= -(result & (1L << 31));
+ #endif
return PyInt_FromLong(result);
}
***************
*** 930,934 ****
static int
! to_int(int c)
{
if (isdigit(c))
--- 936,940 ----
static int
! to_int(int c)
{
if (isdigit(c))
***************
*** 1012,1016 ****
PyDoc_STRVAR(doc_a2b_qp, "Decode a string of qp-encoded data");
! static PyObject*
binascii_a2b_qp(PyObject *self, PyObject *args, PyObject *kwargs)
{
--- 1018,1022 ----
PyDoc_STRVAR(doc_a2b_qp, "Decode a string of qp-encoded data");
! static PyObject*
binascii_a2b_qp(PyObject *self, PyObject *args, PyObject *kwargs)
{
***************
*** 1023,1027 ****
int header = 0;
! if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|i", kwlist, &data,
&datalen, &header))
return NULL;
--- 1029,1033 ----
int header = 0;
! if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|i", kwlist, &data,
&datalen, &header))
return NULL;
***************
*** 1041,1045 ****
if (in >= datalen) break;
/* Soft line breaks */
! if ((data[in] == '\n') || (data[in] == '\r') ||
(data[in] == ' ') || (data[in] == '\t')) {
if (data[in] != '\n') {
--- 1047,1051 ----
if (in >= datalen) break;
/* Soft line breaks */
! if ((data[in] == '\n') || (data[in] == '\r') ||
(data[in] == ' ') || (data[in] == '\t')) {
if (data[in] != '\n') {
***************
*** 1053,1057 ****
in++;
}
! else if (((data[in] >= 'A' && data[in] <= 'F') ||
(data[in] >= 'a' && data[in] <= 'f') ||
(data[in] >= '0' && data[in] <= '9')) &&
--- 1059,1063 ----
in++;
}
! else if (((data[in] >= 'A' && data[in] <= 'F') ||
(data[in] >= 'a' && data[in] <= 'f') ||
(data[in] >= '0' && data[in] <= '9')) &&
***************
*** 1088,1092 ****
}
! static int
to_hex (unsigned char ch, unsigned char *s)
{
--- 1094,1098 ----
}
! static int
to_hex (unsigned char ch, unsigned char *s)
{
***************
*** 1110,1114 ****
* (mostly) with the quopri module. It doesn't re-create the quopri
* module bug where text ending in CRLF has the CR encoded */
! static PyObject*
binascii_b2a_qp (PyObject *self, PyObject *args, PyObject *kwargs)
{
--- 1116,1120 ----
* (mostly) with the quopri module. It doesn't re-create the quopri
* module bug where text ending in CRLF has the CR encoded */
! static PyObject*
binascii_b2a_qp (PyObject *self, PyObject *args, PyObject *kwargs)
{
***************
*** 1126,1130 ****
unsigned char *p;
! if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|iii", kwlist, &data,
&datalen, "etabs, &istext, &header))
return NULL;
--- 1132,1136 ----
unsigned char *p;
! if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|iii", kwlist, &data,
&datalen, "etabs, &istext, &header))
return NULL;
***************
*** 1141,1145 ****
in = 0;
while (in < datalen) {
! if ((data[in] > 126) ||
(data[in] == '=') ||
(header && data[in] == '_') ||
--- 1147,1151 ----
in = 0;
while (in < datalen) {
! if ((data[in] > 126) ||
(data[in] == '=') ||
(header && data[in] == '_') ||
***************
*** 1147,1152 ****
(!istext && ((data[in] == '\r') || (data[in] == '\n'))) ||
((data[in] == '\t' || data[in] == ' ') && (in + 1 == datalen)) ||
! ((data[in] < 33) &&
! (data[in] != '\r') && (data[in] != '\n') &&
(quotetabs && ((data[in] != '\t') || (data[in] != ' ')))))
{
--- 1153,1158 ----
(!istext && ((data[in] == '\r') || (data[in] == '\n'))) ||
((data[in] == '\t' || data[in] == ' ') && (in + 1 == datalen)) ||
! ((data[in] < 33) &&
! (data[in] != '\r') && (data[in] != '\n') &&
(quotetabs && ((data[in] != '\t') || (data[in] != ' ')))))
{
***************
*** 1163,1167 ****
}
else {
! if (istext &&
((data[in] == '\n') ||
((in+1 < datalen) && (data[in] == '\r') &&
--- 1169,1173 ----
}
else {
! if (istext &&
((data[in] == '\n') ||
((in+1 < datalen) && (data[in] == '\r') &&
***************
*** 1182,1186 ****
}
else {
! if ((in + 1 != datalen) &&
(data[in+1] != '\n') &&
(linelen + 1) >= MAXLINESIZE) {
--- 1188,1192 ----
}
else {
! if ((in + 1 != datalen) &&
(data[in+1] != '\n') &&
(linelen + 1) >= MAXLINESIZE) {
***************
*** 1207,1211 ****
in = out = linelen = 0;
while (in < datalen) {
! if ((data[in] > 126) ||
(data[in] == '=') ||
(header && data[in] == '_') ||
--- 1213,1217 ----
in = out = linelen = 0;
while (in < datalen) {
! if ((data[in] > 126) ||
(data[in] == '=') ||
(header && data[in] == '_') ||
***************
*** 1213,1218 ****
(!istext && ((data[in] == '\r') || (data[in] == '\n'))) ||
((data[in] == '\t' || data[in] == ' ') && (in + 1 == datalen)) ||
! ((data[in] < 33) &&
! (data[in] != '\r') && (data[in] != '\n') &&
(quotetabs && ((data[in] != '\t') || (data[in] != ' ')))))
{
--- 1219,1224 ----
(!istext && ((data[in] == '\r') || (data[in] == '\n'))) ||
((data[in] == '\t' || data[in] == ' ') && (in + 1 == datalen)) ||
! ((data[in] < 33) &&
! (data[in] != '\r') && (data[in] != '\n') &&
(quotetabs && ((data[in] != '\t') || (data[in] != ' ')))))
{
***************
*** 1230,1234 ****
}
else {
! if (istext &&
((data[in] == '\n') ||
((in+1 < datalen) && (data[in] == '\r') &&
--- 1236,1240 ----
}
else {
! if (istext &&
((data[in] == '\n') ||
((in+1 < datalen) && (data[in] == '\r') &&
***************
*** 1243,1247 ****
out += 2;
}
!
if (crlf) odata[out++] = '\r';
odata[out++] = '\n';
--- 1249,1253 ----
out += 2;
}
!
if (crlf) odata[out++] = '\r';
odata[out++] = '\n';
***************
*** 1252,1256 ****
}
else {
! if ((in + 1 != datalen) &&
(data[in+1] != '\n') &&
(linelen + 1) >= MAXLINESIZE) {
--- 1258,1262 ----
}
else {
! if ((in + 1 != datalen) &&
(data[in+1] != '\n') &&
(linelen + 1) >= MAXLINESIZE) {
***************
*** 1297,1303 ****
{"crc_hqx", binascii_crc_hqx, METH_VARARGS, doc_crc_hqx},
{"crc32", binascii_crc32, METH_VARARGS, doc_crc32},
! {"a2b_qp", (PyCFunction)binascii_a2b_qp, METH_VARARGS | METH_KEYWORDS,
doc_a2b_qp},
! {"b2a_qp", (PyCFunction)binascii_b2a_qp, METH_VARARGS | METH_KEYWORDS,
doc_b2a_qp},
{NULL, NULL} /* sentinel */
--- 1303,1309 ----
{"crc_hqx", binascii_crc_hqx, METH_VARARGS, doc_crc_hqx},
{"crc32", binascii_crc32, METH_VARARGS, doc_crc32},
! {"a2b_qp", (PyCFunction)binascii_a2b_qp, METH_VARARGS | METH_KEYWORDS,
doc_a2b_qp},
! {"b2a_qp", (PyCFunction)binascii_b2a_qp, METH_VARARGS | METH_KEYWORDS,
doc_b2a_qp},
{NULL, NULL} /* sentinel */