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