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