/* struct module -- pack values into and (out of) bytes objects */
/* New version supporting byte order, alignment and size options,
byte strings, and unsigned numbers */
#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
#include "Python.h"
#include "pycore_bytesobject.h" // _PyBytesWriter
#include "pycore_lock.h" // _PyOnceFlag_CallOnce()
#include "pycore_long.h" // _PyLong_AsByteArray()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
#include // offsetof()
/*[clinic input]
class Struct "PyStructObject *" "&PyStructType"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9b032058a83ed7c3]*/
typedef struct {
PyObject *cache;
PyObject *PyStructType;
PyObject *unpackiter_type;
PyObject *StructError;
} _structmodulestate;
static inline _structmodulestate*
get_struct_state(PyObject *module)
{
void *state = _PyModule_GetState(module);
assert(state != NULL);
return (_structmodulestate *)state;
}
static struct PyModuleDef _structmodule;
#define get_struct_state_structinst(self) \
(get_struct_state(PyType_GetModuleByDef(Py_TYPE(self), &_structmodule)))
#define get_struct_state_iterinst(self) \
(get_struct_state(PyType_GetModule(Py_TYPE(self))))
/* The translation function for each format character is table driven */
typedef struct _formatdef {
const char *format;
Py_ssize_t size;
Py_ssize_t alignment;
PyObject* (*unpack)(_structmodulestate *, const char *,
const struct _formatdef *);
int (*pack)(_structmodulestate *, char *, PyObject *,
const struct _formatdef *);
} formatdef;
typedef struct _formatcode {
const struct _formatdef *fmtdef;
Py_ssize_t offset;
Py_ssize_t size;
Py_ssize_t repeat;
} formatcode;
/* Struct object interface */
typedef struct {
PyObject_HEAD
Py_ssize_t s_size;
Py_ssize_t s_len;
formatcode *s_codes;
PyObject *s_format;
PyObject *weakreflist; /* List of weak references */
bool init_called;
} PyStructObject;
#define PyStructObject_CAST(op) ((PyStructObject *)(op))
#define PyStruct_Check(op, state) PyObject_TypeCheck(op, (PyTypeObject *)(state)->PyStructType)
#ifdef __powerc
#pragma options align=reset
#endif
/*[python input]
class cache_struct_converter(CConverter):
type = 'PyStructObject *'
converter = 'cache_struct_converter'
c_default = "NULL"
broken_limited_capi = True
def parse_arg(self, argname, displayname, *, limited_capi):
assert not limited_capi
return self.format_code("""
if (!{converter}(module, {argname}, &{paramname})) {{{{
goto exit;
}}}}
""",
argname=argname,
converter=self.converter)
def cleanup(self):
return "Py_XDECREF(%s);\n" % self.name
[python start generated code]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=c33b27d6b06006c6]*/
static int cache_struct_converter(PyObject *, PyObject *, PyStructObject **);
#include "clinic/_struct.c.h"
/* Helper for integer format codes: converts an arbitrary Python object to a
PyLongObject if possible, otherwise fails. Caller should decref. */
static PyObject *
get_pylong(_structmodulestate *state, PyObject *v)
{
assert(v != NULL);
if (!PyLong_Check(v)) {
/* Not an integer; try to use __index__ to convert. */
if (PyIndex_Check(v)) {
v = _PyNumber_Index(v);
if (v == NULL)
return NULL;
}
else {
PyErr_SetString(state->StructError,
"required argument is not an integer");
return NULL;
}
}
else
Py_INCREF(v);
assert(PyLong_Check(v));
return v;
}
/* Helper routine to get a C long and raise the appropriate error if it isn't
one */
static int
get_long(_structmodulestate *state, PyObject *v, long *p)
{
long x;
v = get_pylong(state, v);
if (v == NULL)
return -1;
assert(PyLong_Check(v));
x = PyLong_AsLong(v);
Py_DECREF(v);
if (x == (long)-1 && PyErr_Occurred()) {
return -1;
}
*p = x;
return 0;
}
/* Same, but handling unsigned long */
static int
get_ulong(_structmodulestate *state, PyObject *v, unsigned long *p)
{
unsigned long x;
v = get_pylong(state, v);
if (v == NULL)
return -1;
assert(PyLong_Check(v));
x = PyLong_AsUnsignedLong(v);
Py_DECREF(v);
if (x == (unsigned long)-1 && PyErr_Occurred()) {
return -1;
}
*p = x;
return 0;
}
/* Same, but handling native long long. */
static int
get_longlong(_structmodulestate *state, PyObject *v, long long *p)
{
long long x;
v = get_pylong(state, v);
if (v == NULL)
return -1;
assert(PyLong_Check(v));
x = PyLong_AsLongLong(v);
Py_DECREF(v);
if (x == (long long)-1 && PyErr_Occurred()) {
return -1;
}
*p = x;
return 0;
}
/* Same, but handling native unsigned long long. */
static int
get_ulonglong(_structmodulestate *state, PyObject *v, unsigned long long *p)
{
unsigned long long x;
v = get_pylong(state, v);
if (v == NULL)
return -1;
assert(PyLong_Check(v));
x = PyLong_AsUnsignedLongLong(v);
Py_DECREF(v);
if (x == (unsigned long long)-1 && PyErr_Occurred()) {
return -1;
}
*p = x;
return 0;
}
/* Same, but handling Py_ssize_t */
static int
get_ssize_t(_structmodulestate *state, PyObject *v, Py_ssize_t *p)
{
Py_ssize_t x;
v = get_pylong(state, v);
if (v == NULL)
return -1;
assert(PyLong_Check(v));
x = PyLong_AsSsize_t(v);
Py_DECREF(v);
if (x == (Py_ssize_t)-1 && PyErr_Occurred()) {
return -1;
}
*p = x;
return 0;
}
/* Same, but handling size_t */
static int
get_size_t(_structmodulestate *state, PyObject *v, size_t *p)
{
size_t x;
v = get_pylong(state, v);
if (v == NULL)
return -1;
assert(PyLong_Check(v));
x = PyLong_AsSize_t(v);
Py_DECREF(v);
if (x == (size_t)-1 && PyErr_Occurred()) {
return -1;
}
*p = x;
return 0;
}
#define RANGE_ERROR(state, f, flag) return _range_error(state, f, flag)
/* Floating-point helpers */
static PyObject *
unpack_halffloat(const char *p, /* start of 2-byte string */
int le) /* true for little-endian, false for big-endian */
{
double x = PyFloat_Unpack2(p, le);
if (x == -1.0 && PyErr_Occurred()) {
return NULL;
}
return PyFloat_FromDouble(x);
}
static int
pack_halffloat(_structmodulestate *state,
char *p, /* start of 2-byte string */
PyObject *v, /* value to pack */
int le) /* true for little-endian, false for big-endian */
{
double x = PyFloat_AsDouble(v);
if (x == -1.0 && PyErr_Occurred()) {
PyErr_SetString(state->StructError,
"required argument is not a float");
return -1;
}
return PyFloat_Pack2(x, p, le);
}
static PyObject *
unpack_float(const char *p, /* start of 4-byte string */
int le) /* true for little-endian, false for big-endian */
{
double x;
x = PyFloat_Unpack4(p, le);
if (x == -1.0 && PyErr_Occurred())
return NULL;
return PyFloat_FromDouble(x);
}
static PyObject *
unpack_double(const char *p, /* start of 8-byte string */
int le) /* true for little-endian, false for big-endian */
{
double x;
x = PyFloat_Unpack8(p, le);
if (x == -1.0 && PyErr_Occurred())
return NULL;
return PyFloat_FromDouble(x);
}
/* Helper to format the range error exceptions */
static int
_range_error(_structmodulestate *state, const formatdef *f, int is_unsigned)
{
/* ulargest is the largest unsigned value with f->size bytes.
* Note that the simpler:
* ((size_t)1 size * 8)) - 1
* doesn't work when f->size == sizeof(size_t) because C doesn't
* define what happens when a left shift count is >= the number of
* bits in the integer being shifted; e.g., on some boxes it doesn't
* shift at all when they're equal.
*/
const size_t ulargest = (size_t)-1 >> ((SIZEOF_SIZE_T - f->size)*8);
assert(f->size >= 1 && f->size StructError,
"'%s' format requires 0 \n\
\n\
The remaining characters indicate types of args and must match exactly;\n\
these can be preceded by a decimal repeat count:\n\
x: pad byte (no data); c: char; b: signed byte; B: unsigned byte;\n\
?: _Bool; h: short; H: unsigned short; i: int; I: unsigned int;\n\
l: long; L: unsigned long; q: long long; Q: unsigned long long;\n\
f: float; d: double; e: half-float;\n\
F: float complex; D: double complex.\n\
Special cases (preceding decimal count indicates length):\n\
s: byte string (array of char); p: Pascal string (with count byte).\n\
Special cases (only available in native format):\n\
n: ssize_t; N: size_t;\n\
P: an integer type that is wide enough to hold a pointer.\n\
Whitespace between formats is ignored.\n\
\n\
The variable struct.error is an exception raised on errors.\n");
static int
_structmodule_traverse(PyObject *module, visitproc visit, void *arg)
{
_structmodulestate *state = get_struct_state(module);
if (state) {
Py_VISIT(state->cache);
Py_VISIT(state->PyStructType);
Py_VISIT(state->unpackiter_type);
Py_VISIT(state->StructError);
}
return 0;
}
static int
_structmodule_clear(PyObject *module)
{
_structmodulestate *state = get_struct_state(module);
if (state) {
Py_CLEAR(state->cache);
Py_CLEAR(state->PyStructType);
Py_CLEAR(state->unpackiter_type);
Py_CLEAR(state->StructError);
}
return 0;
}
static void
_structmodule_free(void *module)
{
(void)_structmodule_clear((PyObject *)module);
}
static int
_structmodule_exec(PyObject *m)
{
_structmodulestate *state = get_struct_state(m);
state->cache = PyDict_New();
if (state->cache == NULL) {
return -1;
}
state->PyStructType = PyType_FromModuleAndSpec(
m, &PyStructType_spec, NULL);
if (state->PyStructType == NULL) {
return -1;
}
if (PyModule_AddType(m, (PyTypeObject *)state->PyStructType) < 0) {
return -1;
}
state->unpackiter_type = PyType_FromModuleAndSpec(
m, &unpackiter_type_spec, NULL);
if (state->unpackiter_type == NULL) {
return -1;
}
/* init cannot fail */
(void)_PyOnceFlag_CallOnce(&endian_tables_init_once, init_endian_tables, NULL);
/* Add some symbolic constants to the module */
state->StructError = PyErr_NewException("struct.error", NULL, NULL);
if (state->StructError == NULL) {
return -1;
}
if (PyModule_AddObjectRef(m, "error", state->StructError) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot _structmodule_slots[] = {
_Py_ABI_SLOT,
{Py_mod_exec, _structmodule_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
{0, NULL}
};
static struct PyModuleDef _structmodule = {
PyModuleDef_HEAD_INIT,
.m_name = "_struct",
.m_doc = module_doc,
.m_size = sizeof(_structmodulestate),
.m_methods = module_functions,
.m_slots = _structmodule_slots,
.m_traverse = _structmodule_traverse,
.m_clear = _structmodule_clear,
.m_free = _structmodule_free,
};
PyMODINIT_FUNC
PyInit__struct(void)
{
return PyModuleDef_Init(&_structmodule);
}