1 /* -*- c-file-style: "python"; indent-tabs-mode: nil; -*-
3 Python wrapper for Samba tdb pack/unpack functions
4 Copyright (C) Martin Pool 2002
7 NOTE PYTHON STYLE GUIDE
8 http://www.python.org/peps/pep-0007.html
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 static int pytdbpack_calc_reqd_len(char *format_str,
33 static PyObject *pytdbpack_unpack_item(char,
37 pytdbpack_calc_item_len(char format_ch,
40 static PyObject *pytdbpack_pack_data(const char *format_str,
46 static const char * pytdbpack_docstring =
47 "Convert between Python values and Samba binary encodings.
49 This module is conceptually similar to the standard 'struct' module, but it
50 uses both a different binary format and a different description string.
52 Samba's encoding is based on that used inside DCE-RPC and SMB: a
53 little-endian, unpadded, non-self-describing binary format. It is intended
54 that these functions be as similar as possible to the routines in Samba's
55 tdb/tdbutil module, with appropriate adjustments for Python datatypes.
57 Python strings are used to specify the format of data to be packed or
60 Strings in TDBs are typically stored in DOS codepages. The caller of this
61 module must make appropriate translations if necessary, typically to and from
64 tdbpack format strings:
66 'f': NULL-terminated string in DOS codepage
70 'd': 4 byte little-endian number
72 'w': 2 byte little-endian number
74 'P': \"Pointer\" value -- in the subset of DCERPC used by Samba, this is
75 really just an \"exists\" or \"does not exist\" flag. The boolean
76 value of the Python object is used.
78 'B': 4-byte LE length, followed by that many bytes of binary data.
79 Corresponds to a Python byte string of the appropriate length.
81 '$': Special flag indicating that the preceding format code should be
82 repeated while data remains. This is only supported for unpacking.
84 Every code corresponds to a single Python object, except 'B' which
85 corresponds to two values (length and contents), and '$', which produces
86 however many make sense.
90 static char const pytdbpack_pack_doc[] =
91 "pack(format, values) -> buffer
92 Pack Python objects into Samba binary format according to format string.
95 format -- string of tdbpack format characters
96 values -- sequence of value objects corresponding 1:1 to format characters
99 buffer -- string containing packed data
102 IndexError -- if there are not the same number of format codes as of
104 ValueError -- if any of the format characters is illegal
105 TypeError -- if the format is not a string, or values is not a sequence,
106 or any of the values is of the wrong type for the corresponding
111 static char const pytdbpack_unpack_doc[] =
112 "unpack(format, buffer) -> (values, rest)
113 Unpack Samba binary data according to format string.
116 format -- string of tdbpack characters
117 buffer -- string of packed binary data
121 values -- sequence of values corresponding 1:1 to format characters
122 rest -- string containing data that was not decoded, or '' if the
123 whole string was consumed
126 IndexError -- if there is insufficient data in the buffer for the
127 format (or if the data is corrupt and contains a variable-length
128 field extending past the end)
129 ValueError -- if any of the format characters is illegal
132 Because unconsumed data is returned, you can feed it back in to the
133 unpacker to extract further fields. Alternatively, if you wish to modify
134 some fields near the start of the data, you may be able to save time by
135 only unpacking and repacking the necessary part.
141 Game plan is to first of all walk through the arguments and calculate the
142 total length that will be required. We allocate a Python string of that
143 size, then walk through again and fill it in.
145 We just borrow references to all the passed arguments, since none of them
146 need to be permanently stored. We transfer ownership to the returned
150 pytdbpack_pack(PyObject *self,
154 PyObject *val_seq, *fast_seq, *buf_str;
158 /* TODO: Test passing wrong types or too many arguments */
159 if (!PyArg_ParseTuple(args, "sO", &format_str, &val_seq))
162 /* Convert into a list or tuple (if not already one), so that we can
163 * index more easily. */
164 fast_seq = PySequence_Fast(val_seq,
165 __FUNCTION__ ": argument 2 must be sequence");
169 reqd_len = pytdbpack_calc_reqd_len(format_str, fast_seq);
170 if (reqd_len == -1) /* exception was thrown */
175 This design causes an unnecessary copying of the data when Python
176 constructs an object, and that might possibly be avoided by using a
177 Buffer object of some kind instead. I'm not doing that for now
179 packed_buf = malloc(reqd_len);
181 PyErr_Format(PyExc_MemoryError,
182 "%s: couldn't allocate %d bytes for packed buffer",
183 __FUNCTION__, reqd_len);
187 if (!pytdbpack_pack_data(format_str, fast_seq, packed_buf)) {
192 buf_str = PyString_FromStringAndSize(packed_buf, reqd_len);
193 free(packed_buf); /* get rid of tmp buf */
201 pytdbpack_unpack(PyObject *self,
204 char *format_str, *packed_str, *ppacked;
205 PyObject *val_list = NULL, *ret_tuple = NULL;
206 PyObject *rest_string = NULL;
207 int format_len, packed_len;
209 char last_format = '#';
212 if (!PyArg_ParseTuple(args, "ss#", &format_str, &packed_str, &packed_len))
215 format_len = strlen(format_str);
217 /* allocate list to hold results */
218 val_list = PyList_New(format_len);
221 ret_tuple = PyTuple_New(2);
225 /* For every object, unpack. */
226 for (ppacked = packed_str, i = 0; i < format_len; i++) {
230 format = format_str[i];
233 PyErr_Format(PyExc_ValueError,
234 "%s: '$' may not be first character in format",
239 format = last_format; /* repeat */
243 val_obj = pytdbpack_unpack_item(format,
249 PyList_SET_ITEM(val_list, i, val_obj);
250 last_format = format;
253 /* put leftovers in box for lunch tomorrow */
254 rest_string = PyString_FromStringAndSize(ppacked, packed_len);
258 /* return (values, rest) tuple; give up references to them */
259 PyTuple_SET_ITEM(ret_tuple, 0, val_list);
261 PyTuple_SET_ITEM(ret_tuple, 1, rest_string);
266 /* handle failure: deallocate anything */
267 Py_XDECREF(val_list);
268 Py_XDECREF(ret_tuple);
269 Py_XDECREF(rest_string);
275 Internal routine that calculates how many bytes will be required to
276 encode the values in the format.
278 Also checks that the value list is the right size for the format list.
280 Returns number of bytes (may be 0), or -1 if there's something wrong, in
281 which case a Python exception has been raised.
285 val_seq: a Fast Sequence (list or tuple), being all the values
288 pytdbpack_calc_reqd_len(char *format_str,
296 val_len = PySequence_Fast_GET_SIZE(val_seq);
298 for (p = format_str, val_i = 0; *p; p++, val_i++) {
303 if (val_i >= val_len) {
304 PyErr_Format(PyExc_IndexError,
305 "samba.tdbpack.pack: value list is too short for format string");
309 /* borrow a reference to the item */
310 val_obj = PySequence_Fast_GET_ITEM(val_seq, val_i);
314 item_len = pytdbpack_calc_item_len(ch, val_obj);
321 if (val_i != val_len) {
322 PyErr_Format(PyExc_IndexError,
323 "%s: value list is wrong length for format string",
332 static PyObject *pytdbpack_bad_type(char ch,
333 const char *expected,
336 PyObject *r = PyObject_Repr(val_obj);
339 PyErr_Format(PyExc_TypeError,
340 "tdbpack: format '%c' requires %s, not %s",
341 ch, expected, PyString_AS_STRING(r));
348 * Calculate the number of bytes required to pack a single value. While doing
349 * this, also conduct some initial checks that the argument types are
352 * Returns -1 on exception.
355 pytdbpack_calc_item_len(char ch,
358 if (ch == 'd' || ch == 'w') {
359 if (!PyInt_Check(val_obj)) {
360 pytdbpack_bad_type(ch, "Int", val_obj);
367 } else if (ch == 'p') {
370 else if (ch == 'f' || ch == 'P' || ch == 'B') {
371 /* nul-terminated 8-bit string */
372 if (!PyString_Check(val_obj)) {
373 pytdbpack_bad_type(ch, "String", val_obj);
377 /* byte buffer; just use Python string's length, plus
379 return 4 + PyString_GET_SIZE(val_obj);
382 /* one nul character */
383 return 1 + PyString_GET_SIZE(val_obj);
387 PyErr_Format(PyExc_ValueError,
388 "tdbpack: format character '%c' is not supported",
397 XXX: glib and Samba have quicker macro for doing the endianness conversions,
398 but I don't know of one in plain libc, and it's probably not a big deal. I
399 realize this is kind of dumb because we'll almost always be on x86, but
400 being safe is important.
402 static void pack_int32(unsigned long val_long, unsigned char **pbuf)
404 (*pbuf)[0] = val_long & 0xff;
405 (*pbuf)[1] = (val_long >> 8) & 0xff;
406 (*pbuf)[2] = (val_long >> 16) & 0xff;
407 (*pbuf)[3] = (val_long >> 24) & 0xff;
412 static void pack_bytes(long len, const char *from,
413 unsigned char **pbuf)
415 memcpy(*pbuf, from, len);
421 unpack_err_too_short(void)
423 PyErr_Format(PyExc_IndexError,
424 __FUNCTION__ ": data too short for unpack format");
429 unpack_int32(char **pbuf, int *plen)
435 unpack_err_too_short();
440 v = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
445 return PyInt_FromLong(v);
449 static PyObject *unpack_int16(char **pbuf, int *plen)
455 unpack_err_too_short();
465 return PyInt_FromLong(v);
470 unpack_string(char **pbuf, int *plen)
473 char *nul_ptr, *start;
477 nul_ptr = memchr(start, '\0', *plen);
479 unpack_err_too_short();
483 len = nul_ptr - start;
485 *pbuf += len + 1; /* skip \0 */
488 return PyString_FromStringAndSize(start, len);
493 unpack_buffer(char **pbuf, int *plen)
495 /* first get 32-bit len */
498 unsigned char *start;
501 unpack_err_too_short();
506 slen = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
508 if (slen < 0) { /* surely you jest */
509 PyErr_Format(PyExc_ValueError,
510 __FUNCTION__ ": buffer seems to have negative length");
519 PyErr_Format(PyExc_IndexError,
520 __FUNCTION__ ": not enough data to unpack buffer: "
521 "need %d bytes, have %d",
529 return PyString_FromStringAndSize(start, slen);
533 /* Unpack a single field from packed data, according to format character CH.
534 Remaining data is at *PBUF, of *PLEN.
536 *PBUF is advanced, and *PLEN reduced to reflect the amount of data that has
539 Returns a reference to the unpacked Python object, or NULL for failure.
541 static PyObject *pytdbpack_unpack_item(char ch,
545 if (ch == 'w') { /* 16-bit int */
546 return unpack_int16(pbuf, plen);
548 else if (ch == 'd' || ch == 'p') { /* 32-bit int */
549 /* pointers can just come through as integers */
550 return unpack_int32(pbuf, plen);
552 else if (ch == 'f' || ch == 'P') { /* nul-term string */
553 return unpack_string(pbuf, plen);
555 else if (ch == 'B') { /* length, buffer */
556 return unpack_buffer(pbuf, plen);
559 PyErr_Format(PyExc_ValueError,
560 __FUNCTION__ ": format character '%c' is not supported",
570 Pack a single item VAL_OBJ, encoded using format CH, into a buffer at *PBUF,
571 and advance the pointer. Buffer length has been pre-calculated so we are
572 sure that there is enough space.
576 pytdbpack_pack_item(char ch,
578 unsigned char **pbuf)
581 unsigned long val_long = PyInt_AsLong(val_obj);
582 (*pbuf)[0] = val_long & 0xff;
583 (*pbuf)[1] = (val_long >> 8) & 0xff;
586 else if (ch == 'd') {
587 /* 4-byte LE number */
588 pack_int32(PyInt_AsLong(val_obj), pbuf);
590 else if (ch == 'p') {
591 /* "Pointer" value -- in the subset of DCERPC used by Samba,
592 this is really just an "exists" or "does not exist"
594 pack_int32(PyObject_IsTrue(val_obj), pbuf);
596 else if (ch == 'f' || ch == 'P') {
600 size = PyString_GET_SIZE(val_obj);
601 sval = PyString_AS_STRING(val_obj);
602 pack_bytes(size+1, sval, pbuf); /* include nul */
604 else if (ch == 'B') {
608 size = PyString_GET_SIZE(val_obj);
609 pack_int32(size, pbuf);
610 sval = PyString_AS_STRING(val_obj);
611 pack_bytes(size, sval, pbuf); /* do not include nul */
614 /* this ought to be caught while calculating the length, but
616 PyErr_Format(PyExc_ValueError,
617 "%s: format character '%c' is not supported",
628 Pack data according to FORMAT_STR from the elements of VAL_SEQ into
631 The string has already been checked out, so we know that VAL_SEQ is large
632 enough to hold the packed data, and that there are enough value items.
633 (However, their types may not have been thoroughly checked yet.)
635 In addition, val_seq is a Python Fast sequence.
637 Returns NULL for error (with exception set), or None.
640 pytdbpack_pack_data(const char *format_str,
642 unsigned char *packed_buf)
646 for (i = 0; format_str[i]; i++) {
647 char ch = format_str[i];
650 /* borrow a reference to the item */
651 val_obj = PySequence_Fast_GET_ITEM(val_seq, i);
655 if (!pytdbpack_pack_item(ch, val_obj, &packed_buf))
666 static PyMethodDef pytdbpack_methods[] = {
667 { "pack", pytdbpack_pack, METH_VARARGS, (char *) pytdbpack_pack_doc },
668 { "unpack", pytdbpack_unpack, METH_VARARGS, (char *) pytdbpack_unpack_doc },
674 Py_InitModule3("tdbpack", pytdbpack_methods,
675 (char *) pytdbpack_docstring);