blob: 71c0f8d4c4ca5311ababa6c138021404df19cce8 [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 }
482 }
483 break;
484 }
485
486 // TODO(dreiss): Consider breaking this out as a function
487 // the way we did for decode_struct.
488 case T_STRUCT: {
489 StructTypeArgs parsedargs;
490 Py_ssize_t nspec;
491 Py_ssize_t i;
492
493 if (!parse_struct_args(&parsedargs, typeargs)) {
494 return false;
495 }
496
497 nspec = PyTuple_Size(parsedargs.spec);
498
499 if (nspec == -1) {
500 return false;
501 }
502
503 for (i = 0; i < nspec; i++) {
504 StructItemSpec parsedspec;
505 PyObject* spec_tuple;
506 PyObject* instval = NULL;
507
508 spec_tuple = PyTuple_GET_ITEM(parsedargs.spec, i);
509 if (spec_tuple == Py_None) {
510 continue;
511 }
512
513 if (!parse_struct_item_spec (&parsedspec, spec_tuple)) {
514 return false;
515 }
516
517 instval = PyObject_GetAttr(value, parsedspec.attrname);
518
519 if (!instval) {
520 return false;
521 }
522
523 if (instval == Py_None) {
524 Py_DECREF(instval);
525 continue;
526 }
527
528 writeByte(output, (int8_t) parsedspec.type);
529 writeI16(output, parsedspec.tag);
530
531 if (!output_val(output, instval, parsedspec.type, parsedspec.typeargs)) {
532 Py_DECREF(instval);
533 return false;
534 }
535
536 Py_DECREF(instval);
537 }
538
539 writeByte(output, (int8_t)T_STOP);
540 break;
541 }
542
543 case T_STOP:
544 case T_VOID:
545 case T_UTF16:
546 case T_UTF8:
547 case T_U64:
548 default:
549 PyErr_SetString(PyExc_TypeError, "Unexpected TType");
550 return false;
551
552 }
553
554 return true;
555}
556
557
558/* --- TOP-LEVEL WRAPPER FOR OUTPUT -- */
559
560static PyObject *
561encode_binary(PyObject *self, PyObject *args) {
562 PyObject* enc_obj;
563 PyObject* type_args;
564 PyObject* buf;
565 PyObject* ret = NULL;
566
567 if (!PyArg_ParseTuple(args, "OO", &enc_obj, &type_args)) {
568 return NULL;
569 }
570
571 buf = PycStringIO->NewOutput(INIT_OUTBUF_SIZE);
572 if (output_val(buf, enc_obj, T_STRUCT, type_args)) {
573 ret = PycStringIO->cgetvalue(buf);
574 }
575
576 Py_DECREF(buf);
577 return ret;
578}
579
580/* ====== END WRITING FUNCTIONS ====== */
581
582
583/* ====== BEGIN READING FUNCTIONS ====== */
584
585/* --- LOW-LEVEL READING FUNCTIONS --- */
586
587static void
588free_decodebuf(DecodeBuffer* d) {
589 Py_XDECREF(d->stringiobuf);
590 Py_XDECREF(d->refill_callable);
591}
592
593static bool
594decode_buffer_from_obj(DecodeBuffer* dest, PyObject* obj) {
595 dest->stringiobuf = PyObject_GetAttr(obj, INTERN_STRING(cstringio_buf));
596 if (!dest->stringiobuf) {
597 return false;
598 }
599
600 if (!PycStringIO_InputCheck(dest->stringiobuf)) {
601 free_decodebuf(dest);
602 PyErr_SetString(PyExc_TypeError, "expecting stringio input");
603 return false;
604 }
605
606 dest->refill_callable = PyObject_GetAttr(obj, INTERN_STRING(cstringio_refill));
607
608 if(!dest->refill_callable) {
609 free_decodebuf(dest);
610 return false;
611 }
612
613 if (!PyCallable_Check(dest->refill_callable)) {
614 free_decodebuf(dest);
615 PyErr_SetString(PyExc_TypeError, "expecting callable");
616 return false;
617 }
618
619 return true;
620}
621
622static bool readBytes(DecodeBuffer* input, char** output, int len) {
623 int read;
624
625 // TODO(dreiss): Don't fear the malloc. Think about taking a copy of
626 // the partial read instead of forcing the transport
627 // to prepend it to its buffer.
628
629 read = PycStringIO->cread(input->stringiobuf, output, len);
630
631 if (read == len) {
632 return true;
633 } else if (read == -1) {
634 return false;
635 } else {
636 PyObject* newiobuf;
637
638 // using building functions as this is a rare codepath
639 newiobuf = PyObject_CallFunction(
David Reiss2c2e6d22007-09-05 01:14:09 +0000640 input->refill_callable, "s#i", *output, read, len, NULL);
David Reiss382fc302007-08-25 18:01:30 +0000641 if (newiobuf == NULL) {
642 return false;
643 }
644
645 // must do this *AFTER* the call so that we don't deref the io buffer
646 Py_CLEAR(input->stringiobuf);
647 input->stringiobuf = newiobuf;
648
649 read = PycStringIO->cread(input->stringiobuf, output, len);
650
651 if (read == len) {
652 return true;
653 } else if (read == -1) {
654 return false;
655 } else {
656 // TODO(dreiss): This could be a valid code path for big binary blobs.
657 PyErr_SetString(PyExc_TypeError,
658 "refill claimed to have refilled the buffer, but didn't!!");
659 return false;
660 }
661 }
662}
663
664static int8_t readByte(DecodeBuffer* input) {
665 char* buf;
666 if (!readBytes(input, &buf, sizeof(int8_t))) {
667 return -1;
668 }
669
670 return *(int8_t*) buf;
671}
672
673static int16_t readI16(DecodeBuffer* input) {
674 char* buf;
675 if (!readBytes(input, &buf, sizeof(int16_t))) {
676 return -1;
677 }
678
679 return (int16_t) ntohs(*(int16_t*) buf);
680}
681
682static int32_t readI32(DecodeBuffer* input) {
683 char* buf;
684 if (!readBytes(input, &buf, sizeof(int32_t))) {
685 return -1;
686 }
687 return (int32_t) ntohl(*(int32_t*) buf);
688}
689
690
691static int64_t readI64(DecodeBuffer* input) {
692 char* buf;
693 if (!readBytes(input, &buf, sizeof(int64_t))) {
694 return -1;
695 }
696
697 return (int64_t) ntohll(*(int64_t*) buf);
698}
699
700static double readDouble(DecodeBuffer* input) {
701 union {
702 int64_t f;
703 double t;
704 } transfer;
705
706 transfer.f = readI64(input);
707 if (transfer.f == -1) {
708 return -1;
709 }
710 return transfer.t;
711}
712
713static bool
714checkTypeByte(DecodeBuffer* input, TType expected) {
715 TType got = readByte(input);
Mark Slee53d9c0c2007-11-26 21:15:40 +0000716 if (INT_CONV_ERROR_OCCURRED(got)) {
717 return false;
718 }
David Reiss382fc302007-08-25 18:01:30 +0000719
720 if (expected != got) {
721 PyErr_SetString(PyExc_TypeError, "got wrong ttype while reading field");
722 return false;
723 }
724 return true;
725}
726
727static bool
728skip(DecodeBuffer* input, TType type) {
729#define SKIPBYTES(n) \
730 do { \
731 if (!readBytes(input, &dummy_buf, (n))) { \
732 return false; \
733 } \
734 } while(0)
735
736 char* dummy_buf;
737
738 switch (type) {
739
740 case T_BOOL:
741 case T_I08: SKIPBYTES(1); break;
742 case T_I16: SKIPBYTES(2); break;
743 case T_I32: SKIPBYTES(4); break;
744 case T_I64:
745 case T_DOUBLE: SKIPBYTES(8); break;
746
747 case T_STRING: {
748 // TODO(dreiss): Find out if these check_ssize_t32s are really necessary.
749 int len = readI32(input);
750 if (!check_ssize_t_32(len)) {
751 return false;
752 }
753 SKIPBYTES(len);
754 break;
755 }
756
757 case T_LIST:
758 case T_SET: {
759 TType etype;
760 int len, i;
761
762 etype = readByte(input);
763 if (etype == -1) {
764 return false;
765 }
766
767 len = readI32(input);
768 if (!check_ssize_t_32(len)) {
769 return false;
770 }
771
772 for (i = 0; i < len; i++) {
773 if (!skip(input, etype)) {
774 return false;
775 }
776 }
777 break;
778 }
779
780 case T_MAP: {
781 TType ktype, vtype;
782 int len, i;
783
784 ktype = readByte(input);
785 if (ktype == -1) {
786 return false;
787 }
788
789 vtype = readByte(input);
790 if (vtype == -1) {
791 return false;
792 }
793
794 len = readI32(input);
795 if (!check_ssize_t_32(len)) {
796 return false;
797 }
798
799 for (i = 0; i < len; i++) {
800 if (!(skip(input, ktype) && skip(input, vtype))) {
801 return false;
802 }
803 }
804 break;
805 }
806
807 case T_STRUCT: {
808 while (true) {
809 TType type;
810
811 type = readByte(input);
812 if (type == -1) {
813 return false;
814 }
815
816 if (type == T_STOP)
817 break;
818
819 SKIPBYTES(2); // tag
820 if (!skip(input, type)) {
821 return false;
822 }
823 }
824 break;
825 }
826
827 case T_STOP:
828 case T_VOID:
829 case T_UTF16:
830 case T_UTF8:
831 case T_U64:
832 default:
833 PyErr_SetString(PyExc_TypeError, "Unexpected TType");
834 return false;
835
836 }
837
David Reissbc444b02008-02-14 20:20:08 +0000838 return true;
David Reiss382fc302007-08-25 18:01:30 +0000839
840#undef SKIPBYTES
841}
842
843
844/* --- HELPER FUNCTION FOR DECODE_VAL --- */
845
846static PyObject*
847decode_val(DecodeBuffer* input, TType type, PyObject* typeargs);
848
849static bool
850decode_struct(DecodeBuffer* input, PyObject* output, PyObject* spec_seq) {
851 int spec_seq_len = PyTuple_Size(spec_seq);
852 if (spec_seq_len == -1) {
853 return false;
854 }
855
856 while (true) {
857 TType type;
858 int16_t tag;
859 PyObject* item_spec;
860 PyObject* fieldval = NULL;
861 StructItemSpec parsedspec;
862
863 type = readByte(input);
Mark Slee53d9c0c2007-11-26 21:15:40 +0000864 if (type == -1) {
865 return false;
866 }
David Reiss382fc302007-08-25 18:01:30 +0000867 if (type == T_STOP) {
868 break;
869 }
870 tag = readI16(input);
Mark Slee53d9c0c2007-11-26 21:15:40 +0000871 if (INT_CONV_ERROR_OCCURRED(tag)) {
872 return false;
873 }
David Reiss382fc302007-08-25 18:01:30 +0000874 if (tag >= 0 && tag < spec_seq_len) {
875 item_spec = PyTuple_GET_ITEM(spec_seq, tag);
876 } else {
877 item_spec = Py_None;
878 }
879
880 if (item_spec == Py_None) {
881 if (!skip(input, type)) {
882 return false;
David Reissbc444b02008-02-14 20:20:08 +0000883 } else {
884 continue;
David Reiss382fc302007-08-25 18:01:30 +0000885 }
886 }
887
888 if (!parse_struct_item_spec(&parsedspec, item_spec)) {
889 return false;
890 }
891 if (parsedspec.type != type) {
892 PyErr_SetString(PyExc_TypeError, "struct field had wrong type while reading");
893 return false;
894 }
895
896 fieldval = decode_val(input, parsedspec.type, parsedspec.typeargs);
897 if (fieldval == NULL) {
898 return false;
899 }
900
901 if (PyObject_SetAttr(output, parsedspec.attrname, fieldval) == -1) {
902 Py_DECREF(fieldval);
903 return false;
904 }
905 Py_DECREF(fieldval);
906 }
907 return true;
908}
909
910
911/* --- MAIN RECURSIVE INPUT FUCNTION --- */
912
913// Returns a new reference.
914static PyObject*
915decode_val(DecodeBuffer* input, TType type, PyObject* typeargs) {
916 switch (type) {
917
918 case T_BOOL: {
919 int8_t v = readByte(input);
920 if (INT_CONV_ERROR_OCCURRED(v)) {
921 return NULL;
922 }
923
924 switch (v) {
925 case 0: Py_RETURN_FALSE;
926 case 1: Py_RETURN_TRUE;
927 // Don't laugh. This is a potentially serious issue.
928 default: PyErr_SetString(PyExc_TypeError, "boolean out of range"); return NULL;
929 }
930 break;
931 }
932 case T_I08: {
933 int8_t v = readByte(input);
934 if (INT_CONV_ERROR_OCCURRED(v)) {
935 return NULL;
936 }
937
938 return PyInt_FromLong(v);
939 }
940 case T_I16: {
941 int16_t v = readI16(input);
942 if (INT_CONV_ERROR_OCCURRED(v)) {
943 return NULL;
944 }
945 return PyInt_FromLong(v);
946 }
947 case T_I32: {
948 int32_t v = readI32(input);
949 if (INT_CONV_ERROR_OCCURRED(v)) {
950 return NULL;
951 }
952 return PyInt_FromLong(v);
953 }
954
955 case T_I64: {
956 int64_t v = readI64(input);
957 if (INT_CONV_ERROR_OCCURRED(v)) {
958 return NULL;
959 }
960 // TODO(dreiss): Find out if we can take this fastpath always when
961 // sizeof(long) == sizeof(long long).
962 if (CHECK_RANGE(v, LONG_MIN, LONG_MAX)) {
963 return PyInt_FromLong((long) v);
964 }
965
966 return PyLong_FromLongLong(v);
967 }
968
969 case T_DOUBLE: {
970 double v = readDouble(input);
971 if (v == -1.0 && PyErr_Occurred()) {
972 return false;
973 }
974 return PyFloat_FromDouble(v);
975 }
976
977 case T_STRING: {
978 Py_ssize_t len = readI32(input);
979 char* buf;
980 if (!readBytes(input, &buf, len)) {
981 return NULL;
982 }
983
984 return PyString_FromStringAndSize(buf, len);
985 }
986
987 case T_LIST:
988 case T_SET: {
989 SetListTypeArgs parsedargs;
990 int32_t len;
991 PyObject* ret = NULL;
992 int i;
993
994 if (!parse_set_list_args(&parsedargs, typeargs)) {
995 return NULL;
996 }
997
998 if (!checkTypeByte(input, parsedargs.element_type)) {
999 return NULL;
1000 }
1001
1002 len = readI32(input);
1003 if (!check_ssize_t_32(len)) {
1004 return NULL;
1005 }
1006
1007 ret = PyList_New(len);
1008 if (!ret) {
1009 return NULL;
1010 }
1011
1012 for (i = 0; i < len; i++) {
1013 PyObject* item = decode_val(input, parsedargs.element_type, parsedargs.typeargs);
1014 if (!item) {
1015 Py_DECREF(ret);
1016 return NULL;
1017 }
1018 PyList_SET_ITEM(ret, i, item);
1019 }
1020
1021 // TODO(dreiss): Consider biting the bullet and making two separate cases
1022 // for list and set, avoiding this post facto conversion.
1023 if (type == T_SET) {
1024 PyObject* setret;
1025#if (PY_VERSION_HEX < 0x02050000)
1026 // hack needed for older versions
1027 setret = PyObject_CallFunctionObjArgs((PyObject*)&PySet_Type, ret, NULL);
1028#else
1029 // official version
1030 setret = PySet_New(ret);
1031#endif
1032 Py_DECREF(ret);
1033 return setret;
1034 }
1035 return ret;
1036 }
1037
1038 case T_MAP: {
1039 int32_t len;
1040 int i;
1041 MapTypeArgs parsedargs;
1042 PyObject* ret = NULL;
1043
1044 if (!parse_map_args(&parsedargs, typeargs)) {
1045 return NULL;
1046 }
1047
1048 if (!checkTypeByte(input, parsedargs.ktag)) {
1049 return NULL;
1050 }
1051 if (!checkTypeByte(input, parsedargs.vtag)) {
1052 return NULL;
1053 }
1054
1055 len = readI32(input);
1056 if (!check_ssize_t_32(len)) {
1057 return false;
1058 }
1059
1060 ret = PyDict_New();
1061 if (!ret) {
1062 goto error;
1063 }
1064
1065 for (i = 0; i < len; i++) {
1066 PyObject* k = NULL;
1067 PyObject* v = NULL;
1068 k = decode_val(input, parsedargs.ktag, parsedargs.ktypeargs);
1069 if (k == NULL) {
1070 goto loop_error;
1071 }
1072 v = decode_val(input, parsedargs.vtag, parsedargs.vtypeargs);
1073 if (v == NULL) {
1074 goto loop_error;
1075 }
1076 if (PyDict_SetItem(ret, k, v) == -1) {
1077 goto loop_error;
1078 }
1079
1080 Py_DECREF(k);
1081 Py_DECREF(v);
1082 continue;
1083
1084 // Yuck! Destructors, anyone?
1085 loop_error:
1086 Py_XDECREF(k);
1087 Py_XDECREF(v);
1088 goto error;
1089 }
1090
1091 return ret;
1092
1093 error:
1094 Py_XDECREF(ret);
1095 return NULL;
1096 }
1097
1098 case T_STRUCT: {
1099 StructTypeArgs parsedargs;
1100 if (!parse_struct_args(&parsedargs, typeargs)) {
1101 return NULL;
1102 }
1103
1104 PyObject* ret = PyObject_CallObject(parsedargs.klass, NULL);
1105 if (!ret) {
1106 return NULL;
1107 }
1108
1109 if (!decode_struct(input, ret, parsedargs.spec)) {
1110 Py_DECREF(ret);
1111 return NULL;
1112 }
1113
1114 return ret;
1115 }
1116
1117 case T_STOP:
1118 case T_VOID:
1119 case T_UTF16:
1120 case T_UTF8:
1121 case T_U64:
1122 default:
1123 PyErr_SetString(PyExc_TypeError, "Unexpected TType");
1124 return NULL;
1125 }
1126}
1127
1128
1129/* --- TOP-LEVEL WRAPPER FOR INPUT -- */
1130
1131static PyObject*
1132decode_binary(PyObject *self, PyObject *args) {
1133 PyObject* output_obj = NULL;
1134 PyObject* transport = NULL;
1135 PyObject* typeargs = NULL;
1136 StructTypeArgs parsedargs;
1137 DecodeBuffer input = {};
1138
1139 if (!PyArg_ParseTuple(args, "OOO", &output_obj, &transport, &typeargs)) {
1140 return NULL;
1141 }
1142
1143 if (!parse_struct_args(&parsedargs, typeargs)) {
1144 return NULL;
1145 }
1146
1147 if (!decode_buffer_from_obj(&input, transport)) {
1148 return NULL;
1149 }
1150
1151 if (!decode_struct(&input, output_obj, parsedargs.spec)) {
1152 free_decodebuf(&input);
1153 return NULL;
1154 }
1155
1156 free_decodebuf(&input);
1157
1158 Py_RETURN_NONE;
1159}
1160
1161/* ====== END READING FUNCTIONS ====== */
1162
1163
1164/* -- PYTHON MODULE SETUP STUFF --- */
1165
1166static PyMethodDef ThriftFastBinaryMethods[] = {
1167
1168 {"encode_binary", encode_binary, METH_VARARGS, ""},
1169 {"decode_binary", decode_binary, METH_VARARGS, ""},
1170
1171 {NULL, NULL, 0, NULL} /* Sentinel */
1172};
1173
1174PyMODINIT_FUNC
1175initfastbinary(void) {
1176#define INIT_INTERN_STRING(value) \
1177 do { \
1178 INTERN_STRING(value) = PyString_InternFromString(#value); \
1179 if(!INTERN_STRING(value)) return; \
1180 } while(0)
1181
1182 INIT_INTERN_STRING(cstringio_buf);
1183 INIT_INTERN_STRING(cstringio_refill);
1184#undef INIT_INTERN_STRING
1185
1186 PycString_IMPORT;
1187 if (PycStringIO == NULL) return;
1188
1189 (void) Py_InitModule("thrift.protocol.fastbinary", ThriftFastBinaryMethods);
1190}