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