Subversion Repositories SmartDukaan

Rev

Rev 30 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 ashish 1
/*
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
 */
19
 
20
#include <Python.h>
21
#include "cStringIO.h"
22
#include <stdbool.h>
23
#include <stdint.h>
24
#include <netinet/in.h>
25
 
26
/* 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
 
45
// 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.
58
typedef 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
 
79
#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
 
89
// 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
 
112
// Py_ssize_t was not defined before Python 2.5
113
#if (PY_VERSION_HEX < 0x02050000)
114
typedef int Py_ssize_t;
115
#endif
116
 
117
/**
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
 */
121
typedef 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
 */
130
typedef 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
 */
141
typedef 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
 */
150
typedef 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
 */
162
typedef struct {
163
  PyObject* stringiobuf;
164
  PyObject* refill_callable;
165
} DecodeBuffer;
166
 
167
/** Pointer to interned string to speed up attribute lookup. */
168
static PyObject* INTERN_STRING(cstringio_buf);
169
/** Pointer to interned string to speed up attribute lookup. */
170
static PyObject* INTERN_STRING(cstringio_refill);
171
 
172
static inline bool
173
check_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
 
185
static inline bool
186
parse_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
 
204
static bool
205
parse_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
 
221
static bool
222
parse_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
 
244
static bool
245
parse_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
 
257
static int
258
parse_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
 
289
static void writeByte(PyObject* outbuf, int8_t val) {
290
  int8_t net = val;
291
  PycStringIO->cwrite(outbuf, (char*)&net, sizeof(int8_t));
292
}
293
 
294
static 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
 
299
static 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
 
304
static 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
 
309
static 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
 
322
static int
323
output_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;
458
    Py_ssize_t pos = 0;
459
    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
      }
489
      Py_DECREF(k);
490
      Py_DECREF(v);
491
    }
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
 
569
static PyObject *
570
encode_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
 
596
static void
597
free_decodebuf(DecodeBuffer* d) {
598
  Py_XDECREF(d->stringiobuf);
599
  Py_XDECREF(d->refill_callable);
600
}
601
 
602
static bool
603
decode_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
 
631
static 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(
649
        input->refill_callable, "s#i", *output, read, len, NULL);
650
    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
 
673
static 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
 
682
static 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
 
691
static 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
 
700
static 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
 
709
static 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
 
722
static bool
723
checkTypeByte(DecodeBuffer* input, TType expected) {
724
  TType got = readByte(input);
725
  if (INT_CONV_ERROR_OCCURRED(got)) {
726
    return false;
727
  }
728
 
729
  if (expected != got) {
730
    PyErr_SetString(PyExc_TypeError, "got wrong ttype while reading field");
731
    return false;
732
  }
733
  return true;
734
}
735
 
736
static bool
737
skip(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
 
847
  return true;
848
 
849
#undef SKIPBYTES
850
}
851
 
852
 
853
/* --- HELPER FUNCTION FOR DECODE_VAL --- */
854
 
855
static PyObject*
856
decode_val(DecodeBuffer* input, TType type, PyObject* typeargs);
857
 
858
static bool
859
decode_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);
873
    if (type == -1) {
874
      return false;
875
    }
876
    if (type == T_STOP) {
877
      break;
878
    }
879
    tag = readI16(input);
880
    if (INT_CONV_ERROR_OCCURRED(tag)) {
881
      return false;
882
    }
883
    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;
892
      } else {
893
        continue;
894
      }
895
    }
896
 
897
    if (!parse_struct_item_spec(&parsedspec, item_spec)) {
898
      return false;
899
    }
900
    if (parsedspec.type != type) {
901
      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
      }
907
    }
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.
927
static PyObject*
928
decode_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
 
1144
static PyObject*
1145
decode_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
 
1179
static 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
 
1187
PyMODINIT_FUNC
1188
initfastbinary(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
}