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