diff options
Diffstat (limited to 'source3/python')
-rwxr-xr-x | source3/python/examples/tdbpack/test_tdbpack.py | 2 | ||||
-rw-r--r-- | source3/python/py_tdbpack.c | 243 |
2 files changed, 189 insertions, 56 deletions
diff --git a/source3/python/examples/tdbpack/test_tdbpack.py b/source3/python/examples/tdbpack/test_tdbpack.py index d336454274..83282e745e 100755 --- a/source3/python/examples/tdbpack/test_tdbpack.py +++ b/source3/python/examples/tdbpack/test_tdbpack.py @@ -113,6 +113,8 @@ class PackTests(unittest.TestCase): not "canonical". """ cases = [('w', (42,), '\x2a\0'), + ('p', [None], '\0\0\0\0'), + ('p', ['true'], '\x01\0\0\0'), ] for packer in both_packers: diff --git a/source3/python/py_tdbpack.c b/source3/python/py_tdbpack.c index d8c3d46773..7180c3e12c 100644 --- a/source3/python/py_tdbpack.c +++ b/source3/python/py_tdbpack.c @@ -31,7 +31,7 @@ static PyObject * pytdbpack_number(char ch, PyObject *val_iter, PyObject *packed static PyObject * pytdbpack_str_850(PyObject *val_iter, PyObject *packed_list); static PyObject * pytdbpack_buffer(PyObject *val_iter, PyObject *packed_list); -static PyObject *pytdbunpack_item(char, char **pbuf, int *plen, PyObject *); +static PyObject *pytdbpack_unpack_item(char, char **pbuf, int *plen, PyObject *); static PyObject *pytdbpack_data(const char *format_str, PyObject *val_seq, @@ -117,7 +117,7 @@ notes: "; -static char const pytdbunpack_doc[] = +static char const pytdbpack_unpack_doc[] = "unpack(format, buffer) -> (values, rest) Unpack Samba binary data according to format string. @@ -145,7 +145,6 @@ notes: "; -const char *pytdb_string_encoding = "cp850"; /* @@ -325,7 +324,7 @@ pytdbpack_str_850(PyObject *val_iter, PyObject *packed_list) val_obj = NULL; } - if (!(cp850_str = PyUnicode_AsEncodedString(unicode_obj, pytdb_string_encoding, NULL))) + if (!(cp850_str = PyUnicode_AsEncodedString(unicode_obj, "cp850", NULL))) goto out; if (!nul_str) @@ -379,47 +378,45 @@ pytdbpack_buffer(PyObject *val_iter, PyObject *packed_list) } -static PyObject *pytdbpack_bad_type(char ch, - const char *expected, - PyObject *val_obj) -{ - PyObject *r = PyObject_Repr(val_obj); - if (!r) - return NULL; - PyErr_Format(PyExc_TypeError, - "tdbpack: format '%c' requires %s, not %s", - ch, expected, PyString_AS_STRING(r)); - Py_DECREF(r); - return val_obj; -} - +#if 0 +else if (ch == 'B') { + long size; + char *sval; -/* - 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 - realize this is kind of dumb because we'll almost always be on x86, but - being safe is important. -*/ -static void pack_le_uint32(unsigned long val_long, unsigned char *pbuf) -{ - pbuf[0] = val_long & 0xff; - pbuf[1] = (val_long >> 8) & 0xff; - pbuf[2] = (val_long >> 16) & 0xff; - pbuf[3] = (val_long >> 24) & 0xff; -} + if (!PyNumber_Check(val_obj)) { + pytdbpack_bad_type(ch, "Number", val_obj); + return NULL; + } + if (!(val_obj = PyNumber_Long(val_obj))) + return NULL; -static void pack_bytes(long len, const char *from, - unsigned char **pbuf) -{ - memcpy(*pbuf, from, len); - (*pbuf) += len; -} + size = PyLong_AsLong(val_obj); + pack_le_uint32(size, &packed); + /* Release the new reference created by the cast */ + Py_DECREF(val_obj); + val_obj = PySequence_GetItem(val_seq, val_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 { + + } + + return Py_None; +} +#endif static PyObject * -pytdbunpack(PyObject *self, +pytdbpack_unpack(PyObject *self, PyObject *args) { char *format_str, *packed_str, *ppacked; @@ -448,7 +445,7 @@ pytdbunpack(PyObject *self, for (ppacked = packed_str, i = 0; i < format_len && format_str[i] != '$'; i++) { last_format = format_str[i]; /* packed_len is reduced in place */ - if (!pytdbunpack_item(format_str[i], &ppacked, &packed_len, val_list)) + if (!pytdbpack_unpack_item(format_str[i], &ppacked, &packed_len, val_list)) goto failed; } @@ -461,7 +458,7 @@ pytdbunpack(PyObject *self, return NULL; } while (packed_len > 0) - if (!pytdbunpack_item(last_format, &ppacked, &packed_len, val_list)) + if (!pytdbpack_unpack_item(last_format, &ppacked, &packed_len, val_list)) goto failed; } @@ -487,8 +484,142 @@ pytdbunpack(PyObject *self, } + +#if 0 +/* + Internal routine that calculates how many bytes will be required to + encode the values in the format. + + Also checks that the value list is the right size for the format list. + + Returns number of bytes (may be 0), or -1 if there's something wrong, in + which case a Python exception has been raised. + + Arguments: + + val_seq: a Fast Sequence (list or tuple), being all the values +*/ +static int +pytdbpack_calc_reqd_len(char *format_str, + PyObject *val_seq) +{ + int len = 0; + char *p; + int val_i; + int val_len; + + val_len = PySequence_Length(val_seq); + if (val_len == -1) + return -1; + + for (p = format_str, val_i = 0; *p; p++, val_i++) { + char ch = *p; + + if (val_i >= val_len) { + PyErr_Format(PyExc_IndexError, + "%s: value list is too short for format string", + __FUNCTION__); + return -1; + } + + /* borrow a reference to the item */ + 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; + + if (!PyString_Check(str_obj) || ((item_len = PyString_Size(str_obj)) == -1)) { + pytdbpack_bad_type(ch, "String", str_obj); + return -1; + } + + len += 1 + 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; + } + + 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; + } + } + + return len; +} +#endif + + +static PyObject *pytdbpack_bad_type(char ch, + const char *expected, + PyObject *val_obj) +{ + PyObject *r = PyObject_Repr(val_obj); + if (!r) + return NULL; + PyErr_Format(PyExc_TypeError, + "tdbpack: format '%c' requires %s, not %s", + ch, expected, PyString_AS_STRING(r)); + Py_DECREF(r); + return val_obj; +} + + +/* + 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 + realize this is kind of dumb because we'll almost always be on x86, but + being safe is important. +*/ +static void pack_le_uint32(unsigned long val_long, unsigned char *pbuf) +{ + pbuf[0] = val_long & 0xff; + pbuf[1] = (val_long >> 8) & 0xff; + pbuf[2] = (val_long >> 16) & 0xff; + pbuf[3] = (val_long >> 24) & 0xff; +} + + +static void pack_bytes(long len, const char *from, + unsigned char **pbuf) +{ + memcpy(*pbuf, from, len); + (*pbuf) += len; +} + + static void -pytdbunpack_err_too_short(void) +unpack_err_too_short(void) { PyErr_Format(PyExc_IndexError, __FUNCTION__ ": data too short for unpack format"); @@ -496,13 +627,13 @@ pytdbunpack_err_too_short(void) static PyObject * -pytdbunpack_uint32(char **pbuf, int *plen) +unpack_uint32(char **pbuf, int *plen) { unsigned long v; unsigned char *b; if (*plen < 4) { - pytdbunpack_err_too_short(); + unpack_err_too_short(); return NULL; } @@ -516,13 +647,13 @@ pytdbunpack_uint32(char **pbuf, int *plen) } -static PyObject *pytdbunpack_int16(char **pbuf, int *plen) +static PyObject *unpack_int16(char **pbuf, int *plen) { long v; unsigned char *b; if (*plen < 2) { - pytdbunpack_err_too_short(); + unpack_err_too_short(); return NULL; } @@ -537,7 +668,7 @@ static PyObject *pytdbunpack_int16(char **pbuf, int *plen) static PyObject * -pytdbunpack_string(char **pbuf, int *plen) +unpack_string(char **pbuf, int *plen) { int len; char *nul_ptr, *start; @@ -546,7 +677,7 @@ pytdbunpack_string(char **pbuf, int *plen) nul_ptr = memchr(start, '\0', *plen); if (!nul_ptr) { - pytdbunpack_err_too_short(); + unpack_err_too_short(); return NULL; } @@ -555,12 +686,12 @@ pytdbunpack_string(char **pbuf, int *plen) *pbuf += len + 1; /* skip \0 */ *plen -= len + 1; - return PyString_Decode(start, len, pytdb_string_encoding, NULL); + return PyString_FromStringAndSize(start, len); } static PyObject * -pytdbunpack_buffer(char **pbuf, int *plen, PyObject *val_list) +unpack_buffer(char **pbuf, int *plen, PyObject *val_list) { /* first get 32-bit len */ long slen; @@ -569,7 +700,7 @@ pytdbunpack_buffer(char **pbuf, int *plen, PyObject *val_list) PyObject *str_obj = NULL, *len_obj = NULL; if (*plen < 4) { - pytdbunpack_err_too_short(); + unpack_err_too_short(); return NULL; } @@ -626,7 +757,7 @@ pytdbunpack_buffer(char **pbuf, int *plen, PyObject *val_list) Returns a reference to None, or NULL for failure. */ -static PyObject *pytdbunpack_item(char ch, +static PyObject *pytdbpack_unpack_item(char ch, char **pbuf, int *plen, PyObject *val_list) @@ -634,17 +765,17 @@ static PyObject *pytdbunpack_item(char ch, PyObject *result; if (ch == 'w') { /* 16-bit int */ - result = pytdbunpack_int16(pbuf, plen); + result = unpack_int16(pbuf, plen); } else if (ch == 'd' || ch == 'p') { /* 32-bit int */ /* pointers can just come through as integers */ - result = pytdbunpack_uint32(pbuf, plen); + result = unpack_uint32(pbuf, plen); } else if (ch == 'f' || ch == 'P') { /* nul-term string */ - result = pytdbunpack_string(pbuf, plen); + result = unpack_string(pbuf, plen); } else if (ch == 'B') { /* length, buffer */ - return pytdbunpack_buffer(pbuf, plen, val_list); + return unpack_buffer(pbuf, plen, val_list); } else { PyErr_Format(PyExc_ValueError, @@ -670,7 +801,7 @@ static PyObject *pytdbunpack_item(char ch, static PyMethodDef pytdbpack_methods[] = { { "pack", pytdbpack, METH_VARARGS, (char *) pytdbpack_doc }, - { "unpack", pytdbunpack, METH_VARARGS, (char *) pytdbunpack_doc }, + { "unpack", pytdbpack_unpack, METH_VARARGS, (char *) pytdbpack_unpack_doc }, }; DL_EXPORT(void) |