[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/python/cpython/main/Modules/_struct.c [Back]  [Original]

/* 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);
}

Web Proxy Viewer  |  New URL  |  Original Page