static PyObject * struct_calcsize(PyObject *self, PyObject *args) { char *fmt; const formatdef *f; int size; if (!PyArg_ParseTuple(args, "s:calcsize", &fmt)) return NULL; f = whichtable(&fmt); size = calcsize(fmt, f); if (size < 0) return NULL; return PyInt_FromLong((long)size); }
static PyObject * struct_unpack(PyObject *self, PyObject *args) { const formatdef *f, *e; char *str, *start, *fmt, *s; char c; int len, size, num; PyObject *res, *v; if (!PyArg_ParseTuple(args, "ss#:unpack", &fmt, &start, &len)) return NULL; f = whichtable(&fmt); size = calcsize(fmt, f); if (size < 0) return NULL; if (size != len) { PyErr_SetString(StructError, "unpack str size does not match format"); return NULL; } res = PyList_New(0); if (res == NULL) return NULL; str = start; s = fmt; while ((c = *s++) != '\0') { if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; while ('0' <= (c = *s++) && c <= '9') num = num*10 + (c - '0'); if (c == '\0') break; } else num = 1; e = getentry(c, f); if (e == NULL) goto fail; str = start + align((int)(str-start), c, e); if (num == 0 && c != 's') continue; do { if (c == 'x') { str += num; break; } if (c == 's') { /* num is string size, not repeat count */ v = PyString_FromStringAndSize(str, num); if (v == NULL) goto fail; str += num; num = 0; } else if (c == 'p') { /* num is string buffer size, not repeat count */ int n = *(unsigned char*)str; /* first byte (unsigned) is string size */ if (n >= num) n = num-1; v = PyString_FromStringAndSize(str+1, n); if (v == NULL) goto fail; str += num; num = 0; } else { v = e->unpack(str, e); if (v == NULL) goto fail; str += e->size; } if (v == NULL || PyList_Append(res, v) < 0) goto fail; Py_DECREF(v); } while (--num > 0); } v = PyList_AsTuple(res); Py_DECREF(res); return v; fail: Py_DECREF(res); return NULL; }
static PyObject * struct_pack(PyObject *self, PyObject *args) { const formatdef *f, *e; PyObject *format, *result, *v; char *fmt; int size, num; int i, n; char *s, *res, *restart, *nres; char c; if (args == NULL || !PyTuple_Check(args) || (n = PyTuple_Size(args)) < 1) { PyErr_SetString(PyExc_TypeError, "struct.pack requires at least one argument"); return NULL; } format = PyTuple_GetItem(args, 0); fmt = PyString_AsString(format); if (!fmt) return NULL; f = whichtable(&fmt); size = calcsize(fmt, f); if (size < 0) return NULL; result = PyString_FromStringAndSize((char *)NULL, size); if (result == NULL) return NULL; s = fmt; i = 1; res = restart = PyString_AsString(result); while ((c = *s++) != '\0') { if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; while ('0' <= (c = *s++) && c <= '9') num = num*10 + (c - '0'); if (c == '\0') break; } else num = 1; e = getentry(c, f); if (e == NULL) goto fail; nres = restart + align((int)(res-restart), c, e); /* Fill padd bytes with zeros */ while (res < nres) *res++ = '\0'; if (num == 0 && c != 's') continue; do { if (c == 'x') { /* doesn't consume arguments */ memset(res, '\0', num); res += num; break; } if (i >= n) { PyErr_SetString(StructError, "insufficient arguments to pack"); goto fail; } v = PyTuple_GetItem(args, i++); if (v == NULL) goto fail; if (c == 's') { /* num is string size, not repeat count */ int n; if (!PyString_Check(v)) { PyErr_SetString(StructError, "argument for 's' must be a string"); goto fail; } n = PyString_Size(v); if (n > num) n = num; if (n > 0) memcpy(res, PyString_AsString(v), n); if (n < num) memset(res+n, '\0', num-n); res += num; break; } else if (c == 'p') { /* num is string size + 1, to fit in the count byte */ int n; num--; /* now num is max string size */ if (!PyString_Check(v)) { PyErr_SetString(StructError, "argument for 'p' must be a string"); goto fail; } n = PyString_Size(v); if (n > num) n = num; if (n > 0) memcpy(res+1, PyString_AsString(v), n); if (n < num) /* no real need, just to be nice */ memset(res+1+n, '\0', num-n); if (n > 255) n = 255; *res++ = n; /* store the length byte */ res += num; break; } else { if (e->pack(res, v, e) < 0) goto fail; res += e->size; } } while (--num > 0); } if (i < n) { PyErr_SetString(StructError, "too many arguments for pack format"); goto fail; } return result; fail: Py_DECREF(result); return NULL; }
static int prepare_s(PyStructObject *self) { const formatdef *f; const formatdef *e; formatcode *codes; const char *s; const char *fmt; char c; Py_ssize_t size, len, num, itemsize, x; fmt = PyBytes_AS_STRING(self->s_format); f = whichtable((char **)&fmt); s = fmt; size = 0; len = 0; while ((c = *s++) != '\0') { if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; while ('0' <= (c = *s++) && c <= '9') { x = num*10 + (c - '0'); if (x/10 != num) { PyErr_SetString( StructError, "overflow in item count"); return -1; } num = x; } if (c == '\0') break; } else num = 1; e = getentry(c, f); if (e == NULL) return -1; switch (c) { case 's': /* fall through */ case 'p': len++; break; case 'x': break; default: len += num; break; } itemsize = e->size; size = align(size, c, e); x = num * itemsize; size += x; if (x/itemsize != num || size < 0) { PyErr_SetString(StructError, "total struct size too long"); return -1; } } /* check for overflow */ if ((len + 1) > (PY_SSIZE_T_MAX / sizeof(formatcode))) { PyErr_NoMemory(); return -1; } self->s_size = size; self->s_len = len; codes = PyMem_MALLOC((len + 1) * sizeof(formatcode)); if (codes == NULL) { PyErr_NoMemory(); return -1; } self->s_codes = codes; s = fmt; size = 0; while ((c = *s++) != '\0') { if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; while ('0' <= (c = *s++) && c <= '9') num = num*10 + (c - '0'); if (c == '\0') break; } else num = 1; e = getentry(c, f); size = align(size, c, e); if (c == 's' || c == 'p') { codes->offset = size; codes->size = num; codes->fmtdef = e; codes++; size += num; } else if (c == 'x') { size += num; } else { while (--num >= 0) { codes->offset = size; codes->size = e->size; codes->fmtdef = e; codes++; size += e->size; } } } codes->fmtdef = NULL; codes->offset = size; codes->size = 0; return 0; }
static int prepare_s(PyStructObject *self) { const formatdef *f; const formatdef *e; formatcode *codes; const char *s; const char *fmt; char c; Py_ssize_t size, len, num, itemsize; fmt = PyBytes_AS_STRING(self->s_format); f = whichtable((char **)&fmt); s = fmt; size = 0; len = 0; while ((c = *s++) != '\0') { if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; while ('0' <= (c = *s++) && c <= '9') { /* overflow-safe version of if (num*10 + (c - '0') > PY_SSIZE_T_MAX) { ... } */ if (num >= PY_SSIZE_T_MAX / 10 && ( num > PY_SSIZE_T_MAX / 10 || (c - '0') > PY_SSIZE_T_MAX % 10)) goto overflow; num = num*10 + (c - '0'); } if (c == '\0') { PyErr_SetString(StructError, "repeat count given without format specifier"); return -1; } } else num = 1; e = getentry(c, f); if (e == NULL) return -1; switch (c) { case 's': /* fall through */ case 'p': len++; break; case 'x': break; default: len += num; break; } itemsize = e->size; size = align(size, c, e); if (size == -1) goto overflow; /* if (size + num * itemsize > PY_SSIZE_T_MAX) { ... } */ if (num > (PY_SSIZE_T_MAX - size) / itemsize) goto overflow; size += num * itemsize; } /* check for overflow */ if ((len + 1) > (PY_SSIZE_T_MAX / sizeof(formatcode))) { PyErr_NoMemory(); return -1; } self->s_size = size; self->s_len = len; codes = (formatcode *) PyMem_MALLOC((len + 1) * sizeof(formatcode)); if (codes == NULL) { PyErr_NoMemory(); return -1; } /* Free any s_codes value left over from a previous initialization. */ if (self->s_codes != NULL) PyMem_FREE(self->s_codes); self->s_codes = codes; s = fmt; size = 0; while ((c = *s++) != '\0') { if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; while ('0' <= (c = *s++) && c <= '9') num = num*10 + (c - '0'); if (c == '\0') break; } else num = 1; e = getentry(c, f); size = align(size, c, e); if (c == 's' || c == 'p') { codes->offset = size; codes->size = num; codes->fmtdef = e; codes++; size += num; } else if (c == 'x') { size += num; } else { while (--num >= 0) { codes->offset = size; codes->size = e->size; codes->fmtdef = e; codes++; size += e->size; } } } codes->fmtdef = NULL; codes->offset = size; codes->size = 0; return 0; overflow: PyErr_SetString(StructError, "total struct size too long"); return -1; }