wirebin/wbin.c

1031 lines
23 KiB
C

/*
* Copyright (c) 2005-2010 Slide, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the author nor the names of other
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <Python.h>
#include <unicodeobject.h>
#include <netinet/in.h>
#if defined(__linux__)
#include <byteswap.h>
#include <endian.h>
#endif
PyDoc_STRVAR(wbin_module_documentation,
"Provide encoding and decoding functions for a speed/CPU "
"optimized\n binary string representation of basic python "
"types.\n");
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define INIT_BUFFER_LEN 0x1000
#define DEFAULT_MAX_DEPTH 0x1000
#define DEFAULT_MAX_RUN 0x8000
struct serial_buffer {
/*
* buffer/position/length information
*/
char *buf;
int off;
int len;
/*
* yield function/period/last information
*/
PyObject *func;
PyObject *args;
int size;
int last;
};
#define TYPE_NULL 0x0
#define TYPE_INT 0x1
#define TYPE_STRING 0x2
#define TYPE_LIST 0x4
#define TYPE_DICT 0x5
#define TYPE_LONG 0x6
#define TYPE_UTF8 0x7
#define TYPE_DOUBLE 0x8
#define TYPE_TUPLE 0x9
#define TYPE_LONGER 0xA
#define TYPE_PICKLE 0xB
#define TYPE_CMD 666
#define TYPE_RESPONSE 667
#define TYPE_PUSH 668
#if defined(__linux__)
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define htonll(x) bswap_64(x)
#define ntohll(x) bswap_64(x)
#else
#define htonll(x) (x)
#define ntohll(x) (x)
#endif
#endif
#if defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define htonll(x) OSSwapHostToBigInt64(x)
#define ntohll(x) OSSwapBigToHostInt64(x)
#endif
#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION == 4
typedef int Py_ssize_t ;
#endif
static PyObject *cpickle_str;
static PyObject *cploads_str;
static PyObject *cpdumps_str;
static PyObject *empty_tuple;
static PyObject *cpick = NULL;
static int utf8_support = 1;
static int wls_on = 1;
static int max_depth = DEFAULT_MAX_DEPTH;
struct whitelist_entry {
PyObject *mod;
PyObject *cls;
char *mname;
char *cname;
};
static struct whitelist_entry whitelist[] = {
{NULL, NULL, "decimal", "Decimal"},
{NULL, NULL, NULL, NULL}
};
static int _check_space(struct serial_buffer *buffer, int space)
{
if ((buffer->len - buffer->off) < space) {
PyErr_Format(PyExc_SystemError,
"insufficient data <%d> at <%d> of <%d>",
space, buffer->off, buffer->len);
return -EINVAL;
}
return 0;
}
#ifdef USED_SOMEWHERE
static int _check_encode(char *str, int size)
{
int i;
for (i = 0; i < size/4; i++)
if (0x80808080 & ((unsigned int *)str)[i])
return 1;
for (i *= 4; i < size; i++)
if (0x80 & str[i])
return 1;
return 0;
}
#endif
static int _check_yield(struct serial_buffer *b)
{
PyObject *result = NULL;
PyObject *args;
int i = 0;
if ((b->off - b->last) < b->size)
return 0;
/*
* allocate call argument tuple of size N + 1. Where N
* is the size of the user supplied tuple, the extra slot
* contains the current offset as feedback for the user.
*/
args = PyTuple_New(PyTuple_GET_SIZE(b->args) + 1);
/*
* Place the current offset into slot 0, the single reference
* to the new integer object will be decremented when the arg
* tuple is dereferenced and deallocated.
*/
PyTuple_SET_ITEM(args, i++, PyInt_FromLong(b->off));
/*
* Link the objects in the user supplied arguments tuple into
* the new tuple. Do not incremenet the reference count since
* after the call we NULL out the entries w/o a decrement.
*/
for (; i < PyTuple_GET_SIZE(args); i++)
PyTuple_SET_ITEM(args, i, PyTuple_GET_ITEM(b->args, i-1));
/*
* call user supplied callback
*/
result = PyObject_Call(b->func, args, NULL);
/*
* NULL out the entries for the user supplied arguments, and
* derefernce the local arguments tuple.
*/
for (i = 1; i < PyTuple_GET_SIZE(args); i++)
PyTuple_SET_ITEM(args, i, NULL);
Py_DECREF(args);
/*
* process result
*/
if (!result)
return -EINVAL;
Py_DECREF(result);
b->last = b->off;
return 0;
}
static void _deserialize_error(struct serial_buffer *b)
{
/*
* check if the current error is a memory error and include
* information about our buffer.
*/
if (PyErr_Occurred() != PyExc_MemoryError)
return;
PyErr_Format(PyExc_MemoryError,
"allocation failure. length <%d> offset <%d>",
b->len, b->off);
return;
}
static int _get_size(struct serial_buffer *b)
{
int size;
if (_check_space(b, sizeof(uint32_t))) {
PyErr_Format(PyExc_MemoryError,
"no size available at <%d> of <%d>",
b->off, b->len);
return -1;
}
size = ntohl(*(uint32_t *)(b->buf + b->off));
b->off += sizeof(uint32_t);
if (size > (b->len - b->off)) {
PyErr_Format(PyExc_MemoryError,
"Unreasonable element size <%d> at offset <%ld>",
size, b->off - sizeof(uint32_t));
return -1;
}
return size;
}
static PyObject *_deserialize_object(struct serial_buffer *b)
{
PyObject *output = NULL;
PyObject *loads;
PyObject *value;
int result = 0;
int size;
size = _get_size(b);
if (0 > size)
goto err_load;
result = _check_space(b, size);
if (result)
goto err_load;
loads = PyObject_GetAttr(cpick, cploads_str);
if (!loads)
goto err_load;
value = PyString_FromStringAndSize((b->buf + b->off), size);
if (!value)
goto err_data;
b->off += size;
output = PyObject_CallFunction(loads, "O", value);
Py_DECREF(value);
err_data:
Py_DECREF(loads);
err_load:
return output;
}
static PyObject *_deserialize(struct serial_buffer *b, int intern)
{
PyObject *output = NULL;
PyObject *value;
PyObject *key;
char error_str[128];
int result;
int type;
int size;
int i;
if (!b) {
PyErr_SetString(PyExc_SystemError, "missing buffer object");
return NULL;
}
if (b->func) {
if (_check_yield(b))
return NULL;
}
result = _check_space(b, sizeof(uint16_t));
if (result)
return NULL;
type = ntohs(*(uint16_t *)(b->buf + b->off));
b->off += sizeof(uint16_t);
switch (type) {
case TYPE_INT:
result = _check_space(b, sizeof(uint32_t));
if (result)
break;
output = PyInt_FromLong((int32_t)ntohl(*(uint32_t *)(b->buf + b->off)));
b->off += sizeof(uint32_t);
break;
case TYPE_LONG:
result = _check_space(b, sizeof(uint64_t));
if (result)
break;
#if !defined(__APPLE__)
output = PyInt_FromLong(ntohll(*(uint64_t *)(b->buf + b->off)));
#else
output = PyLong_FromLongLong(ntohll(*(uint64_t *)(b->buf + b->off)));
#endif
b->off += sizeof(uint64_t);
break;
case TYPE_LONGER:
size = _get_size(b);
if (0 > size)
break;
result = _check_space(b, size);
if (result)
break;
output = _PyLong_FromByteArray(
(unsigned char *)(b->buf + b->off), size, 0, 1);
b->off += size;
break;
case TYPE_DOUBLE:
result = _check_space(b, sizeof(double));
if (result)
break;
output = PyFloat_FromDouble(*(double *)(b->buf + b->off));
b->off += sizeof(double);
break;
case TYPE_STRING:
size = _get_size(b);
if (0 > size)
break;
result = _check_space(b, size);
if (result)
break;
output = PyString_FromStringAndSize((b->buf + b->off), size);
if (intern)
PyString_InternInPlace(&output);
b->off += size;
break;
case TYPE_UTF8:
size = _get_size(b);
if (0 > size)
break;
result = _check_space(b, size);
if (result)
break;
output = PyUnicode_DecodeUTF8((b->buf + b->off), size, "strict");
b->off += size;
break;
case TYPE_LIST:
size = _get_size(b);
if (0 > size)
break;
output = PyList_New(size);
if (!output)
break;
for (i = 0; i < size; i++) {
value = _deserialize(b, 0);
if (!value)
break;
result = PyList_SetItem(output, i, value);
if (result)
/*
* SetItem decrements value refcnt on error
* and does not increase it on success.
*/
break;
}
if (size > i) {
Py_DECREF(output);
output = NULL;
}
break;
case TYPE_DICT:
size = _get_size(b);
if (0 > size)
break;
output = PyDict_New();
if (!output)
break;
while (size) {
key = _deserialize(b, 1);
if (!key)
break;
value = _deserialize(b, 0);
if (!value) {
Py_DECREF(key);
break;
}
result = PyDict_SetItem(output, key, value);
Py_DECREF(value);
Py_DECREF(key);
if (result)
break;
size--;
}
if (size > 0) {
Py_DECREF(output);
output = NULL;
}
break;
case TYPE_TUPLE:
size = _get_size(b);
if (0 > size)
break;
output = PyTuple_New(size);
if (!output)
break;
for (i = 0; i < size; i++) {
value = _deserialize(b, 0);
if (!value)
break;
result = PyTuple_SetItem(output, i, value);
if (result)
/*
* SetItem decrements value refcnt on error
* and does not increase it on success.
*/
break;
}
if (size > i) {
Py_DECREF(output);
output = NULL;
}
break;
case TYPE_NULL:
Py_INCREF(Py_None);
output = Py_None;
break;
case TYPE_PICKLE:
output = _deserialize_object(b);
break;
default:
sprintf(error_str, "Unhandled type: <%d>", type);
PyErr_SetString(PyExc_TypeError, error_str);
break;
}
return output;
}
static int _check_size(struct serial_buffer *buffer, int size)
{
char *new;
while ((buffer->len - buffer->off) < (size + sizeof(uint16_t))) {
new = realloc(buffer->buf, (buffer->len * 2));
if (!new) {
PyErr_Format(PyExc_MemoryError,
"failed to reallocate buffer to <%d>",
buffer->len * 2);
return -ENOMEM;
}
buffer->buf = new;
buffer->len = buffer->len * 2;
}
return 0;
}
static int _copy_string
(
struct serial_buffer *b,
const char *input_string,
int input_size,
short type
)
{
int result;
result = _check_size(b, input_size + sizeof(uint32_t));
if (result)
return result;
*(uint16_t *)(b->buf + b->off) = htons(type);
b->off += sizeof(uint16_t);
*(uint32_t *)(b->buf + b->off) = htonl(input_size);
b->off += sizeof(uint32_t);
memcpy((b->buf + b->off), input_string, input_size);
b->off += input_size;
return 0;
}
static int _check_whitelist(PyObject *input)
{
struct whitelist_entry *entry;
if (!wls_on)
return 0;
for (entry = whitelist; entry->cls; entry++) {
if (PyObject_IsInstance(input, entry->cls))
return 0;
}
return -EINVAL;
}
static int _serialize_object(PyObject *input, struct serial_buffer *b, int dp)
{
char error_str[128];
PyObject *dumps;
PyObject *value;
int result = 0;
if (_check_whitelist(input)) {
sprintf(error_str, "Unlisted type: <%s>",
input->ob_type->tp_name);
PyErr_SetString(PyExc_TypeError, error_str);
result = -EINVAL;
goto err_dump;
}
dumps = PyObject_GetAttr(cpick, cpdumps_str);
if (!dumps) {
result = -EINVAL;
goto err_dump;
}
value = PyObject_CallFunction(dumps, "O", input);
if (!value) {
result = -EINVAL;
goto err_call;
}
result = _copy_string(b,
PyString_AS_STRING(value),
PyString_GET_SIZE(value),
TYPE_PICKLE);
Py_DECREF(value);
err_call:
Py_DECREF(dumps);
err_dump:
return result;
}
static int _serialize(PyObject *input, struct serial_buffer *b, int dp)
{
char error_str[128];
PyObject *value;
PyObject *key;
long i;
long long item;
int result;
if (max_depth < dp++) {
PyErr_Format(PyExc_SystemError,
"max recursion depth <%d> exceeded", max_depth);
return -EINVAL;
}
if (!input) {
PyErr_SetString(PyExc_SystemError, "missing input object");
return -EINVAL;
}
if (!b) {
PyErr_SetString(PyExc_SystemError, "missing buffer object");
return -EINVAL;
}
if (b->func) {
result = _check_yield(b);
if (result)
return result;
}
if (PyInt_Check(input)) {
item = PyInt_AS_LONG(input);
if (item > INT_MAX || item < INT_MIN) {
result = _check_size(b, sizeof(uint64_t));
if (result)
return result;
*(uint16_t *)(b->buf + b->off) = htons(TYPE_LONG);
b->off += sizeof(uint16_t);
*(uint64_t *)(b->buf + b->off) = htonll(item);
b->off += sizeof(uint64_t);
goto done;
}
else {
result = _check_size(b, sizeof(uint32_t));
if (result)
return result;
*(uint16_t *)(b->buf + b->off) = htons(TYPE_INT);
b->off += sizeof(uint16_t);
*(uint32_t *)(b->buf + b->off) = htonl(item);
b->off += sizeof(uint32_t);
goto done;
}
}
if (PyLong_Check(input)) {
item = PyLong_AsLongLong(input);
if (item == -1 && PyErr_Occurred()) {
PyErr_Clear();
i = _PyLong_NumBits(input) + 1; /* include sign bit */
i = i/8 + MIN(i%8, 1); /* byte count rounded up */
result = _check_size(b, sizeof(uint32_t) + i);
if (result)
return result;
*(uint16_t *)(b->buf + b->off) = htons(TYPE_LONGER);
b->off += sizeof(uint16_t);
*(uint32_t *)(b->buf + b->off) = htonl(i);
b->off += sizeof(uint32_t);
result = _PyLong_AsByteArray(
(PyLongObject *)input,
(unsigned char *)(b->buf + b->off),
(size_t)i, 0, 1);
if (result)
return result;
b->off += i;
goto done;
}
else {
result = _check_size(b, sizeof(uint64_t));
if (result)
return result;
*(uint16_t *)(b->buf + b->off) = htons(TYPE_LONG);
b->off += sizeof(uint16_t);
*(uint64_t *)(b->buf + b->off) = htonll(item);
b->off += sizeof(uint64_t);
goto done;
}
}
if (PyString_Check(input)) {
result = _copy_string(b,
PyString_AS_STRING(input),
PyString_GET_SIZE(input),
TYPE_STRING);
if (result)
return result;
goto done;
}
if (PyUnicode_Check(input)) {
value = PyUnicode_AsUTF8String(input);
if (!value)
return -EINVAL;
result = _copy_string(b,
PyString_AS_STRING(value),
PyString_GET_SIZE(value),
utf8_support ? TYPE_UTF8 : TYPE_STRING);
Py_DECREF(value);
if (result)
return result;
goto done;
}
if (PyList_Check(input)) {
result = _check_size(b, sizeof(uint32_t));
if (result)
return result;
*(uint16_t *)(b->buf + b->off) = htons(TYPE_LIST);
b->off += sizeof(uint16_t);
*(uint32_t *)(b->buf + b->off) = htonl(PyList_GET_SIZE(input));
b->off += sizeof(uint32_t);
for (i = 0; i < PyList_GET_SIZE(input); i++) {
result = _serialize(PyList_GET_ITEM(input, i), b, dp);
if (result)
return result;
}
goto done;
}
if (PyDict_Check(input)) {
Py_ssize_t j = 0;
result = _check_size(b, sizeof(uint32_t));
if (result)
return result;
*(uint16_t *)(b->buf + b->off) = htons(TYPE_DICT);
b->off += sizeof(uint16_t);
*(uint32_t *)(b->buf + b->off) = htonl(PyDict_Size(input));
b->off += sizeof(uint32_t);
while (PyDict_Next(input, &j, &key, &value)) {
result = _serialize(key, b, dp);
if (result)
return result;
result = _serialize(value, b, dp);
if (result)
return result;
}
goto done;
}
if (Py_None == input) {
result = _check_size(b, 0);
if (result)
return result;
*(uint16_t *)(b->buf + b->off) = htons(TYPE_NULL);
b->off += sizeof(uint16_t);
goto done;
}
if (PyFloat_Check(input)) {
result = _check_size(b, sizeof(double));
if (result)
return result;
*(uint16_t *)(b->buf + b->off) = htons(TYPE_DOUBLE);
b->off += sizeof(uint16_t);
*(double *)(b->buf + b->off) = PyFloat_AS_DOUBLE(input);
b->off += sizeof(double);
goto done;
}
if (PyTuple_Check(input)) {
result = _check_size(b, sizeof(uint32_t));
if (result)
return result;
*(uint16_t *)(b->buf + b->off) = htons(TYPE_TUPLE);
b->off += sizeof(uint16_t);
*(uint32_t *)(b->buf + b->off) = htonl(PyTuple_GET_SIZE(input));
b->off += sizeof(uint32_t);
for (i = 0; i < PyTuple_GET_SIZE(input); i++) {
result = _serialize(PyTuple_GET_ITEM(input, i), b, dp);
if (result)
return result;
}
goto done;
}
if (cpick) {
result = _serialize_object(input, b, dp);
if (result)
return result;
goto done;
}
sprintf(error_str, "Unhandled type: <%s>",
input->ob_type->tp_name);
PyErr_SetString(PyExc_TypeError, error_str);
return -EINVAL;
done:
return 0;
}
static PyObject *py_serialize(PyObject *self, PyObject *args)
{
struct serial_buffer buffer;
PyObject *input;
PyObject *output;
PyObject *yield = NULL;
PyObject *yargs = empty_tuple;
int length = DEFAULT_MAX_RUN;
int result;
result = PyArg_ParseTuple(args, "O|OO!i",
&input, &yield,
&PyTuple_Type, &yargs,
&length);
if (!result)
return NULL;
if (yield && !PyCallable_Check(yield)) {
PyErr_Format(PyExc_TypeError,
"'%s' object not callable",
yield->ob_type->tp_name);
return NULL;
}
buffer.len = INIT_BUFFER_LEN;
buffer.off = 0;
buffer.buf = malloc(buffer.len);
buffer.func = yield;
buffer.size = length;
buffer.last = 0;
buffer.args = yargs;
if (!buffer.buf) {
PyErr_Format(PyExc_MemoryError,
"failed to allocate buffer <%d>", buffer.len);
return NULL;
}
result = _serialize(input, &buffer, 0);
if (result)
output = NULL;
else
output = PyString_FromStringAndSize(buffer.buf, buffer.off);
free(buffer.buf);
return output;
}
static PyObject *py_deserialize(PyObject *self, PyObject *args)
{
struct serial_buffer buffer;
PyObject *output;
PyObject *input;
PyObject *yield = NULL;
PyObject *yargs = empty_tuple;
int length = DEFAULT_MAX_RUN;
int result;
result = PyArg_ParseTuple(args, "O!|OO!i",
&PyString_Type, (PyObject *)&input, &yield,
&PyTuple_Type, &yargs,
&length);
if (!result)
return NULL;
if (yield && !PyCallable_Check(yield)) {
PyErr_Format(PyExc_TypeError,
"'%s' object not callable",
yield->ob_type->tp_name);
return NULL;
}
buffer.len = PyString_GET_SIZE(input);
buffer.off = 0;
buffer.buf = PyString_AS_STRING(input);
buffer.func = yield;
buffer.size = length;
buffer.last = 0;
buffer.args = yargs;
output = _deserialize(&buffer, 0);
if (!output)
_deserialize_error(&buffer);
return output;
}
static PyObject *utf8_enable(PyObject *self, PyObject *noargs)
{
utf8_support = 1;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *utf8_disable(PyObject *self, PyObject *noargs)
{
utf8_support = 0;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *utf8_enabled(PyObject *self, PyObject *noargs)
{
return PyBool_FromLong((long)utf8_support);
}
static PyObject *wls_enable(PyObject *self, PyObject *noargs)
{
wls_on = 1;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *wls_disable(PyObject *self, PyObject *noargs)
{
wls_on = 0;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *wls_enabled(PyObject *self, PyObject *noargs)
{
return PyBool_FromLong((long)wls_on);
}
static PyObject *echo_maxint(PyObject *self, PyObject *noargs)
{
return PyInt_FromLong(LONG_MAX);
}
static PyObject *echo_minint(PyObject *self, PyObject *noargs)
{
return PyInt_FromLong(LONG_MIN);
}
static PyMethodDef _bin_methods[] = {
{"serialize", py_serialize, METH_VARARGS,
PyDoc_STR("serialize(object[, callback[, args[, frequency]]]) -> "
"string.\n\nGiven a python object encode it into a "
"python string. An optional\ncallback(offset[,args]) "
"will be periodically called with number of\nbytes so"
"far encoded as the first parameter. The remaining "
"optional\nparameters to the callback are supplied as "
"an optional args parameter\nto the serialize function."
" Finally an optional frequency parameter\ndetermines "
"approximately how many bytes are encoded between each "
"call\nto the callback function. (default 8K)\n")},
{"deserialize", py_deserialize, METH_VARARGS,
PyDoc_STR("deserialize(object[, callback[, args[, frequency]]]) -> "
"string.\n\nGiven a python string decode it into a "
"python object. An optional\ncallback(offset[,args]) "
"will be periodically called with number of\nbytes so"
"far encoded as the first parameter. The remaining "
"optional\nparameters to the callback are supplied as "
"an optional args parameter\nto the serialize function."
" Finally an optional frequency parameter\ndetermines "
"approximately how many bytes are encoded between each "
"call\nto the callback function. (default 8K)\n")},
{"utf8_enable", utf8_enable, METH_NOARGS,
"utf8_enable() -> None\n\nEnable UTF8 encoding support\n"},
{"utf8_disable", utf8_disable, METH_NOARGS,
"utf8_disable() -> None\n\nDisable UTF8 encoding support\n"},
{"utf8_enabled", utf8_enabled, METH_NOARGS,
"utf8_enabled() -> status\n\nReturns True if UTF8 encoding is enable\n"},
{"wls_on", wls_enable, METH_NOARGS,
"wls_on() -> None\n\nEnable encodable object whitelist (default)\n"},
{"wls_off", wls_disable, METH_NOARGS,
"wls_off() -> None\n\nDisable encodable object whitelist (attempt to encode all objects)\n"},
{"wls_status", wls_enabled, METH_NOARGS,
"wls_status() -> status\n\nReturns encodable object whitelist status\n"},
{"min_int", echo_minint, METH_NOARGS,
"min_int() -> int\n\nReturns smallest integer that can be encoded\n"},
{"max_int", echo_maxint, METH_NOARGS,
"max_int() -> int\n\nReturns largest integer that can be encoded\n"},
{NULL, NULL, 0, NULL}
};
#define INIT_STR(s, n) if (!(s = PyString_InternFromString(n))) return;
PyMODINIT_FUNC initwbin(void)
{
struct whitelist_entry *entry;
PyObject *name;
(void)Py_InitModule3("wbin", _bin_methods, wbin_module_documentation);
/*
* empty tuple for default arguments to yield function
*/
empty_tuple = PyTuple_New(0);
if (!empty_tuple)
return;
/*
* attempt an import of cPickle which, if available, can be used
* as a fallback for complex objects. error is not checked here,
* the failure will occur when a compex object is encountered.
*/
INIT_STR(cpickle_str, "cPickle");
INIT_STR(cploads_str, "loads");
INIT_STR(cpdumps_str, "dumps");
cpick = PyImport_Import(cpickle_str);
/*
* import classes for cpickle white list.
*/
for (entry = whitelist; entry->mname; entry++) {
name = PyString_InternFromString(entry->mname);
if (!name)
return;
entry->mod = PyImport_Import(name);
if (!entry->mod)
return;
name = PyString_InternFromString(entry->cname);
if (!name)
return;
entry->cls = PyObject_GetAttr(entry->mod, name);
if (!entry->cls)
return;
}
}
/*
* Local Variables:
* c-file-style: "linux"
* indent-tabs-mode: t
* End:
*/