blob: 5625f4b4f8e95a7957b59077aa2abdf78d26b583 [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
David Reiss5ec8e262007-08-26 02:21:24 +000076// Py_ssize_t was not defined before Python 2.5
77#if (PY_VERSION_HEX < 0x02050000)
78typedef int Py_ssize_t;
79#endif
80
David Reiss382fc302007-08-25 18:01:30 +000081/**
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 */
85typedef 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 */
94typedef 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 */
105typedef 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 */
114typedef 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 */
126typedef struct {
127 PyObject* stringiobuf;
128 PyObject* refill_callable;
129} DecodeBuffer;
130
131/** Pointer to interned string to speed up attribute lookup. */
132static PyObject* INTERN_STRING(cstringio_buf);
133/** Pointer to interned string to speed up attribute lookup. */
134static PyObject* INTERN_STRING(cstringio_refill);
135
136static inline bool
137check_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
149static inline bool
150parse_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
168static bool
169parse_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
185static bool
186parse_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
208static bool
209parse_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
221static int
222parse_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
253static void writeByte(PyObject* outbuf, int8_t val) {
254 int8_t net = val;
255 PycStringIO->cwrite(outbuf, (char*)&net, sizeof(int8_t));
256}
257
258static 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
263static 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
268static 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
273static 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
286static int
287output_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
531static PyObject *
532encode_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
558static void
559free_decodebuf(DecodeBuffer* d) {
560 Py_XDECREF(d->stringiobuf);
561 Py_XDECREF(d->refill_callable);
562}
563
564static bool
565decode_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
593static 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 Reiss2c2e6d22007-09-05 01:14:09 +0000611 input->refill_callable, "s#i", *output, read, len, NULL);
David Reiss382fc302007-08-25 18:01:30 +0000612 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
635static 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
644static 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
653static 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
662static 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
671static 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
684static bool
685checkTypeByte(DecodeBuffer* input, TType expected) {
686 TType got = readByte(input);
Mark Slee53d9c0c2007-11-26 21:15:40 +0000687 if (INT_CONV_ERROR_OCCURRED(got)) {
688 return false;
689 }
David Reiss382fc302007-08-25 18:01:30 +0000690
691 if (expected != got) {
692 PyErr_SetString(PyExc_TypeError, "got wrong ttype while reading field");
693 return false;
694 }
695 return true;
696}
697
698static bool
699skip(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 Reissbc444b02008-02-14 20:20:08 +0000809 return true;
David Reiss382fc302007-08-25 18:01:30 +0000810
811#undef SKIPBYTES
812}
813
814
815/* --- HELPER FUNCTION FOR DECODE_VAL --- */
816
817static PyObject*
818decode_val(DecodeBuffer* input, TType type, PyObject* typeargs);
819
820static bool
821decode_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 Slee53d9c0c2007-11-26 21:15:40 +0000835 if (type == -1) {
836 return false;
837 }
David Reiss382fc302007-08-25 18:01:30 +0000838 if (type == T_STOP) {
839 break;
840 }
841 tag = readI16(input);
Mark Slee53d9c0c2007-11-26 21:15:40 +0000842 if (INT_CONV_ERROR_OCCURRED(tag)) {
843 return false;
844 }
David Reiss382fc302007-08-25 18:01:30 +0000845 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 Reissbc444b02008-02-14 20:20:08 +0000854 } else {
855 continue;
David Reiss382fc302007-08-25 18:01:30 +0000856 }
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.
885static PyObject*
886decode_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
1102static PyObject*
1103decode_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
1137static 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
1145PyMODINIT_FUNC
1146initfastbinary(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}