summaryrefslogtreecommitdiff
path: root/source3/python/py_tdbpack.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/python/py_tdbpack.c')
-rw-r--r--source3/python/py_tdbpack.c243
1 files changed, 187 insertions, 56 deletions
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)