| David Reiss | 382fc30 | 2007-08-25 18:01:30 +0000 | [diff] [blame] | 1 | // Copyright (c) 2006- Facebook | 
 | 2 | // Distributed under the Thrift Software License | 
 | 3 | // | 
 | 4 | // See accompanying file LICENSE or visit the Thrift site at: | 
 | 5 | // http://developers.facebook.com/thrift/ | 
 | 6 | // | 
 | 7 | // NOTE:  This code was contributed by an external developer. | 
 | 8 | //        The internal Thrift team has reviewed and tested it, | 
 | 9 | //        but we cannot guarantee that it is production-ready. | 
 | 10 | //        Please feel free to report bugs and/or success stories | 
 | 11 | //        to the public mailing list. | 
 | 12 |  | 
 | 13 | #include <Python.h> | 
 | 14 | #include "cStringIO.h" | 
 | 15 | #include <stdbool.h> | 
 | 16 | #include <stdint.h> | 
 | 17 | #include <netinet/in.h> | 
 | 18 |  | 
 | 19 | // TODO(dreiss): defval appears to be unused.  Look into removing it. | 
 | 20 | // TODO(dreiss): Make parse_spec_args recursive, and cache the output | 
 | 21 | //               permanently in the object.  (Malloc and orphan.) | 
 | 22 | // TODO(dreiss): Why do we need cStringIO for reading, why not just char*? | 
 | 23 | //               Can cStringIO let us work with a BufferedTransport? | 
 | 24 | // TODO(dreiss): Don't ignore the rv from cwrite (maybe). | 
 | 25 |  | 
 | 26 | /* ====== BEGIN UTILITIES ====== */ | 
 | 27 |  | 
 | 28 | #define INIT_OUTBUF_SIZE 128 | 
 | 29 |  | 
 | 30 | // Stolen out of TProtocol.h. | 
 | 31 | // It would be a huge pain to have both get this from one place. | 
 | 32 | typedef enum TType { | 
 | 33 |   T_STOP       = 0, | 
 | 34 |   T_VOID       = 1, | 
 | 35 |   T_BOOL       = 2, | 
 | 36 |   T_BYTE       = 3, | 
 | 37 |   T_I08        = 3, | 
 | 38 |   T_I16        = 6, | 
 | 39 |   T_I32        = 8, | 
 | 40 |   T_U64        = 9, | 
 | 41 |   T_I64        = 10, | 
 | 42 |   T_DOUBLE     = 4, | 
 | 43 |   T_STRING     = 11, | 
 | 44 |   T_UTF7       = 11, | 
 | 45 |   T_STRUCT     = 12, | 
 | 46 |   T_MAP        = 13, | 
 | 47 |   T_SET        = 14, | 
 | 48 |   T_LIST       = 15, | 
 | 49 |   T_UTF8       = 16, | 
 | 50 |   T_UTF16      = 17 | 
 | 51 | } TType; | 
 | 52 |  | 
 | 53 | // Same comment as the enum.  Sorry. | 
 | 54 | #if __BYTE_ORDER == __BIG_ENDIAN | 
 | 55 | # define ntohll(n) (n) | 
 | 56 | # define htonll(n) (n) | 
 | 57 | #elif __BYTE_ORDER == __LITTLE_ENDIAN | 
 | 58 | # if defined(__GNUC__) && defined(__GLIBC__) | 
 | 59 | #  include <byteswap.h> | 
 | 60 | #  define ntohll(n) bswap_64(n) | 
 | 61 | #  define htonll(n) bswap_64(n) | 
 | 62 | # else /* GNUC & GLIBC */ | 
 | 63 | #  define ntohll(n) ( (((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32) ) | 
 | 64 | #  define htonll(n) ( (((unsigned long long)htonl(n)) << 32) + htonl(n >> 32) ) | 
 | 65 | # endif /* GNUC & GLIBC */ | 
 | 66 | #else /* __BYTE_ORDER */ | 
 | 67 | # error "Can't define htonll or ntohll!" | 
 | 68 | #endif | 
 | 69 |  | 
 | 70 | // Doing a benchmark shows that interning actually makes a difference, amazingly. | 
 | 71 | #define INTERN_STRING(value) _intern_ ## value | 
 | 72 |  | 
 | 73 | #define INT_CONV_ERROR_OCCURRED(v) ( ((v) == -1) && PyErr_Occurred() ) | 
 | 74 | #define CHECK_RANGE(v, min, max) ( ((v) <= (max)) && ((v) >= (min)) ) | 
 | 75 |  | 
| David Reiss | 5ec8e26 | 2007-08-26 02:21:24 +0000 | [diff] [blame] | 76 | // Py_ssize_t was not defined before Python 2.5 | 
 | 77 | #if (PY_VERSION_HEX < 0x02050000) | 
 | 78 | typedef int Py_ssize_t; | 
 | 79 | #endif | 
 | 80 |  | 
| David Reiss | 382fc30 | 2007-08-25 18:01:30 +0000 | [diff] [blame] | 81 | /** | 
 | 82 |  * A cache of the spec_args for a set or list, | 
 | 83 |  * so we don't have to keep calling PyTuple_GET_ITEM. | 
 | 84 |  */ | 
 | 85 | typedef struct { | 
 | 86 |   TType element_type; | 
 | 87 |   PyObject* typeargs; | 
 | 88 | } SetListTypeArgs; | 
 | 89 |  | 
 | 90 | /** | 
 | 91 |  * A cache of the spec_args for a map, | 
 | 92 |  * so we don't have to keep calling PyTuple_GET_ITEM. | 
 | 93 |  */ | 
 | 94 | typedef struct { | 
 | 95 |   TType ktag; | 
 | 96 |   TType vtag; | 
 | 97 |   PyObject* ktypeargs; | 
 | 98 |   PyObject* vtypeargs; | 
 | 99 | } MapTypeArgs; | 
 | 100 |  | 
 | 101 | /** | 
 | 102 |  * A cache of the spec_args for a struct, | 
 | 103 |  * so we don't have to keep calling PyTuple_GET_ITEM. | 
 | 104 |  */ | 
 | 105 | typedef struct { | 
 | 106 |   PyObject* klass; | 
 | 107 |   PyObject* spec; | 
 | 108 | } StructTypeArgs; | 
 | 109 |  | 
 | 110 | /** | 
 | 111 |  * A cache of the item spec from a struct specification, | 
 | 112 |  * so we don't have to keep calling PyTuple_GET_ITEM. | 
 | 113 |  */ | 
 | 114 | typedef struct { | 
 | 115 |   int tag; | 
 | 116 |   TType type; | 
 | 117 |   PyObject* attrname; | 
 | 118 |   PyObject* typeargs; | 
 | 119 |   PyObject* defval; | 
 | 120 | } StructItemSpec; | 
 | 121 |  | 
 | 122 | /** | 
 | 123 |  * A cache of the two key attributes of a CReadableTransport, | 
 | 124 |  * so we don't have to keep calling PyObject_GetAttr. | 
 | 125 |  */ | 
 | 126 | typedef struct { | 
 | 127 |   PyObject* stringiobuf; | 
 | 128 |   PyObject* refill_callable; | 
 | 129 | } DecodeBuffer; | 
 | 130 |  | 
 | 131 | /** Pointer to interned string to speed up attribute lookup. */ | 
 | 132 | static PyObject* INTERN_STRING(cstringio_buf); | 
 | 133 | /** Pointer to interned string to speed up attribute lookup. */ | 
 | 134 | static PyObject* INTERN_STRING(cstringio_refill); | 
 | 135 |  | 
 | 136 | static inline bool | 
 | 137 | check_ssize_t_32(Py_ssize_t len) { | 
 | 138 |   // error from getting the int | 
 | 139 |   if (INT_CONV_ERROR_OCCURRED(len)) { | 
 | 140 |     return false; | 
 | 141 |   } | 
 | 142 |   if (!CHECK_RANGE(len, 0, INT32_MAX)) { | 
 | 143 |     PyErr_SetString(PyExc_OverflowError, "string size out of range"); | 
 | 144 |     return false; | 
 | 145 |   } | 
 | 146 |   return true; | 
 | 147 | } | 
 | 148 |  | 
 | 149 | static inline bool | 
 | 150 | parse_pyint(PyObject* o, int32_t* ret, int32_t min, int32_t max) { | 
 | 151 |   long val = PyInt_AsLong(o); | 
 | 152 |  | 
 | 153 |   if (INT_CONV_ERROR_OCCURRED(val)) { | 
 | 154 |     return false; | 
 | 155 |   } | 
 | 156 |   if (!CHECK_RANGE(val, min, max)) { | 
 | 157 |     PyErr_SetString(PyExc_OverflowError, "int out of range"); | 
 | 158 |     return false; | 
 | 159 |   } | 
 | 160 |  | 
 | 161 |   *ret = (int32_t) val; | 
 | 162 |   return true; | 
 | 163 | } | 
 | 164 |  | 
 | 165 |  | 
 | 166 | /* --- FUNCTIONS TO PARSE STRUCT SPECIFICATOINS --- */ | 
 | 167 |  | 
 | 168 | static bool | 
 | 169 | parse_set_list_args(SetListTypeArgs* dest, PyObject* typeargs) { | 
 | 170 |   if (PyTuple_Size(typeargs) != 2) { | 
 | 171 |     PyErr_SetString(PyExc_TypeError, "expecting tuple of size 2 for list/set type args"); | 
 | 172 |     return false; | 
 | 173 |   } | 
 | 174 |  | 
 | 175 |   dest->element_type = PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 0)); | 
 | 176 |   if (INT_CONV_ERROR_OCCURRED(dest->element_type)) { | 
 | 177 |     return false; | 
 | 178 |   } | 
 | 179 |  | 
 | 180 |   dest->typeargs = PyTuple_GET_ITEM(typeargs, 1); | 
 | 181 |  | 
 | 182 |   return true; | 
 | 183 | } | 
 | 184 |  | 
 | 185 | static bool | 
 | 186 | parse_map_args(MapTypeArgs* dest, PyObject* typeargs) { | 
 | 187 |   if (PyTuple_Size(typeargs) != 4) { | 
 | 188 |     PyErr_SetString(PyExc_TypeError, "expecting 4 arguments for typeargs to map"); | 
 | 189 |     return false; | 
 | 190 |   } | 
 | 191 |  | 
 | 192 |   dest->ktag = PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 0)); | 
 | 193 |   if (INT_CONV_ERROR_OCCURRED(dest->ktag)) { | 
 | 194 |     return false; | 
 | 195 |   } | 
 | 196 |  | 
 | 197 |   dest->vtag = PyInt_AsLong(PyTuple_GET_ITEM(typeargs, 2)); | 
 | 198 |   if (INT_CONV_ERROR_OCCURRED(dest->vtag)) { | 
 | 199 |     return false; | 
 | 200 |   } | 
 | 201 |  | 
 | 202 |   dest->ktypeargs = PyTuple_GET_ITEM(typeargs, 1); | 
 | 203 |   dest->vtypeargs = PyTuple_GET_ITEM(typeargs, 3); | 
 | 204 |  | 
 | 205 |   return true; | 
 | 206 | } | 
 | 207 |  | 
 | 208 | static bool | 
 | 209 | parse_struct_args(StructTypeArgs* dest, PyObject* typeargs) { | 
 | 210 |   if (PyTuple_Size(typeargs) != 2) { | 
 | 211 |     PyErr_SetString(PyExc_TypeError, "expecting tuple of size 2 for struct args"); | 
 | 212 |     return false; | 
 | 213 |   } | 
 | 214 |  | 
 | 215 |   dest->klass = PyTuple_GET_ITEM(typeargs, 0); | 
 | 216 |   dest->spec = PyTuple_GET_ITEM(typeargs, 1); | 
 | 217 |  | 
 | 218 |   return true; | 
 | 219 | } | 
 | 220 |  | 
 | 221 | static int | 
 | 222 | parse_struct_item_spec(StructItemSpec* dest, PyObject* spec_tuple) { | 
 | 223 |  | 
 | 224 |   // i'd like to use ParseArgs here, but it seems to be a bottleneck. | 
 | 225 |   if (PyTuple_Size(spec_tuple) != 5) { | 
 | 226 |     PyErr_SetString(PyExc_TypeError, "expecting 5 arguments for spec tuple"); | 
 | 227 |     return false; | 
 | 228 |   } | 
 | 229 |  | 
 | 230 |   dest->tag = PyInt_AsLong(PyTuple_GET_ITEM(spec_tuple, 0)); | 
 | 231 |   if (INT_CONV_ERROR_OCCURRED(dest->tag)) { | 
 | 232 |     return false; | 
 | 233 |   } | 
 | 234 |  | 
 | 235 |   dest->type = PyInt_AsLong(PyTuple_GET_ITEM(spec_tuple, 1)); | 
 | 236 |   if (INT_CONV_ERROR_OCCURRED(dest->type)) { | 
 | 237 |     return false; | 
 | 238 |   } | 
 | 239 |  | 
 | 240 |   dest->attrname = PyTuple_GET_ITEM(spec_tuple, 2); | 
 | 241 |   dest->typeargs = PyTuple_GET_ITEM(spec_tuple, 3); | 
 | 242 |   dest->defval = PyTuple_GET_ITEM(spec_tuple, 4); | 
 | 243 |   return true; | 
 | 244 | } | 
 | 245 |  | 
 | 246 | /* ====== END UTILITIES ====== */ | 
 | 247 |  | 
 | 248 |  | 
 | 249 | /* ====== BEGIN WRITING FUNCTIONS ====== */ | 
 | 250 |  | 
 | 251 | /* --- LOW-LEVEL WRITING FUNCTIONS --- */ | 
 | 252 |  | 
 | 253 | static void writeByte(PyObject* outbuf, int8_t val) { | 
 | 254 |   int8_t net = val; | 
 | 255 |   PycStringIO->cwrite(outbuf, (char*)&net, sizeof(int8_t)); | 
 | 256 | } | 
 | 257 |  | 
 | 258 | static void writeI16(PyObject* outbuf, int16_t val) { | 
 | 259 |   int16_t net = (int16_t)htons(val); | 
 | 260 |   PycStringIO->cwrite(outbuf, (char*)&net, sizeof(int16_t)); | 
 | 261 | } | 
 | 262 |  | 
 | 263 | static void writeI32(PyObject* outbuf, int32_t val) { | 
 | 264 |   int32_t net = (int32_t)htonl(val); | 
 | 265 |   PycStringIO->cwrite(outbuf, (char*)&net, sizeof(int32_t)); | 
 | 266 | } | 
 | 267 |  | 
 | 268 | static void writeI64(PyObject* outbuf, int64_t val) { | 
 | 269 |   int64_t net = (int64_t)htonll(val); | 
 | 270 |   PycStringIO->cwrite(outbuf, (char*)&net, sizeof(int64_t)); | 
 | 271 | } | 
 | 272 |  | 
 | 273 | static void writeDouble(PyObject* outbuf, double dub) { | 
 | 274 |   // Unfortunately, bitwise_cast doesn't work in C.  Bad C! | 
 | 275 |   union { | 
 | 276 |     double f; | 
 | 277 |     int64_t t; | 
 | 278 |   } transfer; | 
 | 279 |   transfer.f = dub; | 
 | 280 |   writeI64(outbuf, transfer.t); | 
 | 281 | } | 
 | 282 |  | 
 | 283 |  | 
 | 284 | /* --- MAIN RECURSIVE OUTPUT FUCNTION -- */ | 
 | 285 |  | 
 | 286 | static int | 
 | 287 | output_val(PyObject* output, PyObject* value, TType type, PyObject* typeargs) { | 
 | 288 |   /* | 
 | 289 |    * Refcounting Strategy: | 
 | 290 |    * | 
 | 291 |    * We assume that elements of the thrift_spec tuple are not going to be | 
 | 292 |    * mutated, so we don't ref count those at all. Other than that, we try to | 
 | 293 |    * keep a reference to all the user-created objects while we work with them. | 
 | 294 |    * output_val assumes that a reference is already held. The *caller* is | 
 | 295 |    * responsible for handling references | 
 | 296 |    */ | 
 | 297 |  | 
 | 298 |   switch (type) { | 
 | 299 |  | 
 | 300 |   case T_BOOL: { | 
 | 301 |     int v = PyObject_IsTrue(value); | 
 | 302 |     if (v == -1) { | 
 | 303 |       return false; | 
 | 304 |     } | 
 | 305 |  | 
 | 306 |     writeByte(output, (int8_t) v); | 
 | 307 |     break; | 
 | 308 |   } | 
 | 309 |   case T_I08: { | 
 | 310 |     int32_t val; | 
 | 311 |  | 
 | 312 |     if (!parse_pyint(value, &val, INT8_MIN, INT8_MAX)) { | 
 | 313 |       return false; | 
 | 314 |     } | 
 | 315 |  | 
 | 316 |     writeByte(output, (int8_t) val); | 
 | 317 |     break; | 
 | 318 |   } | 
 | 319 |   case T_I16: { | 
 | 320 |     int32_t val; | 
 | 321 |  | 
 | 322 |     if (!parse_pyint(value, &val, INT16_MIN, INT16_MAX)) { | 
 | 323 |       return false; | 
 | 324 |     } | 
 | 325 |  | 
 | 326 |     writeI16(output, (int16_t) val); | 
 | 327 |     break; | 
 | 328 |   } | 
 | 329 |   case T_I32: { | 
 | 330 |     int32_t val; | 
 | 331 |  | 
 | 332 |     if (!parse_pyint(value, &val, INT32_MIN, INT32_MAX)) { | 
 | 333 |       return false; | 
 | 334 |     } | 
 | 335 |  | 
 | 336 |     writeI32(output, val); | 
 | 337 |     break; | 
 | 338 |   } | 
 | 339 |   case T_I64: { | 
 | 340 |     int64_t nval = PyLong_AsLongLong(value); | 
 | 341 |  | 
 | 342 |     if (INT_CONV_ERROR_OCCURRED(nval)) { | 
 | 343 |       return false; | 
 | 344 |     } | 
 | 345 |  | 
 | 346 |     if (!CHECK_RANGE(nval, INT64_MIN, INT64_MAX)) { | 
 | 347 |       PyErr_SetString(PyExc_OverflowError, "int out of range"); | 
 | 348 |       return false; | 
 | 349 |     } | 
 | 350 |  | 
 | 351 |     writeI64(output, nval); | 
 | 352 |     break; | 
 | 353 |   } | 
 | 354 |  | 
 | 355 |   case T_DOUBLE: { | 
 | 356 |     double nval = PyFloat_AsDouble(value); | 
 | 357 |     if (nval == -1.0 && PyErr_Occurred()) { | 
 | 358 |       return false; | 
 | 359 |     } | 
 | 360 |  | 
 | 361 |     writeDouble(output, nval); | 
 | 362 |     break; | 
 | 363 |   } | 
 | 364 |  | 
 | 365 |   case T_STRING: { | 
 | 366 |     Py_ssize_t len = PyString_Size(value); | 
 | 367 |  | 
 | 368 |     if (!check_ssize_t_32(len)) { | 
 | 369 |       return false; | 
 | 370 |     } | 
 | 371 |  | 
 | 372 |     writeI32(output, (int32_t) len); | 
 | 373 |     PycStringIO->cwrite(output, PyString_AsString(value), (int32_t) len); | 
 | 374 |     break; | 
 | 375 |   } | 
 | 376 |  | 
 | 377 |   case T_LIST: | 
 | 378 |   case T_SET: { | 
 | 379 |     Py_ssize_t len; | 
 | 380 |     SetListTypeArgs parsedargs; | 
 | 381 |     PyObject *item; | 
 | 382 |     PyObject *iterator; | 
 | 383 |  | 
 | 384 |     if (!parse_set_list_args(&parsedargs, typeargs)) { | 
 | 385 |       return false; | 
 | 386 |     } | 
 | 387 |  | 
 | 388 |     len = PyObject_Length(value); | 
 | 389 |  | 
 | 390 |     if (!check_ssize_t_32(len)) { | 
 | 391 |       return false; | 
 | 392 |     } | 
 | 393 |  | 
 | 394 |     writeByte(output, parsedargs.element_type); | 
 | 395 |     writeI32(output, (int32_t) len); | 
 | 396 |  | 
 | 397 |     iterator =  PyObject_GetIter(value); | 
 | 398 |     if (iterator == NULL) { | 
 | 399 |       return false; | 
 | 400 |     } | 
 | 401 |  | 
 | 402 |     while ((item = PyIter_Next(iterator))) { | 
 | 403 |       if (!output_val(output, item, parsedargs.element_type, parsedargs.typeargs)) { | 
 | 404 |         Py_DECREF(item); | 
 | 405 |         Py_DECREF(iterator); | 
 | 406 |         return false; | 
 | 407 |       } | 
 | 408 |       Py_DECREF(item); | 
 | 409 |     } | 
 | 410 |  | 
 | 411 |     Py_DECREF(iterator); | 
 | 412 |  | 
 | 413 |     if (PyErr_Occurred()) { | 
 | 414 |       return false; | 
 | 415 |     } | 
 | 416 |  | 
 | 417 |     break; | 
 | 418 |   } | 
 | 419 |  | 
 | 420 |   case T_MAP: { | 
 | 421 |     PyObject *k, *v; | 
 | 422 |     int pos = 0; | 
 | 423 |     Py_ssize_t len; | 
 | 424 |  | 
 | 425 |     MapTypeArgs parsedargs; | 
 | 426 |  | 
 | 427 |     len = PyDict_Size(value); | 
 | 428 |     if (!check_ssize_t_32(len)) { | 
 | 429 |       return false; | 
 | 430 |     } | 
 | 431 |  | 
 | 432 |     if (!parse_map_args(&parsedargs, typeargs)) { | 
 | 433 |       return false; | 
 | 434 |     } | 
 | 435 |  | 
 | 436 |     writeByte(output, parsedargs.ktag); | 
 | 437 |     writeByte(output, parsedargs.vtag); | 
 | 438 |     writeI32(output, len); | 
 | 439 |  | 
 | 440 |     // TODO(bmaurer): should support any mapping, not just dicts | 
 | 441 |     while (PyDict_Next(value, &pos, &k, &v)) { | 
 | 442 |       // TODO(dreiss): Think hard about whether these INCREFs actually | 
 | 443 |       //               turn any unsafe scenarios into safe scenarios. | 
 | 444 |       Py_INCREF(k); | 
 | 445 |       Py_INCREF(v); | 
 | 446 |  | 
 | 447 |       if (!output_val(output, k, parsedargs.ktag, parsedargs.ktypeargs) | 
 | 448 |           || !output_val(output, v, parsedargs.vtag, parsedargs.vtypeargs)) { | 
 | 449 |         Py_DECREF(k); | 
 | 450 |         Py_DECREF(v); | 
 | 451 |         return false; | 
 | 452 |       } | 
 | 453 |     } | 
 | 454 |     break; | 
 | 455 |   } | 
 | 456 |  | 
 | 457 |   // TODO(dreiss): Consider breaking this out as a function | 
 | 458 |   //               the way we did for decode_struct. | 
 | 459 |   case T_STRUCT: { | 
 | 460 |     StructTypeArgs parsedargs; | 
 | 461 |     Py_ssize_t nspec; | 
 | 462 |     Py_ssize_t i; | 
 | 463 |  | 
 | 464 |     if (!parse_struct_args(&parsedargs, typeargs)) { | 
 | 465 |       return false; | 
 | 466 |     } | 
 | 467 |  | 
 | 468 |     nspec = PyTuple_Size(parsedargs.spec); | 
 | 469 |  | 
 | 470 |     if (nspec == -1) { | 
 | 471 |       return false; | 
 | 472 |     } | 
 | 473 |  | 
 | 474 |     for (i = 0; i < nspec; i++) { | 
 | 475 |       StructItemSpec parsedspec; | 
 | 476 |       PyObject* spec_tuple; | 
 | 477 |       PyObject* instval = NULL; | 
 | 478 |  | 
 | 479 |       spec_tuple = PyTuple_GET_ITEM(parsedargs.spec, i); | 
 | 480 |       if (spec_tuple == Py_None) { | 
 | 481 |         continue; | 
 | 482 |       } | 
 | 483 |  | 
 | 484 |       if (!parse_struct_item_spec (&parsedspec, spec_tuple)) { | 
 | 485 |         return false; | 
 | 486 |       } | 
 | 487 |  | 
 | 488 |       instval = PyObject_GetAttr(value, parsedspec.attrname); | 
 | 489 |  | 
 | 490 |       if (!instval) { | 
 | 491 |         return false; | 
 | 492 |       } | 
 | 493 |  | 
 | 494 |       if (instval == Py_None) { | 
 | 495 |         Py_DECREF(instval); | 
 | 496 |         continue; | 
 | 497 |       } | 
 | 498 |  | 
 | 499 |       writeByte(output, (int8_t) parsedspec.type); | 
 | 500 |       writeI16(output, parsedspec.tag); | 
 | 501 |  | 
 | 502 |       if (!output_val(output, instval, parsedspec.type, parsedspec.typeargs)) { | 
 | 503 |         Py_DECREF(instval); | 
 | 504 |         return false; | 
 | 505 |       } | 
 | 506 |  | 
 | 507 |       Py_DECREF(instval); | 
 | 508 |     } | 
 | 509 |  | 
 | 510 |     writeByte(output, (int8_t)T_STOP); | 
 | 511 |     break; | 
 | 512 |   } | 
 | 513 |  | 
 | 514 |   case T_STOP: | 
 | 515 |   case T_VOID: | 
 | 516 |   case T_UTF16: | 
 | 517 |   case T_UTF8: | 
 | 518 |   case T_U64: | 
 | 519 |   default: | 
 | 520 |     PyErr_SetString(PyExc_TypeError, "Unexpected TType"); | 
 | 521 |     return false; | 
 | 522 |  | 
 | 523 |   } | 
 | 524 |  | 
 | 525 |   return true; | 
 | 526 | } | 
 | 527 |  | 
 | 528 |  | 
 | 529 | /* --- TOP-LEVEL WRAPPER FOR OUTPUT -- */ | 
 | 530 |  | 
 | 531 | static PyObject * | 
 | 532 | encode_binary(PyObject *self, PyObject *args) { | 
 | 533 |   PyObject* enc_obj; | 
 | 534 |   PyObject* type_args; | 
 | 535 |   PyObject* buf; | 
 | 536 |   PyObject* ret = NULL; | 
 | 537 |  | 
 | 538 |   if (!PyArg_ParseTuple(args, "OO", &enc_obj, &type_args)) { | 
 | 539 |     return NULL; | 
 | 540 |   } | 
 | 541 |  | 
 | 542 |   buf = PycStringIO->NewOutput(INIT_OUTBUF_SIZE); | 
 | 543 |   if (output_val(buf, enc_obj, T_STRUCT, type_args)) { | 
 | 544 |     ret = PycStringIO->cgetvalue(buf); | 
 | 545 |   } | 
 | 546 |  | 
 | 547 |   Py_DECREF(buf); | 
 | 548 |   return ret; | 
 | 549 | } | 
 | 550 |  | 
 | 551 | /* ====== END WRITING FUNCTIONS ====== */ | 
 | 552 |  | 
 | 553 |  | 
 | 554 | /* ====== BEGIN READING FUNCTIONS ====== */ | 
 | 555 |  | 
 | 556 | /* --- LOW-LEVEL READING FUNCTIONS --- */ | 
 | 557 |  | 
 | 558 | static void | 
 | 559 | free_decodebuf(DecodeBuffer* d) { | 
 | 560 |   Py_XDECREF(d->stringiobuf); | 
 | 561 |   Py_XDECREF(d->refill_callable); | 
 | 562 | } | 
 | 563 |  | 
 | 564 | static bool | 
 | 565 | decode_buffer_from_obj(DecodeBuffer* dest, PyObject* obj) { | 
 | 566 |   dest->stringiobuf = PyObject_GetAttr(obj, INTERN_STRING(cstringio_buf)); | 
 | 567 |   if (!dest->stringiobuf) { | 
 | 568 |     return false; | 
 | 569 |   } | 
 | 570 |  | 
 | 571 |   if (!PycStringIO_InputCheck(dest->stringiobuf)) { | 
 | 572 |     free_decodebuf(dest); | 
 | 573 |     PyErr_SetString(PyExc_TypeError, "expecting stringio input"); | 
 | 574 |     return false; | 
 | 575 |   } | 
 | 576 |  | 
 | 577 |   dest->refill_callable = PyObject_GetAttr(obj, INTERN_STRING(cstringio_refill)); | 
 | 578 |  | 
 | 579 |   if(!dest->refill_callable) { | 
 | 580 |     free_decodebuf(dest); | 
 | 581 |     return false; | 
 | 582 |   } | 
 | 583 |  | 
 | 584 |   if (!PyCallable_Check(dest->refill_callable)) { | 
 | 585 |     free_decodebuf(dest); | 
 | 586 |     PyErr_SetString(PyExc_TypeError, "expecting callable"); | 
 | 587 |     return false; | 
 | 588 |   } | 
 | 589 |  | 
 | 590 |   return true; | 
 | 591 | } | 
 | 592 |  | 
 | 593 | static bool readBytes(DecodeBuffer* input, char** output, int len) { | 
 | 594 |   int read; | 
 | 595 |  | 
 | 596 |   // TODO(dreiss): Don't fear the malloc.  Think about taking a copy of | 
 | 597 |   //               the partial read instead of forcing the transport | 
 | 598 |   //               to prepend it to its buffer. | 
 | 599 |  | 
 | 600 |   read = PycStringIO->cread(input->stringiobuf, output, len); | 
 | 601 |  | 
 | 602 |   if (read == len) { | 
 | 603 |     return true; | 
 | 604 |   } else if (read == -1) { | 
 | 605 |     return false; | 
 | 606 |   } else { | 
 | 607 |     PyObject* newiobuf; | 
 | 608 |  | 
 | 609 |     // using building functions as this is a rare codepath | 
 | 610 |     newiobuf = PyObject_CallFunction( | 
| David Reiss | 2c2e6d2 | 2007-09-05 01:14:09 +0000 | [diff] [blame] | 611 |         input->refill_callable, "s#i", *output, read, len, NULL); | 
| David Reiss | 382fc30 | 2007-08-25 18:01:30 +0000 | [diff] [blame] | 612 |     if (newiobuf == NULL) { | 
 | 613 |       return false; | 
 | 614 |     } | 
 | 615 |  | 
 | 616 |     // must do this *AFTER* the call so that we don't deref the io buffer | 
 | 617 |     Py_CLEAR(input->stringiobuf); | 
 | 618 |     input->stringiobuf = newiobuf; | 
 | 619 |  | 
 | 620 |     read = PycStringIO->cread(input->stringiobuf, output, len); | 
 | 621 |  | 
 | 622 |     if (read == len) { | 
 | 623 |       return true; | 
 | 624 |     } else if (read == -1) { | 
 | 625 |       return false; | 
 | 626 |     } else { | 
 | 627 |       // TODO(dreiss): This could be a valid code path for big binary blobs. | 
 | 628 |       PyErr_SetString(PyExc_TypeError, | 
 | 629 |           "refill claimed to have refilled the buffer, but didn't!!"); | 
 | 630 |       return false; | 
 | 631 |     } | 
 | 632 |   } | 
 | 633 | } | 
 | 634 |  | 
 | 635 | static int8_t readByte(DecodeBuffer* input) { | 
 | 636 |   char* buf; | 
 | 637 |   if (!readBytes(input, &buf, sizeof(int8_t))) { | 
 | 638 |     return -1; | 
 | 639 |   } | 
 | 640 |  | 
 | 641 |   return *(int8_t*) buf; | 
 | 642 | } | 
 | 643 |  | 
 | 644 | static int16_t readI16(DecodeBuffer* input) { | 
 | 645 |   char* buf; | 
 | 646 |   if (!readBytes(input, &buf, sizeof(int16_t))) { | 
 | 647 |     return -1; | 
 | 648 |   } | 
 | 649 |  | 
 | 650 |   return (int16_t) ntohs(*(int16_t*) buf); | 
 | 651 | } | 
 | 652 |  | 
 | 653 | static int32_t readI32(DecodeBuffer* input) { | 
 | 654 |   char* buf; | 
 | 655 |   if (!readBytes(input, &buf, sizeof(int32_t))) { | 
 | 656 |     return -1; | 
 | 657 |   } | 
 | 658 |   return (int32_t) ntohl(*(int32_t*) buf); | 
 | 659 | } | 
 | 660 |  | 
 | 661 |  | 
 | 662 | static int64_t readI64(DecodeBuffer* input) { | 
 | 663 |   char* buf; | 
 | 664 |   if (!readBytes(input, &buf, sizeof(int64_t))) { | 
 | 665 |     return -1; | 
 | 666 |   } | 
 | 667 |  | 
 | 668 |   return (int64_t) ntohll(*(int64_t*) buf); | 
 | 669 | } | 
 | 670 |  | 
 | 671 | static double readDouble(DecodeBuffer* input) { | 
 | 672 |   union { | 
 | 673 |     int64_t f; | 
 | 674 |     double t; | 
 | 675 |   } transfer; | 
 | 676 |  | 
 | 677 |   transfer.f = readI64(input); | 
 | 678 |   if (transfer.f == -1) { | 
 | 679 |     return -1; | 
 | 680 |   } | 
 | 681 |   return transfer.t; | 
 | 682 | } | 
 | 683 |  | 
 | 684 | static bool | 
 | 685 | checkTypeByte(DecodeBuffer* input, TType expected) { | 
 | 686 |   TType got = readByte(input); | 
| Mark Slee | 53d9c0c | 2007-11-26 21:15:40 +0000 | [diff] [blame] | 687 |   if (INT_CONV_ERROR_OCCURRED(got)) { | 
 | 688 |     return false; | 
 | 689 |   } | 
| David Reiss | 382fc30 | 2007-08-25 18:01:30 +0000 | [diff] [blame] | 690 |  | 
 | 691 |   if (expected != got) { | 
 | 692 |     PyErr_SetString(PyExc_TypeError, "got wrong ttype while reading field"); | 
 | 693 |     return false; | 
 | 694 |   } | 
 | 695 |   return true; | 
 | 696 | } | 
 | 697 |  | 
 | 698 | static bool | 
 | 699 | skip(DecodeBuffer* input, TType type) { | 
 | 700 | #define SKIPBYTES(n) \ | 
 | 701 |   do { \ | 
 | 702 |     if (!readBytes(input, &dummy_buf, (n))) { \ | 
 | 703 |       return false; \ | 
 | 704 |     } \ | 
 | 705 |   } while(0) | 
 | 706 |  | 
 | 707 |   char* dummy_buf; | 
 | 708 |  | 
 | 709 |   switch (type) { | 
 | 710 |  | 
 | 711 |   case T_BOOL: | 
 | 712 |   case T_I08: SKIPBYTES(1); break; | 
 | 713 |   case T_I16: SKIPBYTES(2); break; | 
 | 714 |   case T_I32: SKIPBYTES(4); break; | 
 | 715 |   case T_I64: | 
 | 716 |   case T_DOUBLE: SKIPBYTES(8); break; | 
 | 717 |  | 
 | 718 |   case T_STRING: { | 
 | 719 |     // TODO(dreiss): Find out if these check_ssize_t32s are really necessary. | 
 | 720 |     int len = readI32(input); | 
 | 721 |     if (!check_ssize_t_32(len)) { | 
 | 722 |       return false; | 
 | 723 |     } | 
 | 724 |     SKIPBYTES(len); | 
 | 725 |     break; | 
 | 726 |   } | 
 | 727 |  | 
 | 728 |   case T_LIST: | 
 | 729 |   case T_SET: { | 
 | 730 |     TType etype; | 
 | 731 |     int len, i; | 
 | 732 |  | 
 | 733 |     etype = readByte(input); | 
 | 734 |     if (etype == -1) { | 
 | 735 |       return false; | 
 | 736 |     } | 
 | 737 |  | 
 | 738 |     len = readI32(input); | 
 | 739 |     if (!check_ssize_t_32(len)) { | 
 | 740 |       return false; | 
 | 741 |     } | 
 | 742 |  | 
 | 743 |     for (i = 0; i < len; i++) { | 
 | 744 |       if (!skip(input, etype)) { | 
 | 745 |         return false; | 
 | 746 |       } | 
 | 747 |     } | 
 | 748 |     break; | 
 | 749 |   } | 
 | 750 |  | 
 | 751 |   case T_MAP: { | 
 | 752 |     TType ktype, vtype; | 
 | 753 |     int len, i; | 
 | 754 |  | 
 | 755 |     ktype = readByte(input); | 
 | 756 |     if (ktype == -1) { | 
 | 757 |       return false; | 
 | 758 |     } | 
 | 759 |  | 
 | 760 |     vtype = readByte(input); | 
 | 761 |     if (vtype == -1) { | 
 | 762 |       return false; | 
 | 763 |     } | 
 | 764 |  | 
 | 765 |     len = readI32(input); | 
 | 766 |     if (!check_ssize_t_32(len)) { | 
 | 767 |       return false; | 
 | 768 |     } | 
 | 769 |  | 
 | 770 |     for (i = 0; i < len; i++) { | 
 | 771 |       if (!(skip(input, ktype) && skip(input, vtype))) { | 
 | 772 |         return false; | 
 | 773 |       } | 
 | 774 |     } | 
 | 775 |     break; | 
 | 776 |   } | 
 | 777 |  | 
 | 778 |   case T_STRUCT: { | 
 | 779 |     while (true) { | 
 | 780 |       TType type; | 
 | 781 |  | 
 | 782 |       type = readByte(input); | 
 | 783 |       if (type == -1) { | 
 | 784 |         return false; | 
 | 785 |       } | 
 | 786 |  | 
 | 787 |       if (type == T_STOP) | 
 | 788 |         break; | 
 | 789 |  | 
 | 790 |       SKIPBYTES(2); // tag | 
 | 791 |       if (!skip(input, type)) { | 
 | 792 |         return false; | 
 | 793 |       } | 
 | 794 |     } | 
 | 795 |     break; | 
 | 796 |   } | 
 | 797 |  | 
 | 798 |   case T_STOP: | 
 | 799 |   case T_VOID: | 
 | 800 |   case T_UTF16: | 
 | 801 |   case T_UTF8: | 
 | 802 |   case T_U64: | 
 | 803 |   default: | 
 | 804 |     PyErr_SetString(PyExc_TypeError, "Unexpected TType"); | 
 | 805 |     return false; | 
 | 806 |  | 
 | 807 |   } | 
 | 808 |  | 
| David Reiss | bc444b0 | 2008-02-14 20:20:08 +0000 | [diff] [blame] | 809 |   return true; | 
| David Reiss | 382fc30 | 2007-08-25 18:01:30 +0000 | [diff] [blame] | 810 |  | 
 | 811 | #undef SKIPBYTES | 
 | 812 | } | 
 | 813 |  | 
 | 814 |  | 
 | 815 | /* --- HELPER FUNCTION FOR DECODE_VAL --- */ | 
 | 816 |  | 
 | 817 | static PyObject* | 
 | 818 | decode_val(DecodeBuffer* input, TType type, PyObject* typeargs); | 
 | 819 |  | 
 | 820 | static bool | 
 | 821 | decode_struct(DecodeBuffer* input, PyObject* output, PyObject* spec_seq) { | 
 | 822 |   int spec_seq_len = PyTuple_Size(spec_seq); | 
 | 823 |   if (spec_seq_len == -1) { | 
 | 824 |     return false; | 
 | 825 |   } | 
 | 826 |  | 
 | 827 |   while (true) { | 
 | 828 |     TType type; | 
 | 829 |     int16_t tag; | 
 | 830 |     PyObject* item_spec; | 
 | 831 |     PyObject* fieldval = NULL; | 
 | 832 |     StructItemSpec parsedspec; | 
 | 833 |  | 
 | 834 |     type = readByte(input); | 
| Mark Slee | 53d9c0c | 2007-11-26 21:15:40 +0000 | [diff] [blame] | 835 |     if (type == -1) { | 
 | 836 |       return false; | 
 | 837 |     } | 
| David Reiss | 382fc30 | 2007-08-25 18:01:30 +0000 | [diff] [blame] | 838 |     if (type == T_STOP) { | 
 | 839 |       break; | 
 | 840 |     } | 
 | 841 |     tag = readI16(input); | 
| Mark Slee | 53d9c0c | 2007-11-26 21:15:40 +0000 | [diff] [blame] | 842 |     if (INT_CONV_ERROR_OCCURRED(tag)) { | 
 | 843 |       return false; | 
 | 844 |     } | 
| David Reiss | 382fc30 | 2007-08-25 18:01:30 +0000 | [diff] [blame] | 845 |     if (tag >= 0 && tag < spec_seq_len) { | 
 | 846 |       item_spec = PyTuple_GET_ITEM(spec_seq, tag); | 
 | 847 |     } else { | 
 | 848 |       item_spec = Py_None; | 
 | 849 |     } | 
 | 850 |  | 
 | 851 |     if (item_spec == Py_None) { | 
 | 852 |       if (!skip(input, type)) { | 
 | 853 |         return false; | 
| David Reiss | bc444b0 | 2008-02-14 20:20:08 +0000 | [diff] [blame] | 854 |       } else { | 
 | 855 |         continue; | 
| David Reiss | 382fc30 | 2007-08-25 18:01:30 +0000 | [diff] [blame] | 856 |       } | 
 | 857 |     } | 
 | 858 |  | 
 | 859 |     if (!parse_struct_item_spec(&parsedspec, item_spec)) { | 
 | 860 |       return false; | 
 | 861 |     } | 
 | 862 |     if (parsedspec.type != type) { | 
 | 863 |       PyErr_SetString(PyExc_TypeError, "struct field had wrong type while reading"); | 
 | 864 |       return false; | 
 | 865 |     } | 
 | 866 |  | 
 | 867 |     fieldval = decode_val(input, parsedspec.type, parsedspec.typeargs); | 
 | 868 |     if (fieldval == NULL) { | 
 | 869 |       return false; | 
 | 870 |     } | 
 | 871 |  | 
 | 872 |     if (PyObject_SetAttr(output, parsedspec.attrname, fieldval) == -1) { | 
 | 873 |       Py_DECREF(fieldval); | 
 | 874 |       return false; | 
 | 875 |     } | 
 | 876 |     Py_DECREF(fieldval); | 
 | 877 |   } | 
 | 878 |   return true; | 
 | 879 | } | 
 | 880 |  | 
 | 881 |  | 
 | 882 | /* --- MAIN RECURSIVE INPUT FUCNTION --- */ | 
 | 883 |  | 
 | 884 | // Returns a new reference. | 
 | 885 | static PyObject* | 
 | 886 | decode_val(DecodeBuffer* input, TType type, PyObject* typeargs) { | 
 | 887 |   switch (type) { | 
 | 888 |  | 
 | 889 |   case T_BOOL: { | 
 | 890 |     int8_t v = readByte(input); | 
 | 891 |     if (INT_CONV_ERROR_OCCURRED(v)) { | 
 | 892 |       return NULL; | 
 | 893 |     } | 
 | 894 |  | 
 | 895 |     switch (v) { | 
 | 896 |     case 0: Py_RETURN_FALSE; | 
 | 897 |     case 1: Py_RETURN_TRUE; | 
 | 898 |     // Don't laugh.  This is a potentially serious issue. | 
 | 899 |     default: PyErr_SetString(PyExc_TypeError, "boolean out of range"); return NULL; | 
 | 900 |     } | 
 | 901 |     break; | 
 | 902 |   } | 
 | 903 |   case T_I08: { | 
 | 904 |     int8_t v = readByte(input); | 
 | 905 |     if (INT_CONV_ERROR_OCCURRED(v)) { | 
 | 906 |       return NULL; | 
 | 907 |     } | 
 | 908 |  | 
 | 909 |     return PyInt_FromLong(v); | 
 | 910 |   } | 
 | 911 |   case T_I16: { | 
 | 912 |     int16_t v = readI16(input); | 
 | 913 |     if (INT_CONV_ERROR_OCCURRED(v)) { | 
 | 914 |       return NULL; | 
 | 915 |     } | 
 | 916 |     return PyInt_FromLong(v); | 
 | 917 |   } | 
 | 918 |   case T_I32: { | 
 | 919 |     int32_t v = readI32(input); | 
 | 920 |     if (INT_CONV_ERROR_OCCURRED(v)) { | 
 | 921 |       return NULL; | 
 | 922 |     } | 
 | 923 |     return PyInt_FromLong(v); | 
 | 924 |   } | 
 | 925 |  | 
 | 926 |   case T_I64: { | 
 | 927 |     int64_t v = readI64(input); | 
 | 928 |     if (INT_CONV_ERROR_OCCURRED(v)) { | 
 | 929 |       return NULL; | 
 | 930 |     } | 
 | 931 |     // TODO(dreiss): Find out if we can take this fastpath always when | 
 | 932 |     //               sizeof(long) == sizeof(long long). | 
 | 933 |     if (CHECK_RANGE(v, LONG_MIN, LONG_MAX)) { | 
 | 934 |       return PyInt_FromLong((long) v); | 
 | 935 |     } | 
 | 936 |  | 
 | 937 |     return PyLong_FromLongLong(v); | 
 | 938 |   } | 
 | 939 |  | 
 | 940 |   case T_DOUBLE: { | 
 | 941 |     double v = readDouble(input); | 
 | 942 |     if (v == -1.0 && PyErr_Occurred()) { | 
 | 943 |       return false; | 
 | 944 |     } | 
 | 945 |     return PyFloat_FromDouble(v); | 
 | 946 |   } | 
 | 947 |  | 
 | 948 |   case T_STRING: { | 
 | 949 |     Py_ssize_t len = readI32(input); | 
 | 950 |     char* buf; | 
 | 951 |     if (!readBytes(input, &buf, len)) { | 
 | 952 |       return NULL; | 
 | 953 |     } | 
 | 954 |  | 
 | 955 |     return PyString_FromStringAndSize(buf, len); | 
 | 956 |   } | 
 | 957 |  | 
 | 958 |   case T_LIST: | 
 | 959 |   case T_SET: { | 
 | 960 |     SetListTypeArgs parsedargs; | 
 | 961 |     int32_t len; | 
 | 962 |     PyObject* ret = NULL; | 
 | 963 |     int i; | 
 | 964 |  | 
 | 965 |     if (!parse_set_list_args(&parsedargs, typeargs)) { | 
 | 966 |       return NULL; | 
 | 967 |     } | 
 | 968 |  | 
 | 969 |     if (!checkTypeByte(input, parsedargs.element_type)) { | 
 | 970 |       return NULL; | 
 | 971 |     } | 
 | 972 |  | 
 | 973 |     len = readI32(input); | 
 | 974 |     if (!check_ssize_t_32(len)) { | 
 | 975 |       return NULL; | 
 | 976 |     } | 
 | 977 |  | 
 | 978 |     ret = PyList_New(len); | 
 | 979 |     if (!ret) { | 
 | 980 |       return NULL; | 
 | 981 |     } | 
 | 982 |  | 
 | 983 |     for (i = 0; i < len; i++) { | 
 | 984 |       PyObject* item = decode_val(input, parsedargs.element_type, parsedargs.typeargs); | 
 | 985 |       if (!item) { | 
 | 986 |         Py_DECREF(ret); | 
 | 987 |         return NULL; | 
 | 988 |       } | 
 | 989 |       PyList_SET_ITEM(ret, i, item); | 
 | 990 |     } | 
 | 991 |  | 
 | 992 |     // TODO(dreiss): Consider biting the bullet and making two separate cases | 
 | 993 |     //               for list and set, avoiding this post facto conversion. | 
 | 994 |     if (type == T_SET) { | 
 | 995 |       PyObject* setret; | 
 | 996 | #if (PY_VERSION_HEX < 0x02050000) | 
 | 997 |       // hack needed for older versions | 
 | 998 |       setret = PyObject_CallFunctionObjArgs((PyObject*)&PySet_Type, ret, NULL); | 
 | 999 | #else | 
 | 1000 |       // official version | 
 | 1001 |       setret = PySet_New(ret); | 
 | 1002 | #endif | 
 | 1003 |       Py_DECREF(ret); | 
 | 1004 |       return setret; | 
 | 1005 |     } | 
 | 1006 |     return ret; | 
 | 1007 |   } | 
 | 1008 |  | 
 | 1009 |   case T_MAP: { | 
 | 1010 |     int32_t len; | 
 | 1011 |     int i; | 
 | 1012 |     MapTypeArgs parsedargs; | 
 | 1013 |     PyObject* ret = NULL; | 
 | 1014 |  | 
 | 1015 |     if (!parse_map_args(&parsedargs, typeargs)) { | 
 | 1016 |       return NULL; | 
 | 1017 |     } | 
 | 1018 |  | 
 | 1019 |     if (!checkTypeByte(input, parsedargs.ktag)) { | 
 | 1020 |       return NULL; | 
 | 1021 |     } | 
 | 1022 |     if (!checkTypeByte(input, parsedargs.vtag)) { | 
 | 1023 |       return NULL; | 
 | 1024 |     } | 
 | 1025 |  | 
 | 1026 |     len = readI32(input); | 
 | 1027 |     if (!check_ssize_t_32(len)) { | 
 | 1028 |       return false; | 
 | 1029 |     } | 
 | 1030 |  | 
 | 1031 |     ret = PyDict_New(); | 
 | 1032 |     if (!ret) { | 
 | 1033 |       goto error; | 
 | 1034 |     } | 
 | 1035 |  | 
 | 1036 |     for (i = 0; i < len; i++) { | 
 | 1037 |       PyObject* k = NULL; | 
 | 1038 |       PyObject* v = NULL; | 
 | 1039 |       k = decode_val(input, parsedargs.ktag, parsedargs.ktypeargs); | 
 | 1040 |       if (k == NULL) { | 
 | 1041 |         goto loop_error; | 
 | 1042 |       } | 
 | 1043 |       v = decode_val(input, parsedargs.vtag, parsedargs.vtypeargs); | 
 | 1044 |       if (v == NULL) { | 
 | 1045 |         goto loop_error; | 
 | 1046 |       } | 
 | 1047 |       if (PyDict_SetItem(ret, k, v) == -1) { | 
 | 1048 |         goto loop_error; | 
 | 1049 |       } | 
 | 1050 |  | 
 | 1051 |       Py_DECREF(k); | 
 | 1052 |       Py_DECREF(v); | 
 | 1053 |       continue; | 
 | 1054 |  | 
 | 1055 |       // Yuck!  Destructors, anyone? | 
 | 1056 |       loop_error: | 
 | 1057 |       Py_XDECREF(k); | 
 | 1058 |       Py_XDECREF(v); | 
 | 1059 |       goto error; | 
 | 1060 |     } | 
 | 1061 |  | 
 | 1062 |     return ret; | 
 | 1063 |  | 
 | 1064 |     error: | 
 | 1065 |     Py_XDECREF(ret); | 
 | 1066 |     return NULL; | 
 | 1067 |   } | 
 | 1068 |  | 
 | 1069 |   case T_STRUCT: { | 
 | 1070 |     StructTypeArgs parsedargs; | 
 | 1071 |     if (!parse_struct_args(&parsedargs, typeargs)) { | 
 | 1072 |       return NULL; | 
 | 1073 |     } | 
 | 1074 |  | 
 | 1075 |     PyObject* ret = PyObject_CallObject(parsedargs.klass, NULL); | 
 | 1076 |     if (!ret) { | 
 | 1077 |       return NULL; | 
 | 1078 |     } | 
 | 1079 |  | 
 | 1080 |     if (!decode_struct(input, ret, parsedargs.spec)) { | 
 | 1081 |       Py_DECREF(ret); | 
 | 1082 |       return NULL; | 
 | 1083 |     } | 
 | 1084 |  | 
 | 1085 |     return ret; | 
 | 1086 |   } | 
 | 1087 |  | 
 | 1088 |   case T_STOP: | 
 | 1089 |   case T_VOID: | 
 | 1090 |   case T_UTF16: | 
 | 1091 |   case T_UTF8: | 
 | 1092 |   case T_U64: | 
 | 1093 |   default: | 
 | 1094 |     PyErr_SetString(PyExc_TypeError, "Unexpected TType"); | 
 | 1095 |     return NULL; | 
 | 1096 |   } | 
 | 1097 | } | 
 | 1098 |  | 
 | 1099 |  | 
 | 1100 | /* --- TOP-LEVEL WRAPPER FOR INPUT -- */ | 
 | 1101 |  | 
 | 1102 | static PyObject* | 
 | 1103 | decode_binary(PyObject *self, PyObject *args) { | 
 | 1104 |   PyObject* output_obj = NULL; | 
 | 1105 |   PyObject* transport = NULL; | 
 | 1106 |   PyObject* typeargs = NULL; | 
 | 1107 |   StructTypeArgs parsedargs; | 
 | 1108 |   DecodeBuffer input = {}; | 
 | 1109 |  | 
 | 1110 |   if (!PyArg_ParseTuple(args, "OOO", &output_obj, &transport, &typeargs)) { | 
 | 1111 |     return NULL; | 
 | 1112 |   } | 
 | 1113 |  | 
 | 1114 |   if (!parse_struct_args(&parsedargs, typeargs)) { | 
 | 1115 |     return NULL; | 
 | 1116 |   } | 
 | 1117 |  | 
 | 1118 |   if (!decode_buffer_from_obj(&input, transport)) { | 
 | 1119 |     return NULL; | 
 | 1120 |   } | 
 | 1121 |  | 
 | 1122 |   if (!decode_struct(&input, output_obj, parsedargs.spec)) { | 
 | 1123 |     free_decodebuf(&input); | 
 | 1124 |     return NULL; | 
 | 1125 |   } | 
 | 1126 |  | 
 | 1127 |   free_decodebuf(&input); | 
 | 1128 |  | 
 | 1129 |   Py_RETURN_NONE; | 
 | 1130 | } | 
 | 1131 |  | 
 | 1132 | /* ====== END READING FUNCTIONS ====== */ | 
 | 1133 |  | 
 | 1134 |  | 
 | 1135 | /* -- PYTHON MODULE SETUP STUFF --- */ | 
 | 1136 |  | 
 | 1137 | static PyMethodDef ThriftFastBinaryMethods[] = { | 
 | 1138 |  | 
 | 1139 |   {"encode_binary",  encode_binary, METH_VARARGS, ""}, | 
 | 1140 |   {"decode_binary",  decode_binary, METH_VARARGS, ""}, | 
 | 1141 |  | 
 | 1142 |   {NULL, NULL, 0, NULL}        /* Sentinel */ | 
 | 1143 | }; | 
 | 1144 |  | 
 | 1145 | PyMODINIT_FUNC | 
 | 1146 | initfastbinary(void) { | 
 | 1147 | #define INIT_INTERN_STRING(value) \ | 
 | 1148 |   do { \ | 
 | 1149 |     INTERN_STRING(value) = PyString_InternFromString(#value); \ | 
 | 1150 |     if(!INTERN_STRING(value)) return; \ | 
 | 1151 |   } while(0) | 
 | 1152 |  | 
 | 1153 |   INIT_INTERN_STRING(cstringio_buf); | 
 | 1154 |   INIT_INTERN_STRING(cstringio_refill); | 
 | 1155 | #undef INIT_INTERN_STRING | 
 | 1156 |  | 
 | 1157 |   PycString_IMPORT; | 
 | 1158 |   if (PycStringIO == NULL) return; | 
 | 1159 |  | 
 | 1160 |   (void) Py_InitModule("thrift.protocol.fastbinary", ThriftFastBinaryMethods); | 
 | 1161 | } |