aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules/_struct.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_struct.c')
-rw-r--r--Modules/_struct.c479
1 files changed, 236 insertions, 243 deletions
diff --git a/Modules/_struct.c b/Modules/_struct.c
index d8c932427d6..edbe9b9884b 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -1,4 +1,4 @@
-/* struct module -- pack values into and (out of) strings */
+/* struct module -- pack values into and (out of) bytes objects */
/* New version supporting byte order, alignment and size options,
character strings, and unsigned numbers */
@@ -6,23 +6,11 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
-#include "structseq.h"
#include "structmember.h"
#include <ctype.h>
static PyTypeObject PyStructType;
-/* compatibility macros */
-#if (PY_VERSION_HEX < 0x02050000)
-typedef int Py_ssize_t;
-#endif
-
-/* warning messages */
-#define FLOAT_COERCE_WARN "integer argument expected, got float"
-#define NON_INTEGER_WARN "integer argument expected, got non-integer " \
- "(implicit conversion using __int__ is deprecated)"
-
-
/* The translation function for each format character is table driven */
typedef struct _formatdef {
char format;
@@ -100,96 +88,35 @@ typedef struct { char c; _Bool x; } s_bool;
#pragma options align=reset
#endif
-static char *integer_codes = "bBhHiIlLqQ";
-
-/* Helper to get a PyLongObject by hook or by crook. Caller should decref. */
+/* Helper for integer format codes: converts an arbitrary Python object to a
+ PyLongObject if possible, otherwise fails. Caller should decref. */
static PyObject *
get_pylong(PyObject *v)
{
- PyObject *r, *w;
- int converted = 0;
assert(v != NULL);
- if (!PyInt_Check(v) && !PyLong_Check(v)) {
- PyNumberMethods *m;
- /* Not an integer; first try to use __index__ to
- convert to an integer. If the __index__ method
- doesn't exist, or raises a TypeError, try __int__.
- Use of the latter is deprecated, and will fail in
- Python 3.x. */
-
- m = Py_TYPE(v)->tp_as_number;
+ if (!PyLong_Check(v)) {
+ /* Not an integer; try to use __index__ to convert. */
if (PyIndex_Check(v)) {
- w = PyNumber_Index(v);
- if (w != NULL) {
- v = w;
- /* successfully converted to an integer */
- converted = 1;
- }
- else if (PyErr_ExceptionMatches(PyExc_TypeError)) {
- PyErr_Clear();
- }
- else
- return NULL;
- }
- if (!converted && m != NULL && m->nb_int != NULL) {
- /* Special case warning message for floats, for
- backwards compatibility. */
- if (PyFloat_Check(v)) {
- if (PyErr_WarnEx(
- PyExc_DeprecationWarning,
- FLOAT_COERCE_WARN, 1))
- return NULL;
- }
- else {
- if (PyErr_WarnEx(
- PyExc_DeprecationWarning,
- NON_INTEGER_WARN, 1))
- return NULL;
- }
- v = m->nb_int(v);
+ v = PyNumber_Index(v);
if (v == NULL)
return NULL;
- if (!PyInt_Check(v) && !PyLong_Check(v)) {
- PyErr_SetString(PyExc_TypeError,
- "__int__ method returned "
- "non-integer");
- return NULL;
- }
- converted = 1;
}
- if (!converted) {
+ else {
PyErr_SetString(StructError,
- "cannot convert argument "
- "to integer");
+ "required argument is not an integer");
return NULL;
}
}
else
- /* Ensure we own a reference to v. */
Py_INCREF(v);
- assert(PyInt_Check(v) || PyLong_Check(v));
- if (PyInt_Check(v)) {
- r = PyLong_FromLong(PyInt_AS_LONG(v));
- Py_DECREF(v);
- }
- else if (PyLong_Check(v)) {
- assert(PyLong_Check(v));
- r = v;
- }
- else {
- r = NULL; /* silence compiler warning about
- possibly uninitialized variable */
- assert(0); /* shouldn't ever get here */
- }
-
- return r;
+ assert(PyLong_Check(v));
+ return v;
}
-/* Helper to convert a Python object to a C long. Sets an exception
- (struct.error for an inconvertible type, OverflowError for
- out-of-range values) and returns -1 on error. */
+/* Helper routine to get a C long and raise the appropriate error if it isn't
+ one */
static int
get_long(PyObject *v, long *p)
@@ -202,12 +129,17 @@ get_long(PyObject *v, long *p)
assert(PyLong_Check(v));
x = PyLong_AsLong(v);
Py_DECREF(v);
- if (x == (long)-1 && PyErr_Occurred())
+ if (x == (long)-1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ PyErr_SetString(StructError,
+ "argument out of range");
return -1;
+ }
*p = x;
return 0;
}
+
/* Same, but handling unsigned long */
static int
@@ -221,8 +153,12 @@ get_ulong(PyObject *v, unsigned long *p)
assert(PyLong_Check(v));
x = PyLong_AsUnsignedLong(v);
Py_DECREF(v);
- if (x == (unsigned long)-1 && PyErr_Occurred())
+ if (x == (unsigned long)-1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ PyErr_SetString(StructError,
+ "argument out of range");
return -1;
+ }
*p = x;
return 0;
}
@@ -242,8 +178,12 @@ get_longlong(PyObject *v, PY_LONG_LONG *p)
assert(PyLong_Check(v));
x = PyLong_AsLongLong(v);
Py_DECREF(v);
- if (x == (PY_LONG_LONG)-1 && PyErr_Occurred())
+ if (x == (PY_LONG_LONG)-1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ PyErr_SetString(StructError,
+ "argument out of range");
return -1;
+ }
*p = x;
return 0;
}
@@ -261,14 +201,22 @@ get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p)
assert(PyLong_Check(v));
x = PyLong_AsUnsignedLongLong(v);
Py_DECREF(v);
- if (x == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
+ if (x == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) {
+ if (PyErr_ExceptionMatches(PyExc_OverflowError))
+ PyErr_SetString(StructError,
+ "argument out of range");
return -1;
+ }
*p = x;
return 0;
}
#endif
+
+#define RANGE_ERROR(x, f, flag, mask) return _range_error(f, flag)
+
+
/* Floating point helpers */
static PyObject *
@@ -322,6 +270,7 @@ _range_error(const formatdef *f, int is_unsigned)
~ largest,
largest);
}
+
return -1;
}
@@ -349,19 +298,19 @@ _range_error(const formatdef *f, int is_unsigned)
static PyObject *
nu_char(const char *p, const formatdef *f)
{
- return PyString_FromStringAndSize(p, 1);
+ return PyBytes_FromStringAndSize(p, 1);
}
static PyObject *
nu_byte(const char *p, const formatdef *f)
{
- return PyInt_FromLong((long) *(signed char *)p);
+ return PyLong_FromLong((long) *(signed char *)p);
}
static PyObject *
nu_ubyte(const char *p, const formatdef *f)
{
- return PyInt_FromLong((long) *(unsigned char *)p);
+ return PyLong_FromLong((long) *(unsigned char *)p);
}
static PyObject *
@@ -369,7 +318,7 @@ nu_short(const char *p, const formatdef *f)
{
short x;
memcpy((char *)&x, p, sizeof x);
- return PyInt_FromLong((long)x);
+ return PyLong_FromLong((long)x);
}
static PyObject *
@@ -377,7 +326,7 @@ nu_ushort(const char *p, const formatdef *f)
{
unsigned short x;
memcpy((char *)&x, p, sizeof x);
- return PyInt_FromLong((long)x);
+ return PyLong_FromLong((long)x);
}
static PyObject *
@@ -385,7 +334,7 @@ nu_int(const char *p, const formatdef *f)
{
int x;
memcpy((char *)&x, p, sizeof x);
- return PyInt_FromLong((long)x);
+ return PyLong_FromLong((long)x);
}
static PyObject *
@@ -394,10 +343,10 @@ nu_uint(const char *p, const formatdef *f)
unsigned int x;
memcpy((char *)&x, p, sizeof x);
#if (SIZEOF_LONG > SIZEOF_INT)
- return PyInt_FromLong((long)x);
+ return PyLong_FromLong((long)x);
#else
if (x <= ((unsigned int)LONG_MAX))
- return PyInt_FromLong((long)x);
+ return PyLong_FromLong((long)x);
return PyLong_FromUnsignedLong((unsigned long)x);
#endif
}
@@ -407,7 +356,7 @@ nu_long(const char *p, const formatdef *f)
{
long x;
memcpy((char *)&x, p, sizeof x);
- return PyInt_FromLong(x);
+ return PyLong_FromLong(x);
}
static PyObject *
@@ -416,7 +365,7 @@ nu_ulong(const char *p, const formatdef *f)
unsigned long x;
memcpy((char *)&x, p, sizeof x);
if (x <= LONG_MAX)
- return PyInt_FromLong((long)x);
+ return PyLong_FromLong((long)x);
return PyLong_FromUnsignedLong(x);
}
@@ -431,7 +380,7 @@ nu_longlong(const char *p, const formatdef *f)
PY_LONG_LONG x;
memcpy((char *)&x, p, sizeof x);
if (x >= LONG_MIN && x <= LONG_MAX)
- return PyInt_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long));
return PyLong_FromLongLong(x);
}
@@ -441,7 +390,7 @@ nu_ulonglong(const char *p, const formatdef *f)
unsigned PY_LONG_LONG x;
memcpy((char *)&x, p, sizeof x);
if (x <= LONG_MAX)
- return PyInt_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long));
return PyLong_FromUnsignedLongLong(x);
}
@@ -513,12 +462,12 @@ np_ubyte(char *p, PyObject *v, const formatdef *f)
static int
np_char(char *p, PyObject *v, const formatdef *f)
{
- if (!PyString_Check(v) || PyString_Size(v) != 1) {
+ if (!PyBytes_Check(v) || PyBytes_Size(v) != 1) {
PyErr_SetString(StructError,
- "char format require string of length 1");
+ "char format requires a bytes object of length 1");
return -1;
}
- *p = *PyString_AsString(v);
+ *p = *PyBytes_AsString(v);
return 0;
}
@@ -566,7 +515,7 @@ np_int(char *p, PyObject *v, const formatdef *f)
return -1;
#if (SIZEOF_LONG > SIZEOF_INT)
if ((x < ((long)INT_MIN)) || (x > ((long)INT_MAX)))
- return _range_error(f, 0);
+ RANGE_ERROR(x, f, 0, -1);
#endif
y = (int)x;
memcpy(p, (char *)&y, sizeof y);
@@ -583,7 +532,7 @@ np_uint(char *p, PyObject *v, const formatdef *f)
y = (unsigned int)x;
#if (SIZEOF_LONG > SIZEOF_INT)
if (x > ((unsigned long)UINT_MAX))
- return _range_error(f, 1);
+ RANGE_ERROR(y, f, 1, -1);
#endif
memcpy(p, (char *)&y, sizeof y);
return 0;
@@ -727,7 +676,7 @@ bu_int(const char *p, const formatdef *f)
/* Extend the sign bit. */
if (SIZEOF_LONG > f->size)
x |= -(x & (1L << ((8 * f->size) - 1)));
- return PyInt_FromLong(x);
+ return PyLong_FromLong(x);
}
static PyObject *
@@ -740,7 +689,7 @@ bu_uint(const char *p, const formatdef *f)
x = (x<<8) | *bytes++;
} while (--i > 0);
if (x <= LONG_MAX)
- return PyInt_FromLong((long)x);
+ return PyLong_FromLong((long)x);
return PyLong_FromUnsignedLong(x);
}
@@ -758,7 +707,7 @@ bu_longlong(const char *p, const formatdef *f)
if (SIZEOF_LONG_LONG > f->size)
x |= -(x & ((PY_LONG_LONG)1 << ((8 * f->size) - 1)));
if (x >= LONG_MIN && x <= LONG_MAX)
- return PyInt_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long));
return PyLong_FromLongLong(x);
#else
return _PyLong_FromByteArray((const unsigned char *)p,
@@ -779,7 +728,7 @@ bu_ulonglong(const char *p, const formatdef *f)
x = (x<<8) | *bytes++;
} while (--i > 0);
if (x <= LONG_MAX)
- return PyInt_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long));
return PyLong_FromUnsignedLongLong(x);
#else
return _PyLong_FromByteArray((const unsigned char *)p,
@@ -819,10 +768,10 @@ bp_int(char *p, PyObject *v, const formatdef *f)
i = f->size;
if (i != SIZEOF_LONG) {
if ((i == 2) && (x < -32768 || x > 32767))
- return _range_error(f, 0);
+ RANGE_ERROR(x, f, 0, 0xffffL);
#if (SIZEOF_LONG != 4)
else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
- return _range_error(f, 0);
+ RANGE_ERROR(x, f, 0, 0xffffffffL);
#endif
}
do {
@@ -844,7 +793,7 @@ bp_uint(char *p, PyObject *v, const formatdef *f)
unsigned long maxint = 1;
maxint <<= (unsigned long)(i * 8);
if (x >= maxint)
- return _range_error(f, 1);
+ RANGE_ERROR(x, f, 1, maxint - 1);
}
do {
p[--i] = (char)x;
@@ -955,7 +904,7 @@ lu_int(const char *p, const formatdef *f)
/* Extend the sign bit. */
if (SIZEOF_LONG > f->size)
x |= -(x & (1L << ((8 * f->size) - 1)));
- return PyInt_FromLong(x);
+ return PyLong_FromLong(x);
}
static PyObject *
@@ -968,7 +917,7 @@ lu_uint(const char *p, const formatdef *f)
x = (x<<8) | bytes[--i];
} while (i > 0);
if (x <= LONG_MAX)
- return PyInt_FromLong((long)x);
+ return PyLong_FromLong((long)x);
return PyLong_FromUnsignedLong((long)x);
}
@@ -986,7 +935,7 @@ lu_longlong(const char *p, const formatdef *f)
if (SIZEOF_LONG_LONG > f->size)
x |= -(x & ((PY_LONG_LONG)1 << ((8 * f->size) - 1)));
if (x >= LONG_MIN && x <= LONG_MAX)
- return PyInt_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long));
return PyLong_FromLongLong(x);
#else
return _PyLong_FromByteArray((const unsigned char *)p,
@@ -1007,7 +956,7 @@ lu_ulonglong(const char *p, const formatdef *f)
x = (x<<8) | bytes[--i];
} while (i > 0);
if (x <= LONG_MAX)
- return PyInt_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long));
return PyLong_FromUnsignedLongLong(x);
#else
return _PyLong_FromByteArray((const unsigned char *)p,
@@ -1039,10 +988,10 @@ lp_int(char *p, PyObject *v, const formatdef *f)
i = f->size;
if (i != SIZEOF_LONG) {
if ((i == 2) && (x < -32768 || x > 32767))
- return _range_error(f, 0);
+ RANGE_ERROR(x, f, 0, 0xffffL);
#if (SIZEOF_LONG != 4)
else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
- return _range_error(f, 0);
+ RANGE_ERROR(x, f, 0, 0xffffffffL);
#endif
}
do {
@@ -1064,7 +1013,7 @@ lp_uint(char *p, PyObject *v, const formatdef *f)
unsigned long maxint = 1;
maxint <<= (unsigned long)(i * 8);
if (x >= maxint)
- return _range_error(f, 1);
+ RANGE_ERROR(x, f, 1, maxint - 1);
}
do {
*p++ = (char)x;
@@ -1227,7 +1176,7 @@ prepare_s(PyStructObject *self)
char c;
Py_ssize_t size, len, num, itemsize;
- fmt = PyString_AS_STRING(self->s_format);
+ fmt = PyBytes_AS_STRING(self->s_format);
f = whichtable((char **)&fmt);
@@ -1248,8 +1197,11 @@ prepare_s(PyStructObject *self)
goto overflow;
num = num*10 + (c - '0');
}
- if (c == '\0')
- break;
+ if (c == '\0') {
+ PyErr_SetString(StructError,
+ "repeat count given without format specifier");
+ return -1;
+ }
}
else
num = 1;
@@ -1371,11 +1323,28 @@ s_init(PyObject *self, PyObject *args, PyObject *kwds)
assert(PyStruct_Check(self));
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:Struct", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:Struct", kwlist,
&o_format))
return -1;
- Py_INCREF(o_format);
+ if (PyUnicode_Check(o_format)) {
+ o_format = PyUnicode_AsASCIIString(o_format);
+ if (o_format == NULL)
+ return -1;
+ }
+ /* XXX support buffer interface, too */
+ else {
+ Py_INCREF(o_format);
+ }
+
+ if (!PyBytes_Check(o_format)) {
+ Py_DECREF(o_format);
+ PyErr_Format(PyExc_TypeError,
+ "Struct() argument 1 must be a bytes object, not %.200s",
+ Py_TYPE(o_format)->tp_name);
+ return -1;
+ }
+
Py_CLEAR(soself->s_format);
soself->s_format = o_format;
@@ -1408,12 +1377,12 @@ s_unpack_internal(PyStructObject *soself, char *startfrom) {
const formatdef *e = code->fmtdef;
const char *res = startfrom + code->offset;
if (e->format == 's') {
- v = PyString_FromStringAndSize(res, code->size);
+ v = PyBytes_FromStringAndSize(res, code->size);
} else if (e->format == 'p') {
Py_ssize_t n = *(unsigned char*)res;
if (n >= code->size)
n = code->size - 1;
- v = PyString_FromStringAndSize(res + 1, n);
+ v = PyBytes_FromStringAndSize(res + 1, n);
} else {
v = e->unpack(res, e);
}
@@ -1430,89 +1399,74 @@ fail:
PyDoc_STRVAR(s_unpack__doc__,
-"S.unpack(str) -> (v1, v2, ...)\n\
+"S.unpack(buffer) -> (v1, v2, ...)\n\
\n\
-Return tuple containing values unpacked according to this Struct's format.\n\
-Requires len(str) == self.size. See struct.__doc__ for more on format\n\
-strings.");
+Return a tuple containing values unpacked according to the format\n\
+string S.format. Requires len(buffer) == S.size. See help(struct)\n\
+for more on format strings.");
static PyObject *
-s_unpack(PyObject *self, PyObject *inputstr)
+s_unpack(PyObject *self, PyObject *input)
{
- char *start;
- Py_ssize_t len;
- PyObject *args=NULL, *result;
+ Py_buffer vbuf;
+ PyObject *result;
PyStructObject *soself = (PyStructObject *)self;
+
assert(PyStruct_Check(self));
assert(soself->s_codes != NULL);
- if (inputstr == NULL)
- goto fail;
- if (PyString_Check(inputstr) &&
- PyString_GET_SIZE(inputstr) == soself->s_size) {
- return s_unpack_internal(soself, PyString_AS_STRING(inputstr));
- }
- args = PyTuple_Pack(1, inputstr);
- if (args == NULL)
+ if (PyObject_GetBuffer(input, &vbuf, PyBUF_SIMPLE) < 0)
return NULL;
- if (!PyArg_ParseTuple(args, "s#:unpack", &start, &len))
- goto fail;
- if (soself->s_size != len)
- goto fail;
- result = s_unpack_internal(soself, start);
- Py_DECREF(args);
+ if (vbuf.len != soself->s_size) {
+ PyErr_Format(StructError,
+ "unpack requires a bytes object of length %zd",
+ soself->s_size);
+ PyBuffer_Release(&vbuf);
+ return NULL;
+ }
+ result = s_unpack_internal(soself, vbuf.buf);
+ PyBuffer_Release(&vbuf);
return result;
-
-fail:
- Py_XDECREF(args);
- PyErr_Format(StructError,
- "unpack requires a string argument of length %zd",
- soself->s_size);
- return NULL;
}
PyDoc_STRVAR(s_unpack_from__doc__,
-"S.unpack_from(buffer[, offset]) -> (v1, v2, ...)\n\
+"S.unpack_from(buffer, offset=0) -> (v1, v2, ...)\n\
\n\
-Return tuple containing values unpacked according to this Struct's format.\n\
-Unlike unpack, unpack_from can unpack values from any object supporting\n\
-the buffer API, not just str. Requires len(buffer[offset:]) >= self.size.\n\
-See struct.__doc__ for more on format strings.");
+Return a tuple containing values unpacked according to the format\n\
+string S.format. Requires len(buffer[offset:]) >= S.size. See\n\
+help(struct) for more on format strings.");
static PyObject *
s_unpack_from(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"buffer", "offset", 0};
-#if (PY_VERSION_HEX < 0x02050000)
- static char *fmt = "z#|i:unpack_from";
-#else
- static char *fmt = "z#|n:unpack_from";
-#endif
- Py_ssize_t buffer_len = 0, offset = 0;
- char *buffer = NULL;
+
+ PyObject *input;
+ Py_ssize_t offset = 0;
+ Py_buffer vbuf;
+ PyObject *result;
PyStructObject *soself = (PyStructObject *)self;
+
assert(PyStruct_Check(self));
assert(soself->s_codes != NULL);
- if (!PyArg_ParseTupleAndKeywords(args, kwds, fmt, kwlist,
- &buffer, &buffer_len, &offset))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ "O|n:unpack_from", kwlist,
+ &input, &offset))
return NULL;
-
- if (buffer == NULL) {
- PyErr_Format(StructError,
- "unpack_from requires a buffer argument");
+ if (PyObject_GetBuffer(input, &vbuf, PyBUF_SIMPLE) < 0)
return NULL;
- }
-
if (offset < 0)
- offset += buffer_len;
-
- if (offset < 0 || (buffer_len - offset) < soself->s_size) {
+ offset += vbuf.len;
+ if (offset < 0 || vbuf.len - offset < soself->s_size) {
PyErr_Format(StructError,
"unpack_from requires a buffer of at least %zd bytes",
soself->s_size);
+ PyBuffer_Release(&vbuf);
return NULL;
}
- return s_unpack_internal(soself, buffer + offset);
+ result = s_unpack_internal(soself, (char*)vbuf.buf + offset);
+ PyBuffer_Release(&vbuf);
+ return result;
}
@@ -1542,40 +1496,57 @@ s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf)
const formatdef *e = code->fmtdef;
char *res = buf + code->offset;
if (e->format == 's') {
- if (!PyString_Check(v)) {
+ int isstring;
+ void *p;
+ isstring = PyBytes_Check(v);
+ if (!isstring && !PyByteArray_Check(v)) {
PyErr_SetString(StructError,
- "argument for 's' must "
- "be a string");
+ "argument for 's' must be a bytes object");
return -1;
}
- n = PyString_GET_SIZE(v);
+ if (isstring) {
+ n = PyBytes_GET_SIZE(v);
+ p = PyBytes_AS_STRING(v);
+ }
+ else {
+ n = PyByteArray_GET_SIZE(v);
+ p = PyByteArray_AS_STRING(v);
+ }
if (n > code->size)
n = code->size;
if (n > 0)
- memcpy(res, PyString_AS_STRING(v), n);
+ memcpy(res, p, n);
} else if (e->format == 'p') {
- if (!PyString_Check(v)) {
+ int isstring;
+ void *p;
+ isstring = PyBytes_Check(v);
+ if (!isstring && !PyByteArray_Check(v)) {
PyErr_SetString(StructError,
- "argument for 'p' must "
- "be a string");
+ "argument for 'p' must be a bytes object");
return -1;
}
- n = PyString_GET_SIZE(v);
+ if (isstring) {
+ n = PyBytes_GET_SIZE(v);
+ p = PyBytes_AS_STRING(v);
+ }
+ else {
+ n = PyByteArray_GET_SIZE(v);
+ p = PyByteArray_AS_STRING(v);
+ }
if (n > (code->size - 1))
n = code->size - 1;
if (n > 0)
- memcpy(res + 1, PyString_AS_STRING(v), n);
+ memcpy(res + 1, p, n);
if (n > 255)
n = 255;
*res = Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char);
- } else if (e->pack(res, v, e) < 0) {
- if (strchr(integer_codes, e->format) != NULL &&
- PyErr_ExceptionMatches(PyExc_OverflowError))
- PyErr_Format(StructError,
- "integer out of range for "
- "'%c' format code",
- e->format);
- return -1;
+ } else {
+ if (e->pack(res, v, e) < 0) {
+ if (PyLong_Check(v) && PyErr_ExceptionMatches(PyExc_OverflowError))
+ PyErr_SetString(StructError,
+ "long too large to convert to int");
+ return -1;
+ }
}
}
@@ -1585,10 +1556,11 @@ s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf)
PyDoc_STRVAR(s_pack__doc__,
-"S.pack(v1, v2, ...) -> string\n\
+"S.pack(v1, v2, ...) -> bytes\n\
\n\
-Return a string containing values v1, v2, ... packed according to this\n\
-Struct's format. See struct.__doc__ for more on format strings.");
+Return a bytes object containing values v1, v2, ... packed according\n\
+to the format string S.format. See help(struct) for more on format\n\
+strings.");
static PyObject *
s_pack(PyObject *self, PyObject *args)
@@ -1608,12 +1580,12 @@ s_pack(PyObject *self, PyObject *args)
}
/* Allocate a new string */
- result = PyString_FromStringAndSize((char *)NULL, soself->s_size);
+ result = PyBytes_FromStringAndSize((char *)NULL, soself->s_size);
if (result == NULL)
return NULL;
/* Call the guts */
- if ( s_pack_internal(soself, args, 0, PyString_AS_STRING(result)) != 0 ) {
+ if ( s_pack_internal(soself, args, 0, PyBytes_AS_STRING(result)) != 0 ) {
Py_DECREF(result);
return NULL;
}
@@ -1624,10 +1596,10 @@ s_pack(PyObject *self, PyObject *args)
PyDoc_STRVAR(s_pack_into__doc__,
"S.pack_into(buffer, offset, v1, v2, ...)\n\
\n\
-Pack the values v1, v2, ... according to this Struct's format, write \n\
-the packed bytes into the writable buffer buf starting at offset. Note\n\
-that the offset is not an optional argument. See struct.__doc__ for \n\
-more on format strings.");
+Pack the values v1, v2, ... according to the format string S.format\n\
+and write the packed bytes into the writable buffer buf starting at\n\
+offset. Note that the offset is a required argument. See\n\
+help(struct) for more on format strings.");
static PyObject *
s_pack_into(PyObject *self, PyObject *args)
@@ -1666,7 +1638,7 @@ s_pack_into(PyObject *self, PyObject *args)
assert( buffer_len >= 0 );
/* Extract the offset from the first argument */
- offset = PyInt_AsSsize_t(PyTuple_GET_ITEM(args, 1));
+ offset = PyNumber_AsSsize_t(PyTuple_GET_ITEM(args, 1), PyExc_IndexError);
if (offset == -1 && PyErr_Occurred())
return NULL;
@@ -1700,7 +1672,7 @@ s_get_format(PyStructObject *self, void *unused)
static PyObject *
s_get_size(PyStructObject *self, void *unused)
{
- return PyInt_FromSsize_t(self->s_size);
+ return PyLong_FromSsize_t(self->s_size);
}
PyDoc_STRVAR(s_sizeof__doc__,
@@ -1727,7 +1699,11 @@ static struct PyMethodDef s_methods[] = {
{NULL, NULL} /* sentinel */
};
-PyDoc_STRVAR(s__doc__, "Compiled struct object");
+PyDoc_STRVAR(s__doc__,
+"Struct(fmt) --> compiled struct object\n"
+"\n"
+"Return a new Struct object which writes and reads binary data according to\n"
+"the format string fmt. See help(struct) for more on format strings.");
#define OFF(x) offsetof(PyStructObject, x)
@@ -1747,7 +1723,7 @@ PyTypeObject PyStructType = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- 0, /* tp_compare */
+ 0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
@@ -1758,7 +1734,7 @@ PyTypeObject PyStructType = {
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS,/* tp_flags */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
s__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
@@ -1825,7 +1801,9 @@ clearcache(PyObject *self)
}
PyDoc_STRVAR(calcsize_doc,
-"Return size of C struct described by format string fmt.");
+"calcsize(fmt) -> integer\n\
+\n\
+Return size in bytes of the struct described by the format string fmt.");
static PyObject *
calcsize(PyObject *self, PyObject *fmt)
@@ -1836,11 +1814,14 @@ calcsize(PyObject *self, PyObject *fmt)
return NULL;
n = ((PyStructObject *)s_object)->s_size;
Py_DECREF(s_object);
- return PyInt_FromSsize_t(n);
+ return PyLong_FromSsize_t(n);
}
PyDoc_STRVAR(pack_doc,
-"Return string containing values v1, v2, ... packed according to fmt.");
+"pack(fmt, v1, v2, ...) -> bytes\n\
+\n\
+Return a bytes object containing the values v1, v2, ... packed according\n\
+to the format string fmt. See help(struct) for more on format strings.");
static PyObject *
pack(PyObject *self, PyObject *args)
@@ -1869,8 +1850,12 @@ pack(PyObject *self, PyObject *args)
}
PyDoc_STRVAR(pack_into_doc,
-"Pack the values v1, v2, ... according to fmt.\n\
-Write the packed bytes into the writable buffer buf starting at offset.");
+"pack_into(fmt, buffer, offset, v1, v2, ...)\n\
+\n\
+Pack the values v1, v2, ... according to the format string fmt and write\n\
+the packed bytes into the writable buffer buf starting at offset. Note\n\
+that the offset is a required argument. See help(struct) for more\n\
+on format strings.");
static PyObject *
pack_into(PyObject *self, PyObject *args)
@@ -1899,8 +1884,11 @@ pack_into(PyObject *self, PyObject *args)
}
PyDoc_STRVAR(unpack_doc,
-"Unpack the string containing packed C structure data, according to fmt.\n\
-Requires len(string) == calcsize(fmt).");
+"unpack(fmt, buffer) -> (v1, v2, ...)\n\
+\n\
+Return a tuple containing values unpacked according to the format string\n\
+fmt. Requires len(buffer) == calcsize(fmt). See help(struct) for more\n\
+on format strings.");
static PyObject *
unpack(PyObject *self, PyObject *args)
@@ -1919,8 +1907,11 @@ unpack(PyObject *self, PyObject *args)
}
PyDoc_STRVAR(unpack_from_doc,
-"Unpack the buffer, containing packed C structure data, according to\n\
-fmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).");
+"unpack_from(fmt, buffer, offset=0) -> (v1, v2, ...)\n\
+\n\
+Return a tuple containing values unpacked according to the format string\n\
+fmt. Requires len(buffer[offset:]) >= calcsize(fmt). See help(struct)\n\
+for more on format strings.");
static PyObject *
unpack_from(PyObject *self, PyObject *args, PyObject *kwds)
@@ -1963,10 +1954,10 @@ static struct PyMethodDef module_functions[] = {
/* Module initialization */
PyDoc_STRVAR(module_doc,
-"Functions to convert between Python values and C structs represented\n\
-as Python strings. It uses format strings (explained below) as compact\n\
-descriptions of the lay-out of the C structs and the intended conversion\n\
-to/from Python values.\n\
+"Functions to convert between Python values and C structs.\n\
+Python bytes objects are used to hold the data representing the C struct\n\
+and also as format strings (explained below) to describe the layout of data\n\
+in the C struct.\n\
\n\
The optional first format char indicates byte order, size and alignment:\n\
@: native order, size & alignment (default)\n\
@@ -1991,26 +1982,31 @@ Whitespace between formats is ignored.\n\
\n\
The variable struct.error is an exception raised on errors.\n");
+
+static struct PyModuleDef _structmodule = {
+ PyModuleDef_HEAD_INIT,
+ "_struct",
+ module_doc,
+ -1,
+ module_functions,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
PyMODINIT_FUNC
-init_struct(void)
+PyInit__struct(void)
{
- PyObject *ver, *m;
+ PyObject *m;
- ver = PyString_FromString("0.2");
- if (ver == NULL)
- return;
-
- m = Py_InitModule3("_struct", module_functions, module_doc);
+ m = PyModule_Create(&_structmodule);
if (m == NULL)
- return;
+ return NULL;
Py_TYPE(&PyStructType) = &PyType_Type;
if (PyType_Ready(&PyStructType) < 0)
- return;
-
- /* This speed trick can't be used until overflow masking goes
- away, because native endian always raises exceptions
- instead of overflow masking. */
+ return NULL;
/* Check endian and swap in faster functions */
{
@@ -2055,7 +2051,7 @@ init_struct(void)
if (StructError == NULL) {
StructError = PyErr_NewException("struct.error", NULL, NULL);
if (StructError == NULL)
- return;
+ return NULL;
}
Py_INCREF(StructError);
@@ -2064,8 +2060,5 @@ init_struct(void)
Py_INCREF((PyObject*)&PyStructType);
PyModule_AddObject(m, "Struct", (PyObject*)&PyStructType);
- PyModule_AddObject(m, "__version__", ver);
-
- PyModule_AddIntConstant(m, "_PY_STRUCT_RANGE_CHECKING", 1);
- PyModule_AddIntConstant(m, "_PY_STRUCT_FLOAT_COERCE", 1);
+ return m;
}