From 859850faf7bed5464f644df3aeedd40b9663be6a Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Mon, 4 Nov 2002 22:22:12 +0000 Subject: Change to representing buffers ('B') as (LEN, STRING) in Python, rather than as just a string. Makes the code more messy, but needed for compatibility with existing PSA Python code which seems to be too knotty to separate out. (This used to be commit 20d88a7d1e2a6d2daca29c5ffff3781197a97b57) --- source3/python/py_tdbpack.c | 242 ++++++++++++++++++++------------------------ 1 file changed, 112 insertions(+), 130 deletions(-) diff --git a/source3/python/py_tdbpack.c b/source3/python/py_tdbpack.c index 6c697533a0..001b082f16 100644 --- a/source3/python/py_tdbpack.c +++ b/source3/python/py_tdbpack.c @@ -31,18 +31,20 @@ static int pytdbpack_calc_reqd_len(char *format_str, PyObject *val_seq); static PyObject *pytdbpack_unpack_item(char, - char **pbuf, - int *plen); -static int -pytdbpack_calc_item_len(char format_ch, - PyObject *val_obj); + char **pbuf, + int *plen); static PyObject *pytdbpack_pack_data(const char *format_str, PyObject *val_seq, unsigned char *buf); - + + +static PyObject *pytdbpack_bad_type(char ch, + const char *expected, + PyObject *val_obj); + static const char * pytdbpack_docstring = "Convert between Python values and Samba binary encodings. @@ -76,7 +78,8 @@ tdbpack format strings: value of the Python object is used. 'B': 4-byte LE length, followed by that many bytes of binary data. - Corresponds to a Python byte string of the appropriate length. + Corresponds to a Python integer giving the length, followed by a byte + string of the appropriate length. '$': Special flag indicating that the preceding format code should be repeated while data remains. This is only supported for unpacking. @@ -253,7 +256,7 @@ pytdbpack_unpack(PyObject *self, last_format = format; } - /* put leftovers in box for lunch tomorrow */ + /* save leftovers for next time */ rest_string = PyString_FromStringAndSize(ppacked, packed_len); if (!rest_string) goto failed; @@ -302,8 +305,6 @@ pytdbpack_calc_reqd_len(char *format_str, for (p = format_str, val_i = 0; *p; p++, val_i++) { char ch = *p; - PyObject *val_obj; - int item_len; if (val_i >= val_len) { PyErr_Format(PyExc_IndexError, @@ -313,15 +314,57 @@ pytdbpack_calc_reqd_len(char *format_str, } /* borrow a reference to the item */ - val_obj = PySequence_GetItem(val_seq, val_i); - if (!val_obj) - return -1; + if (ch == 'd' || ch == 'p') + len += 4; + else if (ch == 'w') + len += 2; + else if (ch == 'f' || ch == 'P') { + /* nul-terminated 8-bit string */ + int item_len; + PyObject *str_obj; + + str_obj = PySequence_GetItem(val_seq, val_i); + if (!str_obj) + return -1; + + item_len = PyString_Size(str_obj); + if (item_len == -1) { + pytdbpack_bad_type(ch, "String", str_obj); + return -1; + } + + len += item_len; + } + else if (ch == 'B') { + /* length-preceded byte buffer: n bytes, plus a preceding + * word */ + PyObject *len_obj; + long len_val; + + len_obj = PySequence_GetItem(val_seq, val_i); + val_i++; /* skip over buffer */ + + if (!PyNumber_Check(len_obj)) { + pytdbpack_bad_type(ch, "Number", len_obj); + return -1; + } - item_len = pytdbpack_calc_item_len(ch, val_obj); - if (item_len == -1) + len_val = PyInt_AsLong(len_obj); + if (len_val < 0) { + PyErr_Format(PyExc_ValueError, + "%s: format 'B' requires positive integer", __FUNCTION__); + return -1; + } + + len += 4 + len_val; + } + else { + PyErr_Format(PyExc_ValueError, + "%s: format character '%c' is not supported", + __FUNCTION__, ch); + return -1; - else - len += item_len; + } } return len; @@ -343,56 +386,6 @@ static PyObject *pytdbpack_bad_type(char ch, } -/* - * Calculate the number of bytes required to pack a single value. While doing - * this, also conduct some initial checks that the argument types are - * reasonable. - * - * Returns -1 on exception. - */ -static int -pytdbpack_calc_item_len(char ch, - PyObject *val_obj) -{ - if (ch == 'd' || ch == 'w') { - if (!PyInt_Check(val_obj)) { - pytdbpack_bad_type(ch, "Int", val_obj); - return -1; - } - if (ch == 'w') - return 2; - else - return 4; - } else if (ch == 'p') { - return 4; - } - else if (ch == 'f' || ch == 'P' || ch == 'B') { - /* nul-terminated 8-bit string */ - if (!PyString_Check(val_obj)) { - pytdbpack_bad_type(ch, "String", val_obj); - return -1; - } - - if (ch == 'B') { - /* byte buffer; just use Python string's length, plus - a preceding word */ - return 4 + PyString_GET_SIZE(val_obj); - } - else { - /* one nul character */ - return 1 + PyString_GET_SIZE(val_obj); - } - } - else { - PyErr_Format(PyExc_ValueError, - "tdbpack: format character '%c' is not supported", - ch); - - return -1; - } -} - - /* XXX: glib and Samba have quicker macro for doing the endianness conversions, but I don't know of one in plain libc, and it's probably not a big deal. I @@ -566,63 +559,6 @@ static PyObject *pytdbpack_unpack_item(char ch, -/* - Pack a single item VAL_OBJ, encoded using format CH, into a buffer at *PBUF, - and advance the pointer. Buffer length has been pre-calculated so we are - sure that there is enough space. - -*/ -static PyObject * -pytdbpack_pack_item(char ch, - PyObject *val_obj, - unsigned char **pbuf) -{ - if (ch == 'w') { - unsigned long val_long = PyInt_AsLong(val_obj); - (*pbuf)[0] = val_long & 0xff; - (*pbuf)[1] = (val_long >> 8) & 0xff; - (*pbuf) += 2; - } - else if (ch == 'd') { - /* 4-byte LE number */ - pack_int32(PyInt_AsLong(val_obj), pbuf); - } - else if (ch == 'p') { - /* "Pointer" value -- in the subset of DCERPC used by Samba, - this is really just an "exists" or "does not exist" - flag. */ - pack_int32(PyObject_IsTrue(val_obj), pbuf); - } - else if (ch == 'f' || ch == 'P') { - int size; - char *sval; - - size = PyString_GET_SIZE(val_obj); - sval = PyString_AS_STRING(val_obj); - pack_bytes(size+1, sval, pbuf); /* include nul */ - } - else if (ch == 'B') { - int size; - char *sval; - - size = PyString_GET_SIZE(val_obj); - pack_int32(size, pbuf); - sval = PyString_AS_STRING(val_obj); - pack_bytes(size, sval, pbuf); /* do not include nul */ - } - else { - /* this ought to be caught while calculating the length, but - just in case. */ - PyErr_Format(PyExc_ValueError, - "%s: format character '%c' is not supported", - __FUNCTION__, ch); - - return NULL; - } - - return Py_None; -} - /* Pack data according to FORMAT_STR from the elements of VAL_SEQ into @@ -639,7 +575,7 @@ pytdbpack_pack_item(char ch, PyObject * pytdbpack_pack_data(const char *format_str, PyObject *val_seq, - unsigned char *packed_buf) + unsigned char *packed) { int i; @@ -648,21 +584,67 @@ pytdbpack_pack_data(const char *format_str, PyObject *val_obj; /* borrow a reference to the item */ - val_obj = PySequence_Fast_GET_ITEM(val_seq, i); + val_obj = PySequence_GetItem(val_seq, i); if (!val_obj) return NULL; - if (!pytdbpack_pack_item(ch, val_obj, &packed_buf)) + if (ch == 'w') { + unsigned long val_long = PyInt_AsLong(val_obj); + (packed)[0] = val_long & 0xff; + (packed)[1] = (val_long >> 8) & 0xff; + (packed) += 2; + } + else if (ch == 'd') { + /* 4-byte LE number */ + pack_int32(PyInt_AsLong(val_obj), &packed); + } + else if (ch == 'p') { + /* "Pointer" value -- in the subset of DCERPC used by Samba, + this is really just an "exists" or "does not exist" + flag. */ + pack_int32(PyObject_IsTrue(val_obj), &packed); + } + else if (ch == 'f' || ch == 'P') { + int size; + char *sval; + + size = PyString_GET_SIZE(val_obj); + sval = PyString_AS_STRING(val_obj); + pack_bytes(size+1, sval, &packed); /* include nul */ + } + else if (ch == 'B') { + long size; + char *sval; + + size = PyInt_AsLong(val_obj); + pack_int32(size, &packed); + + val_obj = PySequence_GetItem(val_seq, ++i); + if (!val_obj) + return NULL; + + sval = PyString_AsString(val_obj); + if (!sval) + return NULL; + + pack_bytes(size, sval, &packed); /* do not include nul */ + } + else { + /* this ought to be caught while calculating the length, but + just in case. */ + PyErr_Format(PyExc_ValueError, + "%s: format character '%c' is not supported", + __FUNCTION__, ch); + return NULL; + } } - + return Py_None; } - - static PyMethodDef pytdbpack_methods[] = { { "pack", pytdbpack_pack, METH_VARARGS, (char *) pytdbpack_pack_doc }, { "unpack", pytdbpack_unpack, METH_VARARGS, (char *) pytdbpack_unpack_doc }, -- cgit