#ifdef WIN32
# include <windows.h>
# define EXTERN_API __declspec(dllexport)
# define snprintf _snprintf
#else
# define EXTERN_API
#endif
#ifdef __GNUC__
# define TM_INLINE inline
#else
# define TM_INLINE
#endif
#include <sys/types.h>
#include <Python.h>
PyObject* cBanana_module;
PyObject* cBanana_dict;
EXTERN_API void initcBanana(void);
extern EXTERN_API PyObject *cBanana_encode( PyObject *self, PyObject *args );
extern EXTERN_API PyObject *cBanana_dataReceived( PyObject *self, PyObject *args );
extern EXTERN_API PyObject *cBananaState_new( PyObject *self, PyObject *args );
extern EXTERN_API void cBananaState_dealloc(PyObject* self);
extern EXTERN_API PyObject *cBananaBuf_new( PyObject *self, PyObject *args );
extern EXTERN_API void cBananaBuf_dealloc(PyObject* self);
extern EXTERN_API PyObject *cBananaBuf_getattr(PyObject* self, char* attrname);
extern EXTERN_API PyObject *cBananaBuf_write( PyObject *self, PyObject *args );
extern EXTERN_API PyObject *cBananaBuf_get( PyObject *self, PyObject *args );
extern EXTERN_API PyObject *cBananaBuf_clear( PyObject *self, PyObject *args );
static PyMethodDef cBanana__methods__[] =
{
{ "dataReceived", cBanana_dataReceived, METH_VARARGS },
{ "encode", cBanana_encode, METH_VARARGS },
{ "newState", cBananaState_new, METH_VARARGS },
{ "newBuf", cBananaBuf_new, METH_VARARGS },
{ NULL, NULL }
};
static PyMethodDef cBananaBuf__methods__[] =
{
{ "write", cBananaBuf_write, METH_VARARGS },
{ "clear", cBananaBuf_clear, METH_VARARGS },
{ "get", cBananaBuf_get, METH_VARARGS },
{ NULL, NULL }
};
static PyObject *BananaError;
#define HIGH_BIT_SET 0x80
#define LIST 0x80
#define INT 0x81
#define STRING 0x82
#define NEG 0x83
#define FLOAT 0x84
#define LONGINT 0x85
#define LONGNEG 0x86
#define VOCAB 0x87
#define NUM_VOCABS 31
struct listItem
{
struct listItem *lastList;
PyObject *thisList;
int currentIndex;
int size;
};
typedef struct {
PyObject_HEAD
struct listItem *currentList;
} cBananaState;
static PyTypeObject cBananaStateType = {
PyObject_HEAD_INIT(NULL)
0,
"cBananaState",
sizeof(cBananaState),
0,
cBananaState_dealloc,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
typedef struct {
PyObject_HEAD
char* contents;
unsigned int available;
unsigned int size;
} cBananaBuf;
static PyTypeObject cBananaBufType = {
PyObject_HEAD_INIT(NULL)
0,
"cBananaBuf",
sizeof(cBananaBuf),
0,
cBananaBuf_dealloc,
0,
cBananaBuf_getattr,
0,
0,
0,
0,
0,
0,
0,
0,
};
#define INITIAL_BUF_SZ 1024
extern EXTERN_API PyObject*
cBananaBuf_new(PyObject *self, PyObject *args) {
cBananaBuf* buf;
if (!PyArg_ParseTuple(args, ":newState")){
return NULL;
}
buf = PyObject_New(cBananaBuf, &cBananaBufType);
buf->contents = malloc(INITIAL_BUF_SZ);
buf->size = INITIAL_BUF_SZ;
buf->available = INITIAL_BUF_SZ;
return (PyObject*) buf;
}
extern EXTERN_API void
cBananaBuf_dealloc(PyObject *self) {
cBananaBuf* buf;
buf = (cBananaBuf*) self;
if (buf->contents) {
free(buf->contents);
}
buf->contents = 0;
buf->available = 0;
buf->size = 0;
PyObject_Del(self);
}
extern EXTERN_API PyObject*
cBananaBuf_getattr(PyObject *self, char* attrname) {
return Py_FindMethod(cBananaBuf__methods__, self, attrname);
}
static void cBananaBuf_write_internal(cBananaBuf* me, const char* src, unsigned int len) {
unsigned int index;
while (len > (me -> available)) {
unsigned int newsize;
newsize = me->size * 2;
me->contents = realloc(me->contents, newsize);
me->available += me->size;
me->size = newsize;
}
index = me->size - me->available;
memcpy((me->contents)+index, src, len);
me->available -= len;
}
#define cBananaBuf_append_byte(me, byte) \
do { \
if (me->available >= 1) { \
me->contents[me->size - me->available] = byte; \
me->available--; \
} else { \
cBananaBuf_write_internal(me, &byte, 1); \
} \
} while (0)
extern EXTERN_API PyObject*
cBananaBuf_write(PyObject *self, PyObject *args) {
cBananaBuf* me;
char* src;
int len;
me = (cBananaBuf*) self;
if (!PyArg_ParseTuple(args, "s#:write", &src, &len)) {
return NULL;
}
cBananaBuf_write_internal(me, src, len);
Py_INCREF(Py_None);
return Py_None;
}
static void cBananaBuf_clear_internal(cBananaBuf* me) {
me->available = me->size;
}
extern EXTERN_API PyObject*
cBananaBuf_clear(PyObject *self, PyObject *args) {
cBananaBuf* me;
me = (cBananaBuf*) self;
if (!PyArg_ParseTuple(args, ":clear")) {
return NULL;
}
cBananaBuf_clear_internal(me);
Py_INCREF(Py_None);
return Py_None;
}
extern EXTERN_API PyObject*
cBananaBuf_get(PyObject *self, PyObject *args) {
cBananaBuf* me;
me = (cBananaBuf*) self;
if (PyArg_ParseTuple(args, ":get")) {
return PyString_FromStringAndSize(me->contents, me->size - me->available);
}
return NULL;
}
extern EXTERN_API PyObject*
cBananaState_new(PyObject *self, PyObject *args) {
cBananaState* state;
if (!PyArg_ParseTuple(args, ":newState")){
return NULL;
}
state = PyObject_New(cBananaState, &cBananaStateType);
state->currentList = NULL;
return (PyObject*) state;
}
extern EXTERN_API void
cBananaState_dealloc(PyObject* self)
{
struct listItem* thatList;
struct listItem* thisList;
thisList = ((cBananaState*)self) -> currentList;
while (thisList) {
thatList = thisList->lastList;
Py_DECREF(thisList->thisList);
free(thisList);
thisList = thatList;
}
PyObject_Del(self);
}
static const char *vocab[] = {
"Dummy",
"None",
"class",
"dereference",
"reference",
"dictionary",
"function",
"instance",
"list",
"module",
"persistent",
"tuple",
"unpersistable",
"copy",
"cache",
"cached",
"remote",
"local",
"lcache",
"version",
"login",
"password",
"challenge",
"perspective",
"inperspective",
"cachemessage",
"message",
"answer",
"error",
"decref",
"decache",
"uncache"
};
static const char *findVocab(int offset)
{
if (offset < 0 || offset > NUM_VOCABS) {
return NULL;
}
return vocab[offset];
}
static void int2b128(long integer, cBananaBuf* writeobj) {
char typeByte;
if (integer == 0) {
typeByte = 0;
cBananaBuf_append_byte(writeobj, typeByte);
return;
}
while (integer) {
typeByte = (char) integer & 0x7f;
cBananaBuf_append_byte(writeobj, typeByte);
integer >>= 7;
}
}
PyObject* cBanana_encode_internal(PyObject* encodeobj, cBananaBuf* writeobj) {
char typeByte;
if (PyList_Check(encodeobj)) {
int counter;
int2b128(PyList_Size(encodeobj), writeobj);
typeByte = LIST;
cBananaBuf_append_byte(writeobj, typeByte);
for (counter=0; counter < PyList_Size(encodeobj); counter ++) {
if (!cBanana_encode_internal(PyList_GetItem(encodeobj, counter), writeobj)) {
return NULL;
}
}
} else if (PyTuple_Check(encodeobj)) {
int counter;
int2b128(PyTuple_Size(encodeobj), writeobj);
typeByte = LIST;
cBananaBuf_append_byte(writeobj, typeByte);
for (counter=0; counter < PyTuple_Size(encodeobj); counter ++) {
if (!cBanana_encode_internal(PyTuple_GetItem(encodeobj, counter), writeobj)) {
return NULL;
}
}
} else if (PyInt_Check(encodeobj)) {
long integer = PyInt_AsLong(encodeobj);
if (integer >= 0) {
int2b128(integer, writeobj);
typeByte = INT;
cBananaBuf_append_byte(writeobj, typeByte);
} else {
int2b128(-integer, writeobj);
typeByte = NEG;
cBananaBuf_append_byte(writeobj, typeByte);
}
} else if (PyLong_Check(encodeobj)) {
PyObject* result;
PyObject* argtup;
argtup = PyTuple_New(2);
Py_INCREF(encodeobj);
if (PyObject_Compare(encodeobj, PyLong_FromDouble(0.0)) == -1) {
typeByte = LONGNEG;
PyTuple_SetItem(argtup, 0, PyNumber_Negative(encodeobj));
} else {
typeByte = LONGINT;
PyTuple_SetItem(argtup, 0, encodeobj);
}
PyTuple_SetItem(argtup, 1, PyObject_GetAttrString((PyObject*) writeobj, "write"));
result = PyObject_CallObject(PyObject_GetAttrString(cBanana_module, "pyint2b128"), argtup);
Py_DECREF(argtup);
if (!result) {
return NULL;
}
Py_DECREF(result);
cBananaBuf_append_byte(writeobj, typeByte);
} else if (PyFloat_Check(encodeobj)) {
double x;
int s;
int e;
double f;
long fhi, flo;
char floatbuf[8];
x = PyFloat_AS_DOUBLE(encodeobj);
if (x < 0) {
s = 1;
x = -x;
}
else
s = 0;
f = frexp(x, &e);
if (0.5 <= f && f < 1.0) {
f *= 2.0;
e--;
}
else if (f == 0.0) {
e = 0;
}
else {
PyErr_SetString(PyExc_SystemError,
"frexp() result out of range");
return NULL;
}
if (e >= 1024) {
PyErr_SetString(PyExc_OverflowError,
"float too large to pack with d format");
return NULL;
}
else if (e < -1022) {
f = ldexp(f, 1022 + e);
e = 0;
}
else if (!(e == 0 && f == 0.0)) {
e += 1023;
f -= 1.0;
}
f *= 268435456.0;
fhi = (long) floor(f);
f -= (double)fhi;
f *= 16777216.0;
flo = (long) floor(f + 0.5);
floatbuf[0] = (s<<7) | (e>>4);
floatbuf[1] = (char) (((e&0xF)<<4) | (fhi>>24));
floatbuf[2] = (fhi>>16) & 0xFF;
floatbuf[3] = (fhi>>8) & 0xFF;
floatbuf[4] = fhi & 0xFF;
floatbuf[5] = (flo>>16) & 0xFF;
floatbuf[6] = (flo>>8) & 0xFF;
floatbuf[7] = flo & 0xFF;
typeByte = FLOAT;
cBananaBuf_append_byte(writeobj, typeByte);
cBananaBuf_write_internal(writeobj, floatbuf, sizeof(floatbuf));
} else if (PyString_Check(encodeobj)) {
int len;
char* src;
PyString_AsStringAndSize(encodeobj, &src, &len);
int2b128(len, writeobj);
typeByte = STRING;
cBananaBuf_append_byte(writeobj, typeByte);
cBananaBuf_write_internal(writeobj, src, len);
} else {
char errmsg[256];
snprintf(errmsg, 256, "Unknown Python Type: %s", encodeobj->ob_type->tp_name);
PyErr_SetString(BananaError, errmsg);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
extern EXTERN_API
PyObject* cBanana_encode(PyObject* self, PyObject *args) {
PyObject* encodeobj;
PyObject* writeobj;
if (!PyArg_ParseTuple(args, "OO", &encodeobj, &writeobj)) {
return NULL;
}
if (writeobj->ob_type != &cBananaBufType) {
PyErr_SetString(BananaError, "Encoding only accepts BananaBufs");
return NULL;
}
return cBanana_encode_internal(encodeobj, (cBananaBuf*) writeobj);
}
static long b1282int(unsigned char *str, int begin, int end) {
long result = 0;
long place = 0;
int count;
for (count=begin; count < end; count++) {
unsigned char num = str[count];
if (place) {
result = result + (num << (7 * place));
} else {
result = result + num;
}
place++;
}
return result;
}
static TM_INLINE int gotPythonItem(PyObject *object, struct listItem *currentList, PyObject *expressionReceived)
{
if (currentList) {
PyList_SET_ITEM(currentList->thisList, currentList->currentIndex, object);
currentList->currentIndex++;
return 1;
}
else {
PyObject *result;
PyObject *args;
args = PyTuple_New(1);
PyTuple_SetItem(args, 0, object);
result = PyObject_CallObject(expressionReceived, args);
if (result) {
Py_DECREF(result);
}
Py_DECREF(args);
return (int) result;
}
}
static TM_INLINE int gotItemFloat(double value, struct listItem *currentList, PyObject *expressionReceived)
{
PyObject *object = PyFloat_FromDouble(value);
return gotPythonItem(object, currentList, expressionReceived);
}
static TM_INLINE int gotItemInt(int value, struct listItem *currentList, PyObject *expressionReceived)
{
PyObject *object = PyInt_FromLong(value) ;
return gotPythonItem(object, currentList, expressionReceived);
}
static TM_INLINE int gotItemString(const char *value, int len, struct listItem *currentList, PyObject *expressionReceived)
{
PyObject *object;
object = PyString_FromStringAndSize(value, len);
return gotPythonItem(object, currentList, expressionReceived);
}
static TM_INLINE int gotItemList(PyObject *listObject, struct listItem *currentList, PyObject *expressionReceived)
{
return gotPythonItem(listObject, currentList, expressionReceived);
}
extern EXTERN_API PyObject *cBanana_dataReceived( PyObject *self, PyObject *args )
{
PyObject *newChunk;
PyObject *expressionReceived;
PyObject *stateobj;
cBananaState *state;
unsigned char *buffer;
char **bufptr;
int bufferSize;
int pos;
int nBeginPos;
int nEndPos;
unsigned char typeByte;
bufptr = (char**) &buffer;
if( !PyArg_ParseTuple( args, "OOO", &stateobj, &newChunk, &expressionReceived) )
return NULL;
if (!PyCallable_Check(expressionReceived) ) {
Py_INCREF(Py_None);
return Py_None;
}
if (!PyString_Check(newChunk)) {
printf("Second arg was not a string\n");
Py_INCREF(Py_None);
return Py_None;
}
if ((stateobj == NULL) || ((stateobj->ob_type) != (&cBananaStateType))) {
printf("state object wasn't\n");
Py_INCREF(Py_None);
return Py_None;
}
state = (cBananaState*) stateobj;
PyString_AsStringAndSize(newChunk, bufptr, &bufferSize);
pos = 0;
while (pos < bufferSize) {
nBeginPos = pos;
while (buffer[pos] < HIGH_BIT_SET) {
pos++;
if ((pos-nBeginPos) > 64) {
PyErr_SetString(PyExc_SystemError,
"Security precaution: more than 64 bytes of prefix (this should raise an exception).\n");
return NULL;
} else if (pos == bufferSize) {
return PyInt_FromLong(nBeginPos);
}
}
nEndPos = pos;
typeByte = buffer[pos];
pos++;
switch (typeByte) {
case LIST: {
int num = b1282int(buffer, nBeginPos, nEndPos);
if (num > 640*1024) {
PyErr_SetString(BananaError,
"Security precaution: List too long.\n");
return NULL;
}
if (!state->currentList) {
state->currentList = (struct listItem *)malloc(sizeof(struct listItem));
if (!state->currentList)
return PyErr_NoMemory();
state->currentList->lastList = NULL;
state->currentList->currentIndex = 0;
state->currentList->size = num;
state->currentList->thisList = PyList_New(num);
if (!state->currentList->thisList) {
free(state->currentList); state->currentList = NULL;
return NULL;
}
} else {
struct listItem *newList = (struct listItem *) malloc(sizeof(struct listItem));
if (!newList)
return PyErr_NoMemory();
newList->size = num;
newList->thisList = PyList_New(num);
if (!newList->thisList) {
free(newList);
return NULL;
}
newList->currentIndex = 0;
newList->lastList = state->currentList;
state->currentList = newList;
}
}
break;
case INT: {
int num = b1282int(buffer, nBeginPos, nEndPos);
if (!gotItemInt(num, state->currentList, expressionReceived)){
return NULL;
}
}
break;
case NEG: {
int num = -b1282int(buffer, nBeginPos, nEndPos);
if (!gotItemInt(num, state->currentList, expressionReceived)){
return NULL;
}
}
break;
case LONGINT: {
PyObject* argtup;
PyObject* rval;
PyObject* pyb1282int;
argtup = PyTuple_New(1);
PyTuple_SetItem(argtup, 0,
PyString_FromStringAndSize(buffer + nBeginPos,
nEndPos - nBeginPos));
pyb1282int = PyObject_GetAttrString(cBanana_module, "pyb1282int");
if (!pyb1282int) { return NULL; }
rval = PyObject_CallObject(pyb1282int, argtup);
Py_DECREF(argtup);
Py_DECREF(pyb1282int);
if (!rval) { return NULL; }
if (!gotPythonItem(rval, state->currentList, expressionReceived)) {
return NULL;
}
}
break;
case LONGNEG: {
PyObject* argtup;
PyObject* rval;
PyObject* negval;
PyObject* pyb1282int;
argtup = PyTuple_New(1);
PyTuple_SetItem(argtup, 0,
PyString_FromStringAndSize(buffer + nBeginPos,
nEndPos - nBeginPos));
pyb1282int = PyObject_GetAttrString(cBanana_module, "pyb1282int");
if (!pyb1282int) { return NULL; }
rval = PyObject_CallObject(pyb1282int, argtup);
Py_DECREF(argtup);
Py_DECREF(pyb1282int);
if (!rval) {
return NULL;
}
negval = PyNumber_Negative(rval);
if (!negval) {
return NULL;
}
Py_DECREF(rval);
if (!gotPythonItem(negval, state->currentList, expressionReceived)) {
return NULL;
}
}
break;
case STRING: {
int len = b1282int(buffer, nBeginPos, nEndPos);
if (len > 640 * 1024) {
PyErr_SetString(BananaError,
"Security precaution: String too long.\n");
return NULL;
}
if (len > (bufferSize - pos) ) {
return PyInt_FromLong(nBeginPos);
}
if (!gotItemString(buffer+pos, len, state->currentList, expressionReceived)) {
return NULL;
}
pos += len;
}
break;
case VOCAB: {
int num = b1282int(buffer, nBeginPos, nEndPos);
const char *vocabString = findVocab(num);
if (vocabString == NULL) {
char errmsg[256];
snprintf(errmsg, 256, "Vocab String Not Found: %d", num);
PyErr_SetString(BananaError, errmsg);
return NULL;
}
if (!gotItemString(vocabString, strlen(vocabString),
state->currentList, expressionReceived)) {
return NULL;
}
}
break;
case FLOAT: {
double num;
int sign_bit;
int exponent;
long fhi, flo;
char* p;
if (8 > (bufferSize - pos) ) {
return PyInt_FromLong(nBeginPos);
}
p = (char*) (buffer + pos);
sign_bit = (*p>>7) & 1;
exponent = (*p & 0x7F) << 4;
p ++;
exponent |= (*p>>4) & 0xF;
fhi = (*p & 0xF) << 24;
p ++;
fhi |= (*p & 0xFF) << 16;
p ++;
fhi |= (*p & 0xFF) << 8;
p ++;
fhi |= (*p & 0xFF);
p ++;
flo = (*p & 0xFF) << 16;
p ++;
flo |= (*p & 0xFF) << 8;
p ++;
flo |= (*p & 0xFF);
p ++;
num = (double)fhi + (double)flo / 16777216.0;
num /= 268435456.0;
if (exponent == 0)
exponent = -1022;
else {
num += 1.0;
exponent -= 1023;
}
num = ldexp(num, exponent);
if (sign_bit)
num = -num;
gotItemFloat(num, state->currentList, expressionReceived);
pos += 8;
}
break;
default: {
char errmsg[256];
snprintf(errmsg, 256, "Invalid Type Byte: %hhd", typeByte);
PyErr_SetString(BananaError, errmsg);
return NULL;
}
}
if (state->currentList) {
while (state->currentList && (state->currentList->currentIndex == state->currentList->size)){
PyObject *list;
struct listItem *tmp;
list = state->currentList->thisList;
tmp = state->currentList->lastList;
free(state->currentList);
state->currentList = tmp;
if (!gotItemList(list, state->currentList, expressionReceived)) {
return NULL;
}
}
}
}
return PyInt_FromLong(pos);
}
static PyObject *util_FromImport(const char *name, const char *from_item)
{
PyObject *from_list;
PyObject *module;
PyObject *item;
from_list = PyList_New(1);
PyList_SetItem(from_list, 0, PyString_FromString(from_item));
module = PyImport_ImportModuleEx((char *)name, NULL, NULL, from_list);
Py_DECREF(from_list);
if (!module)
{
return NULL;
}
item = PyObject_GetAttrString(module, (char *)from_item);
Py_DECREF(module);
return item;
}
extern EXTERN_API void initcBanana(void)
{
cBananaStateType.ob_type = &PyType_Type;
cBananaBufType.ob_type = &PyType_Type;
cBanana_module = Py_InitModule("cBanana", cBanana__methods__);
cBanana_dict = PyModule_GetDict(cBanana_module);
BananaError = util_FromImport("twisted.spread.banana", "BananaError");
if (!BananaError) {
PyErr_Print();
BananaError = PyErr_NewException("BananaError", NULL, NULL);
}
PyDict_SetItemString(cBanana_dict, "BananaError", BananaError);
}