diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/python/py_tdbpack.c | 243 |
1 files changed, 56 insertions, 187 deletions
diff --git a/source3/python/py_tdbpack.c b/source3/python/py_tdbpack.c index 7180c3e12c..d8c3d46773 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 *pytdbpack_unpack_item(char, char **pbuf, int *plen, PyObject *); +static PyObject *pytdbunpack_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 pytdbpack_unpack_doc[] = +static char const pytdbunpack_doc[] = "unpack(format, buffer) -> (values, rest) Unpack Samba binary data according to format string. @@ -145,6 +145,7 @@ notes: "; +const char *pytdb_string_encoding = "cp850"; /* @@ -324,7 +325,7 @@ pytdbpack_str_850(PyObject *val_iter, PyObject *packed_list) val_obj = NULL; } - if (!(cp850_str = PyUnicode_AsEncodedString(unicode_obj, "cp850", NULL))) + if (!(cp850_str = PyUnicode_AsEncodedString(unicode_obj, pytdb_string_encoding, NULL))) goto out; if (!nul_str) @@ -378,45 +379,47 @@ pytdbpack_buffer(PyObject *val_iter, PyObject *packed_list) } -#if 0 -else if (ch == 'B') { - long size; - char *sval; - - if (!PyNumber_Check(val_obj)) { - pytdbpack_bad_type(ch, "Number", val_obj); - return NULL; - } +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 (!(val_obj = PyNumber_Long(val_obj))) - return NULL; - size = PyLong_AsLong(val_obj); - pack_le_uint32(size, &packed); +/* + 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; +} - /* 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; +static void pack_bytes(long len, const char *from, + unsigned char **pbuf) +{ + memcpy(*pbuf, from, len); + (*pbuf) += len; } -#endif + + static PyObject * -pytdbpack_unpack(PyObject *self, +pytdbunpack(PyObject *self, PyObject *args) { char *format_str, *packed_str, *ppacked; @@ -445,7 +448,7 @@ pytdbpack_unpack(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 (!pytdbpack_unpack_item(format_str[i], &ppacked, &packed_len, val_list)) + if (!pytdbunpack_item(format_str[i], &ppacked, &packed_len, val_list)) goto failed; } @@ -458,7 +461,7 @@ pytdbpack_unpack(PyObject *self, return NULL; } while (packed_len > 0) - if (!pytdbpack_unpack_item(last_format, &ppacked, &packed_len, val_list)) + if (!pytdbunpack_item(last_format, &ppacked, &packed_len, val_list)) goto failed; } @@ -484,142 +487,8 @@ pytdbpack_unpack(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 -unpack_err_too_short(void) +pytdbunpack_err_too_short(void) { PyErr_Format(PyExc_IndexError, __FUNCTION__ ": data too short for unpack format"); @@ -627,13 +496,13 @@ unpack_err_too_short(void) static PyObject * -unpack_uint32(char **pbuf, int *plen) +pytdbunpack_uint32(char **pbuf, int *plen) { unsigned long v; unsigned char *b; if (*plen < 4) { - unpack_err_too_short(); + pytdbunpack_err_too_short(); return NULL; } @@ -647,13 +516,13 @@ unpack_uint32(char **pbuf, int *plen) } -static PyObject *unpack_int16(char **pbuf, int *plen) +static PyObject *pytdbunpack_int16(char **pbuf, int *plen) { long v; unsigned char *b; if (*plen < 2) { - unpack_err_too_short(); + pytdbunpack_err_too_short(); return NULL; } @@ -668,7 +537,7 @@ static PyObject *unpack_int16(char **pbuf, int *plen) static PyObject * -unpack_string(char **pbuf, int *plen) +pytdbunpack_string(char **pbuf, int *plen) { int len; char *nul_ptr, *start; @@ -677,7 +546,7 @@ unpack_string(char **pbuf, int *plen) nul_ptr = memchr(start, '\0', *plen); if (!nul_ptr) { - unpack_err_too_short(); + pytdbunpack_err_too_short(); return NULL; } @@ -686,12 +555,12 @@ unpack_string(char **pbuf, int *plen) *pbuf += len + 1; /* skip \0 */ *plen -= len + 1; - return PyString_FromStringAndSize(start, len); + return PyString_Decode(start, len, pytdb_string_encoding, NULL); } static PyObject * -unpack_buffer(char **pbuf, int *plen, PyObject *val_list) +pytdbunpack_buffer(char **pbuf, int *plen, PyObject *val_list) { /* first get 32-bit len */ long slen; @@ -700,7 +569,7 @@ unpack_buffer(char **pbuf, int *plen, PyObject *val_list) PyObject *str_obj = NULL, *len_obj = NULL; if (*plen < 4) { - unpack_err_too_short(); + pytdbunpack_err_too_short(); return NULL; } @@ -757,7 +626,7 @@ unpack_buffer(char **pbuf, int *plen, PyObject *val_list) Returns a reference to None, or NULL for failure. */ -static PyObject *pytdbpack_unpack_item(char ch, +static PyObject *pytdbunpack_item(char ch, char **pbuf, int *plen, PyObject *val_list) @@ -765,17 +634,17 @@ static PyObject *pytdbpack_unpack_item(char ch, PyObject *result; if (ch == 'w') { /* 16-bit int */ - result = unpack_int16(pbuf, plen); + result = pytdbunpack_int16(pbuf, plen); } else if (ch == 'd' || ch == 'p') { /* 32-bit int */ /* pointers can just come through as integers */ - result = unpack_uint32(pbuf, plen); + result = pytdbunpack_uint32(pbuf, plen); } else if (ch == 'f' || ch == 'P') { /* nul-term string */ - result = unpack_string(pbuf, plen); + result = pytdbunpack_string(pbuf, plen); } else if (ch == 'B') { /* length, buffer */ - return unpack_buffer(pbuf, plen, val_list); + return pytdbunpack_buffer(pbuf, plen, val_list); } else { PyErr_Format(PyExc_ValueError, @@ -801,7 +670,7 @@ static PyObject *pytdbpack_unpack_item(char ch, static PyMethodDef pytdbpack_methods[] = { { "pack", pytdbpack, METH_VARARGS, (char *) pytdbpack_doc }, - { "unpack", pytdbpack_unpack, METH_VARARGS, (char *) pytdbpack_unpack_doc }, + { "unpack", pytdbunpack, METH_VARARGS, (char *) pytdbunpack_doc }, }; DL_EXPORT(void) |