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 <string.h>
21 #include <stdio.h>
22 
23 #include <thrift/c_glib/thrift.h>
24 #include <thrift/c_glib/protocol/thrift_protocol.h>
25 #include <thrift/c_glib/protocol/thrift_compact_protocol.h>
26 
27 #include <thrift/config.h>
28 
29 /*
30  * *_to_zigzag depend on the fact that the right shift
31  * operator on a signed integer is an arithmetic (sign-extending) shift.
32  * If this is not the case, the current implementation will not work.
33  */
34 #if !defined(SIGNED_RIGHT_SHIFT_IS) || !defined(ARITHMETIC_RIGHT_SHIFT)
35 # error "Unable to determine the behavior of a signed right shift"
36 #endif
37 #if SIGNED_RIGHT_SHIFT_IS != ARITHMETIC_RIGHT_SHIFT
38 # error "thrift_compact_protocol only works if signed right shift is arithmetic"
39 #endif
40 
41 /* object properties */
42 enum _ThriftCompactProtocolProperties
43 {
44     PROP_0,
45     PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT,
46     PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT
47 };
48 
49 G_DEFINE_TYPE (ThriftCompactProtocol, thrift_compact_protocol,
50                THRIFT_TYPE_PROTOCOL)
51 
52 static const gint8 PROTOCOL_ID = (gint8)0x82u;
53 static const gint8 VERSION_N = 1;
54 static const gint8 VERSION_MASK = 0x1f;       /* 0001 1111 */
55 static const gint8 TYPE_MASK = (gint8)0xe0u;  /* 1110 0000 */
56 static const gint8 TYPE_BITS = 0x07;          /* 0000 0111 */
57 static const gint32 TYPE_SHIFT_AMOUNT = 5;
58 
59 enum Types {
60   CT_STOP           = 0x00,
61   CT_BOOLEAN_TRUE   = 0x01,
62   CT_BOOLEAN_FALSE  = 0x02,
63   CT_BYTE           = 0x03,
64   CT_I16            = 0x04,
65   CT_I32            = 0x05,
66   CT_I64            = 0x06,
67   CT_DOUBLE         = 0x07,
68   CT_BINARY         = 0x08,
69   CT_LIST           = 0x09,
70   CT_SET            = 0x0A,
71   CT_MAP            = 0x0B,
72   CT_STRUCT         = 0x0C
73 };
74 
75 static const gint8 TTypeToCType[16] = {
76   CT_STOP, /* T_STOP */
77   0, /* unused */
78   CT_BOOLEAN_TRUE, /* T_BOOL */
79   CT_BYTE, /* T_BYTE */
80   CT_DOUBLE, /* T_DOUBLE */
81   0, /* unused */
82   CT_I16, /* T_I16 */
83   0, /* unused */
84   CT_I32, /* T_I32 */
85   0, /* unused */
86   CT_I64, /* T_I64 */
87   CT_BINARY, /* T_STRING */
88   CT_STRUCT, /* T_STRUCT */
89   CT_MAP, /* T_MAP */
90   CT_SET, /* T_SET */
91   CT_LIST, /* T_LIST */
92 };
93 
94 static guint64
thrift_bitwise_cast_guint64(const gdouble v)95 thrift_bitwise_cast_guint64 (const gdouble v)
96 {
97   union {
98     gdouble from;
99     guint64 to;
100   } u;
101   u.from = v;
102   return u.to;
103 }
104 
105 static gdouble
thrift_bitwise_cast_gdouble(const guint64 v)106 thrift_bitwise_cast_gdouble (const guint64 v)
107 {
108   union {
109     guint64 from;
110     gdouble to;
111   } u;
112   u.from = v;
113   return u.to;
114 }
115 
116 /**
117  * Convert l into a zigzag long. This allows negative numbers to be
118  * represented compactly as a varint.
119  */
120 static guint64
i64_to_zigzag(const gint64 l)121 i64_to_zigzag (const gint64 l)
122 {
123   return (((guint64)l) << 1) ^ (l >> 63);
124 }
125 
126 /**
127  * Convert n into a zigzag int. This allows negative numbers to be
128  * represented compactly as a varint.
129  */
130 static guint32
i32_to_zigzag(const gint32 n)131 i32_to_zigzag (const gint32 n)
132 {
133   return (((guint32)n) << 1) ^ (n >> 31);
134 }
135 
136 /**
137  * Convert from zigzag int to int.
138  */
139 static gint32
zigzag_to_i32(guint32 n)140 zigzag_to_i32 (guint32 n)
141 {
142   return (n >> 1) ^ (guint32) (-(gint32) (n & 1));
143 }
144 
145 /**
146  * Convert from zigzag long to long.
147  */
148 static gint64
zigzag_to_i64(guint64 n)149 zigzag_to_i64 (guint64 n)
150 {
151   return (n >> 1) ^ (guint64) (-(gint64) (n & 1));
152 }
153 
thrift_compact_protocol_get_ttype(ThriftCompactProtocol * protocol,const gint8 type,GError ** error)154 ThriftType thrift_compact_protocol_get_ttype (ThriftCompactProtocol *protocol,
155                                               const gint8 type, GError **error)
156 {
157   THRIFT_UNUSED_VAR (protocol);
158 
159   switch (type) {
160     case T_STOP:
161       return T_STOP;
162     case CT_BOOLEAN_FALSE:
163     case CT_BOOLEAN_TRUE:
164       return T_BOOL;
165     case CT_BYTE:
166       return T_BYTE;
167     case CT_I16:
168       return T_I16;
169     case CT_I32:
170       return T_I32;
171     case CT_I64:
172       return T_I64;
173     case CT_DOUBLE:
174       return T_DOUBLE;
175     case CT_BINARY:
176       return T_STRING;
177     case CT_LIST:
178       return T_LIST;
179     case CT_SET:
180       return T_SET;
181     case CT_MAP:
182       return T_MAP;
183     case CT_STRUCT:
184       return T_STRUCT;
185     default:
186       g_set_error (error, THRIFT_PROTOCOL_ERROR,
187                    THRIFT_PROTOCOL_ERROR_INVALID_DATA,
188                    "unrecognized type");
189       return -1;
190   }
191 }
192 
193 /**
194  * Write an i32 as a varint. Results in 1-5 bytes on the wire.
195  */
196 gint32
thrift_compact_protocol_write_varint32(ThriftCompactProtocol * protocol,const guint32 n,GError ** error)197 thrift_compact_protocol_write_varint32 (ThriftCompactProtocol *protocol,
198                                         const guint32 n,
199                                         GError **error)
200 {
201   guint8 buf[5];
202   gint32 xfer;
203   guint32 m;
204 
205   THRIFT_UNUSED_VAR (error);
206 
207   xfer = 0;
208   m = n;
209 
210   while (TRUE) {
211     if ((m & ~0x7F) == 0) {
212       buf[xfer++] = (gint8)m;
213       break;
214     } else {
215       buf[xfer++] = (gint8)((m & 0x7F) | 0x80);
216       m >>= 7;
217     }
218   }
219 
220   if (thrift_transport_write (THRIFT_PROTOCOL (protocol)->transport,
221                               (const gpointer) buf, xfer, error)) {
222     return xfer;
223   } else {
224     return -1;
225   }
226 }
227 
228 /**
229  * Write an i64 as a varint. Results in 1-10 bytes on the wire.
230  */
231 gint32
thrift_compact_protocol_write_varint64(ThriftCompactProtocol * protocol,const guint64 n,GError ** error)232 thrift_compact_protocol_write_varint64 (ThriftCompactProtocol *protocol,
233                                         const guint64 n,
234                                         GError **error)
235 {
236   guint8 buf[10];
237   gint32 xfer;
238   guint64 m;
239 
240   THRIFT_UNUSED_VAR (error);
241 
242   xfer = 0;
243   m = n;
244 
245   while (TRUE) {
246     if ((m & ~0x7FL) == 0) {
247       buf[xfer++] = (gint8)m;
248       break;
249     } else {
250       buf[xfer++] = (gint8)((m & 0x7F) | 0x80);
251       m >>= 7;
252     }
253   }
254 
255   if (thrift_transport_write (THRIFT_PROTOCOL (protocol)->transport,
256                               (const gpointer) buf, xfer, error)) {
257     return xfer;
258   } else {
259     return -1;
260   }
261 }
262 
263 /**
264  * Read an i64 from the wire as a proper varint. The MSB of each byte is set
265  * if there is another byte to follow. This can read up to 10 bytes.
266  */
267 gint32
thrift_compact_protocol_read_varint64(ThriftCompactProtocol * protocol,gint64 * i64,GError ** error)268 thrift_compact_protocol_read_varint64 (ThriftCompactProtocol *protocol,
269                                        gint64 *i64,
270                                        GError **error)
271 {
272   ThriftProtocol *tp;
273   gint32 ret;
274   gint32 xfer;
275   guint64 val;
276   gint shift;
277   guint8 byte;
278 
279   tp = THRIFT_PROTOCOL (protocol);
280   xfer = 0;
281   val = 0;
282   shift = 0;
283   byte = 0;
284 
285   while (TRUE) {
286     if ((ret = thrift_transport_read_all (tp->transport,
287                                           (gpointer) &byte, 1, error)) < 0) {
288       return -1;
289     }
290     ++xfer;
291     val |= (guint64)(byte & 0x7f) << shift;
292     shift += 7;
293     if (!(byte & 0x80)) {
294       *i64 = (gint64) val;
295       return xfer;
296     }
297     if (G_UNLIKELY (xfer == 10)) { /* 7 * 9 < 64 < 7 * 10 */
298       g_set_error (error, THRIFT_PROTOCOL_ERROR,
299                    THRIFT_PROTOCOL_ERROR_INVALID_DATA,
300                    "variable-length int over 10 bytes");
301       return -1;
302     }
303   }
304 }
305 
306 /**
307  * Read an i32 from the wire as a varint. The MSB of each byte is set
308  * if there is another byte to follow. This can read up to 5 bytes.
309  */
310 gint32
thrift_compact_protocol_read_varint32(ThriftCompactProtocol * protocol,gint32 * i32,GError ** error)311 thrift_compact_protocol_read_varint32 (ThriftCompactProtocol *protocol,
312                                        gint32 *i32,
313                                        GError **error)
314 {
315   gint64 val;
316   gint32 ret;
317   gint32 xfer;
318 
319   xfer = 0;
320 
321   if ((ret = thrift_compact_protocol_read_varint64 (protocol, &val,
322                                                     error)) < 0) {
323     return -1;
324   }
325   xfer += ret;
326 
327   *i32 = (gint32)val;
328 
329   return xfer;
330 }
331 
332 gint32
thrift_compact_protocol_write_field_begin_internal(ThriftCompactProtocol * protocol,const gchar * name,const ThriftType field_type,const gint16 field_id,const gint8 type_override,GError ** error)333 thrift_compact_protocol_write_field_begin_internal (ThriftCompactProtocol
334                                                       *protocol,
335                                                     const gchar *name,
336                                                     const ThriftType field_type,
337                                                     const gint16 field_id,
338                                                     const gint8 type_override,
339                                                     GError **error)
340 {
341   gint32 ret;
342   gint32 xfer;
343   gint8 type_to_write;
344 
345   THRIFT_UNUSED_VAR (name);
346 
347   xfer = 0;
348 
349   /* if there's a type override, use that. */
350   type_to_write
351     = (type_override == -1 ? TTypeToCType[field_type] : type_override);
352 
353   /* check if we can use delta encoding for the field id */
354   if (field_id > protocol->_last_field_id
355       && field_id - protocol->_last_field_id <= 15) {
356     /* write them together */
357     if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
358                                            (gint8) ((field_id
359                                                      - protocol->_last_field_id)
360                                                     << 4 | type_to_write),
361                                            error)) < 0) {
362       return -1;
363     }
364     xfer += ret;
365   } else {
366     /* write them separate */
367     if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
368                                            type_to_write, error)) < 0) {
369       return -1;
370     }
371     xfer += ret;
372 
373     if ((ret = thrift_protocol_write_i16 (THRIFT_PROTOCOL (protocol), field_id,
374                                           error)) < 0) {
375       return -1;
376     }
377     xfer += ret;
378   }
379 
380   protocol->_last_field_id = field_id;
381   return xfer;
382 }
383 
384 /**
385  * Method for writing the start of lists and sets. List and sets on
386  * the wire differ only by the type indicator.
387  */
388 gint32
thrift_compact_protocol_write_collection_begin(ThriftCompactProtocol * protocol,const ThriftType elem_type,guint32 size,GError ** error)389 thrift_compact_protocol_write_collection_begin (ThriftCompactProtocol *protocol,
390                                                 const ThriftType elem_type,
391                                                 guint32 size, GError **error)
392 {
393   gint32 ret;
394   gint32 xfer;
395 
396   xfer = 0;
397 
398   if (size <= 14) {
399     if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
400                                            (gint8) (size << 4
401                                                     | TTypeToCType[elem_type]),
402                                            error)) < 0) {
403       return -1;
404     }
405     xfer += ret;
406   } else {
407     if ((ret = thrift_protocol_write_byte (THRIFT_PROTOCOL (protocol),
408                                            (gint8) (0xf0
409                                                     | TTypeToCType[elem_type]),
410                                            error)) < 0) {
411       return -1;
412     }
413     xfer += ret;
414 
415     if ((ret = thrift_compact_protocol_write_varint32 (protocol,
416                                                        (guint32) size,
417                                                        error)) < 0) {
418       return -1;
419     }
420     xfer += ret;
421   }
422 
423   return xfer;
424 }
425 
426 /*
427  * public methods
428  */
429 
430 gint32
thrift_compact_protocol_write_message_begin(ThriftProtocol * protocol,const gchar * name,const ThriftMessageType message_type,const gint32 seqid,GError ** error)431 thrift_compact_protocol_write_message_begin (ThriftProtocol *protocol,
432                                              const gchar *name,
433                                              const ThriftMessageType
434                                                message_type,
435                                              const gint32 seqid, GError **error)
436 {
437   gint8 version;
438   gint32 ret;
439   gint32 xfer;
440 
441   ThriftCompactProtocol *cp;
442 
443   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
444 
445   cp = THRIFT_COMPACT_PROTOCOL (protocol);
446 
447   version = (VERSION_N & VERSION_MASK)
448             | (((gint32) message_type << TYPE_SHIFT_AMOUNT) & TYPE_MASK);
449   xfer = 0;
450 
451   if ((ret = thrift_protocol_write_byte (protocol, PROTOCOL_ID, error)) < 0) {
452     return -1;
453   }
454   xfer += ret;
455 
456   if ((ret = thrift_protocol_write_byte (protocol, version, error)) < 0) {
457     return -1;
458   }
459   xfer += ret;
460 
461   if ((ret = thrift_compact_protocol_write_varint32 (cp,
462                                                      (guint32) seqid,
463                                                      error)) < 0) {
464     return -1;
465   }
466   xfer += ret;
467 
468   if ((ret = thrift_protocol_write_string (protocol, name, error)) < 0) {
469     return -1;
470   }
471   xfer += ret;
472 
473   return xfer;
474 }
475 
476 gint32
thrift_compact_protocol_write_message_end(ThriftProtocol * protocol,GError ** error)477 thrift_compact_protocol_write_message_end (ThriftProtocol *protocol,
478                                            GError **error)
479 {
480   /* satisfy -Wall */
481   THRIFT_UNUSED_VAR (protocol);
482   THRIFT_UNUSED_VAR (error);
483   return 0;
484 }
485 
486 gint32
thrift_compact_protocol_write_struct_begin(ThriftProtocol * protocol,const gchar * name,GError ** error)487 thrift_compact_protocol_write_struct_begin (ThriftProtocol *protocol,
488                                             const gchar *name,
489                                             GError **error)
490 {
491   ThriftCompactProtocol *cp;
492   GQueue *q;
493 
494   /* satisfy -Wall */
495   THRIFT_UNUSED_VAR (name);
496   THRIFT_UNUSED_VAR (error);
497 
498   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
499 
500   cp = THRIFT_COMPACT_PROTOCOL (protocol);
501   q = &(cp->_last_field);
502 
503   g_queue_push_tail (q, GINT_TO_POINTER ((gint) cp->_last_field_id));
504   cp->_last_field_id = 0;
505   return 0;
506 }
507 
508 gint32
thrift_compact_protocol_write_struct_end(ThriftProtocol * protocol,GError ** error)509 thrift_compact_protocol_write_struct_end (ThriftProtocol *protocol,
510                                           GError **error)
511 {
512   ThriftCompactProtocol *cp;
513   GQueue *q;
514 
515   /* satisfy -Wall */
516   THRIFT_UNUSED_VAR (error);
517 
518   cp = THRIFT_COMPACT_PROTOCOL (protocol);
519   q = &(cp->_last_field);
520 
521   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
522 
523   cp->_last_field_id = (gint16) GPOINTER_TO_INT (g_queue_pop_tail (q));
524   return 0;
525 }
526 
527 gint32
thrift_compact_protocol_write_field_begin(ThriftProtocol * protocol,const gchar * name,const ThriftType field_type,const gint16 field_id,GError ** error)528 thrift_compact_protocol_write_field_begin (ThriftProtocol *protocol,
529                                            const gchar *name,
530                                            const ThriftType field_type,
531                                            const gint16 field_id,
532                                            GError **error)
533 {
534   ThriftCompactProtocol *cp;
535 
536   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
537 
538   cp = THRIFT_COMPACT_PROTOCOL (protocol);
539 
540   if (field_type == T_BOOL) {
541     cp->_bool_field_name = name;
542     cp->_bool_field_type = field_type;
543     cp->_bool_field_id = field_id;
544     return 0;
545   } else {
546     return thrift_compact_protocol_write_field_begin_internal (cp, name,
547                                                                field_type,
548                                                                field_id, -1,
549                                                                error);
550   }
551 }
552 
553 gint32
thrift_compact_protocol_write_field_end(ThriftProtocol * protocol,GError ** error)554 thrift_compact_protocol_write_field_end (ThriftProtocol *protocol,
555                                          GError **error)
556 {
557   /* satisfy -Wall */
558   THRIFT_UNUSED_VAR (protocol);
559   THRIFT_UNUSED_VAR (error);
560   return 0;
561 }
562 
563 gint32
thrift_compact_protocol_write_field_stop(ThriftProtocol * protocol,GError ** error)564 thrift_compact_protocol_write_field_stop (ThriftProtocol *protocol,
565                                           GError **error)
566 {
567   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
568   return thrift_protocol_write_byte (protocol, (gint8) T_STOP, error);
569 }
570 
571 gint32
thrift_compact_protocol_write_map_begin(ThriftProtocol * protocol,const ThriftType key_type,const ThriftType value_type,const guint32 size,GError ** error)572 thrift_compact_protocol_write_map_begin (ThriftProtocol *protocol,
573                                          const ThriftType key_type,
574                                          const ThriftType value_type,
575                                          const guint32 size,
576                                          GError **error)
577 {
578   gint32 ret;
579   gint32 xfer;
580 
581   ThriftCompactProtocol *cp;
582 
583   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
584 
585   cp = THRIFT_COMPACT_PROTOCOL (protocol);
586 
587   xfer = 0;
588 
589   if ((ret = thrift_compact_protocol_write_varint32 (cp, (guint32) size,
590                                                      error)) < 0) {
591     return -1;
592   }
593   xfer += ret;
594 
595   if (size > 0) {
596     if ((ret = thrift_protocol_write_byte (protocol,
597                                            (gint8) (TTypeToCType[key_type] << 4
598                                                     | TTypeToCType[value_type]),
599                                            error)) < 0) {
600       return -1;
601     }
602     xfer += ret;
603   }
604 
605   return xfer;
606 }
607 
608 gint32
thrift_compact_protocol_write_map_end(ThriftProtocol * protocol,GError ** error)609 thrift_compact_protocol_write_map_end (ThriftProtocol *protocol,
610                                        GError **error)
611 {
612   THRIFT_UNUSED_VAR (protocol);
613   THRIFT_UNUSED_VAR (error);
614   return 0;
615 }
616 
617 gint32
thrift_compact_protocol_write_list_begin(ThriftProtocol * protocol,const ThriftType element_type,const guint32 size,GError ** error)618 thrift_compact_protocol_write_list_begin (ThriftProtocol *protocol,
619                                           const ThriftType element_type,
620                                           const guint32 size,
621                                           GError **error)
622 {
623   ThriftCompactProtocol *cp;
624 
625   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
626 
627   cp = THRIFT_COMPACT_PROTOCOL (protocol);
628 
629   return thrift_compact_protocol_write_collection_begin (cp, element_type,
630                                                          size, error);
631 }
632 
633 gint32
thrift_compact_protocol_write_list_end(ThriftProtocol * protocol,GError ** error)634 thrift_compact_protocol_write_list_end (ThriftProtocol *protocol,
635                                         GError **error)
636 {
637   THRIFT_UNUSED_VAR (protocol);
638   THRIFT_UNUSED_VAR (error);
639   return 0;
640 }
641 
642 gint32
thrift_compact_protocol_write_set_begin(ThriftProtocol * protocol,const ThriftType element_type,const guint32 size,GError ** error)643 thrift_compact_protocol_write_set_begin (ThriftProtocol *protocol,
644                                          const ThriftType element_type,
645                                          const guint32 size,
646                                          GError **error)
647 {
648   ThriftCompactProtocol *cp;
649 
650   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
651 
652   cp = THRIFT_COMPACT_PROTOCOL (protocol);
653 
654   return thrift_compact_protocol_write_collection_begin (cp, element_type,
655                                                          size, error);
656 }
657 
658 gint32
thrift_compact_protocol_write_set_end(ThriftProtocol * protocol,GError ** error)659 thrift_compact_protocol_write_set_end (ThriftProtocol *protocol, GError **error)
660 {
661   THRIFT_UNUSED_VAR (protocol);
662   THRIFT_UNUSED_VAR (error);
663   return 0;
664 }
665 
666 gint32
thrift_compact_protocol_write_bool(ThriftProtocol * protocol,const gboolean value,GError ** error)667 thrift_compact_protocol_write_bool (ThriftProtocol *protocol,
668                                     const gboolean value, GError **error)
669 {
670   ThriftCompactProtocol *cp;
671 
672   gint32 ret;
673   gint32 xfer;
674 
675   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
676 
677   cp = THRIFT_COMPACT_PROTOCOL (protocol);
678 
679   xfer = 0;
680 
681   if (cp->_bool_field_name != NULL) {
682     /* we haven't written the field header yet */
683     if ((ret = thrift_compact_protocol_write_field_begin_internal (cp,
684                                  cp->_bool_field_name,
685                                  cp->_bool_field_type,
686                                  cp->_bool_field_id,
687                                  (gint8) (value
688                                           ? CT_BOOLEAN_TRUE : CT_BOOLEAN_FALSE),
689                                  error)) < 0) {
690       return -1;
691     }
692     xfer += ret;
693 
694     cp->_bool_field_name = NULL;
695   } else {
696     /* we're not part of a field, so just write the value */
697     if ((ret = thrift_protocol_write_byte (protocol,
698                                            (gint8) (value ? CT_BOOLEAN_TRUE
699                                                           : CT_BOOLEAN_FALSE),
700                                            error)) < 0) {
701       return -1;
702     }
703     xfer += ret;
704   }
705   return xfer;
706 }
707 
708 gint32
thrift_compact_protocol_write_byte(ThriftProtocol * protocol,const gint8 value,GError ** error)709 thrift_compact_protocol_write_byte (ThriftProtocol *protocol, const gint8 value,
710                                     GError **error)
711 {
712   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
713 
714   if (thrift_transport_write (protocol->transport,
715                               (const gpointer) &value, 1, error)) {
716     return 1;
717   } else {
718     return -1;
719   }
720 }
721 
722 gint32
thrift_compact_protocol_write_i16(ThriftProtocol * protocol,const gint16 value,GError ** error)723 thrift_compact_protocol_write_i16 (ThriftProtocol *protocol, const gint16 value,
724                                    GError **error)
725 {
726   ThriftCompactProtocol *cp;
727 
728   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
729 
730   cp = THRIFT_COMPACT_PROTOCOL (protocol);
731 
732   return thrift_compact_protocol_write_varint32 (cp,
733                          i32_to_zigzag ((gint32) value),
734                          error);
735 }
736 
737 gint32
thrift_compact_protocol_write_i32(ThriftProtocol * protocol,const gint32 value,GError ** error)738 thrift_compact_protocol_write_i32 (ThriftProtocol *protocol, const gint32 value,
739                                    GError **error)
740 {
741   ThriftCompactProtocol *cp;
742 
743   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
744 
745   cp = THRIFT_COMPACT_PROTOCOL (protocol);
746 
747   return thrift_compact_protocol_write_varint32 (cp,
748                          i32_to_zigzag (value),
749                          error);
750 }
751 
752 gint32
thrift_compact_protocol_write_i64(ThriftProtocol * protocol,const gint64 value,GError ** error)753 thrift_compact_protocol_write_i64 (ThriftProtocol *protocol, const gint64 value,
754                                    GError **error)
755 {
756   ThriftCompactProtocol *cp;
757 
758   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
759 
760   cp = THRIFT_COMPACT_PROTOCOL (protocol);
761 
762   return thrift_compact_protocol_write_varint64 (cp,
763                          i64_to_zigzag (value),
764                          error);
765 }
766 
767 gint32
thrift_compact_protocol_write_double(ThriftProtocol * protocol,const gdouble value,GError ** error)768 thrift_compact_protocol_write_double (ThriftProtocol *protocol,
769                                       const gdouble value, GError **error)
770 {
771   guint64 bits;
772 
773   g_assert (sizeof (gdouble) == sizeof (guint64));
774 
775   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
776 
777   bits = GUINT64_TO_LE (thrift_bitwise_cast_guint64 (value));
778   if (thrift_transport_write (protocol->transport,
779                               (const gpointer) &bits, 8, error)) {
780     return 8;
781   } else {
782     return -1;
783   }
784 }
785 
786 gint32
thrift_compact_protocol_write_string(ThriftProtocol * protocol,const gchar * str,GError ** error)787 thrift_compact_protocol_write_string (ThriftProtocol *protocol,
788                                       const gchar *str, GError **error)
789 {
790   size_t len;
791 
792   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
793 
794   len = str != NULL ? strlen (str) : 0;
795   if (len > G_MAXINT32) {
796     g_set_error (error, THRIFT_PROTOCOL_ERROR,
797                  THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
798                  "string size (guess: %lu) is too large", (unsigned long) len);
799     return -1;
800   }
801 
802   /* write the string length + 1 which includes the null terminator */
803   return thrift_protocol_write_binary (protocol, (const gpointer) str,
804                                        (const guint32) len, error);
805 }
806 
807 gint32
thrift_compact_protocol_write_binary(ThriftProtocol * protocol,const gpointer buf,const guint32 len,GError ** error)808 thrift_compact_protocol_write_binary (ThriftProtocol *protocol,
809                                       const gpointer buf,
810                                       const guint32 len, GError **error)
811 {
812   ThriftCompactProtocol *cp;
813 
814   gint32 ret;
815   gint32 xfer;
816 
817   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
818 
819   cp = THRIFT_COMPACT_PROTOCOL (protocol);
820 
821   xfer = 0;
822 
823   if ((ret = thrift_compact_protocol_write_varint32 (cp, len, error)) < 0) {
824     return -1;
825   }
826   xfer += ret;
827 
828   if (len > 0) {
829     /* checking len + xfer > uint_max, but we don't want to overflow while
830      * checking for overflows. transforming to len > uint_max - xfer.
831      */
832     if (len > (guint32) (G_MAXINT32 - xfer)) {
833       g_set_error (error, THRIFT_PROTOCOL_ERROR,
834                    THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
835                    "size %d + %d is too large", len, xfer);
836       return -1;
837     }
838 
839     if (thrift_transport_write (protocol->transport,
840                                 (const gpointer) buf, len, error) == FALSE) {
841       return -1;
842     }
843     xfer += len;
844   }
845 
846   return xfer;
847 }
848 
849 gint32
thrift_compact_protocol_read_message_begin(ThriftProtocol * protocol,gchar ** name,ThriftMessageType * message_type,gint32 * seqid,GError ** error)850 thrift_compact_protocol_read_message_begin (ThriftProtocol *protocol,
851                                             gchar **name,
852                                             ThriftMessageType *message_type,
853                                             gint32 *seqid, GError **error)
854 {
855   ThriftCompactProtocol *cp;
856 
857   gint32 ret;
858   gint32 xfer;
859 
860   gint8 protocol_id, version_and_type, version;
861 
862   xfer = 0;
863 
864   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
865 
866   cp = THRIFT_COMPACT_PROTOCOL (protocol);
867 
868   if ((ret = thrift_protocol_read_byte (protocol, &protocol_id, error)) < 0) {
869     return -1;
870   }
871   xfer += ret;
872 
873   if (protocol_id != PROTOCOL_ID) {
874     g_set_error (error, THRIFT_PROTOCOL_ERROR,
875                  THRIFT_PROTOCOL_ERROR_BAD_VERSION,
876                  "bad protocol id");
877     return -1;
878   }
879 
880   if ((ret = thrift_protocol_read_byte (protocol, &version_and_type,
881                                         error)) < 0) {
882     return -1;
883   }
884   xfer += ret;
885 
886   version = (gint8)(version_and_type & VERSION_MASK);
887   if (version != VERSION_N) {
888     g_set_error (error, THRIFT_PROTOCOL_ERROR,
889                  THRIFT_PROTOCOL_ERROR_BAD_VERSION,
890                  "bad version and/or type");
891     return -1;
892   }
893 
894   *message_type
895     = (ThriftMessageType)((version_and_type >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
896 
897   if ((ret = thrift_compact_protocol_read_varint32 (cp, seqid, error)) < 0) {
898     return -1;
899   }
900   xfer += ret;
901 
902   if ((ret = thrift_protocol_read_string (protocol, name, error)) < 0) {
903     return -1;
904   }
905   xfer += ret;
906 
907   return xfer;
908 }
909 
910 gint32
thrift_compact_protocol_read_message_end(ThriftProtocol * protocol,GError ** error)911 thrift_compact_protocol_read_message_end (ThriftProtocol *protocol,
912                                           GError **error)
913 {
914   THRIFT_UNUSED_VAR (protocol);
915   THRIFT_UNUSED_VAR (error);
916   return 0;
917 }
918 
919 gint32
thrift_compact_protocol_read_struct_begin(ThriftProtocol * protocol,gchar ** name,GError ** error)920 thrift_compact_protocol_read_struct_begin (ThriftProtocol *protocol,
921                                            gchar **name,
922                                            GError **error)
923 {
924   ThriftCompactProtocol *cp;
925   GQueue *q;
926 
927   THRIFT_UNUSED_VAR (error);
928 
929   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
930 
931   cp = THRIFT_COMPACT_PROTOCOL (protocol);
932   q = &(cp->_last_field);
933 
934   *name = NULL;
935 
936   g_queue_push_tail (q, GINT_TO_POINTER ((gint) cp->_last_field_id));
937   cp->_last_field_id = 0;
938 
939   return 0;
940 }
941 
942 gint32
thrift_compact_protocol_read_struct_end(ThriftProtocol * protocol,GError ** error)943 thrift_compact_protocol_read_struct_end (ThriftProtocol *protocol,
944                                          GError **error)
945 {
946   ThriftCompactProtocol *cp;
947   GQueue *q;
948 
949   THRIFT_UNUSED_VAR (error);
950 
951   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
952 
953   cp = THRIFT_COMPACT_PROTOCOL (protocol);
954   q = &(cp->_last_field);
955 
956   cp->_last_field_id = (gint16) GPOINTER_TO_INT (g_queue_pop_tail (q));
957 
958   return 0;
959 }
960 
961 gint32
thrift_compact_protocol_read_field_begin(ThriftProtocol * protocol,gchar ** name,ThriftType * field_type,gint16 * field_id,GError ** error)962 thrift_compact_protocol_read_field_begin (ThriftProtocol *protocol,
963                                           gchar **name,
964                                           ThriftType *field_type,
965                                           gint16 *field_id,
966                                           GError **error)
967 {
968   ThriftCompactProtocol *cp;
969 
970   gint32 ret;
971   gint32 xfer;
972 
973   gint16 modifier;
974   gint8 byte;
975   gint8 type;
976 
977   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
978 
979   cp = THRIFT_COMPACT_PROTOCOL (protocol);
980 
981   THRIFT_UNUSED_VAR (name);
982 
983   xfer = 0;
984 
985   if ((ret = thrift_protocol_read_byte (protocol, &byte, error)) < 0) {
986     return -1;
987   }
988   xfer += ret;
989 
990   type = (byte & 0x0f);
991 
992   /* if it's a stop, then we can return immediately, as the struct is over. */
993   if (type == T_STOP) {
994     *field_type = T_STOP;
995     *field_id = 0;
996     return xfer;
997   }
998 
999   /* mask off the 4 MSB of the type header.
1000    * it could contain a field id delta.
1001    */
1002   modifier = (gint16)(((guint8)byte & 0xf0) >> 4);
1003   if (modifier == 0) {
1004     /* not a delta, look ahead for the zigzag varint field id. */
1005     if ((ret = thrift_protocol_read_i16 (protocol, field_id, error)) < 0) {
1006       return -1;
1007     }
1008     xfer += ret;
1009   } else {
1010     *field_id = (gint16)(cp->_last_field_id + modifier);
1011   }
1012   if ((ret = thrift_compact_protocol_get_ttype (cp, type, error)) < 0) {
1013     return -1;
1014   }
1015   *field_type = ret;
1016 
1017   /* if this happens to be a boolean field, the value is encoded in the type */
1018   if (type == CT_BOOLEAN_TRUE || type == CT_BOOLEAN_FALSE) {
1019     /* save the boolean value in a special instance variable. */
1020     cp->_has_bool_value = TRUE;
1021     cp->_bool_value =
1022       (type == CT_BOOLEAN_TRUE ? TRUE : FALSE);
1023   }
1024 
1025   /* push the new field onto the field stack so we can keep the deltas going. */
1026   cp->_last_field_id = *field_id;
1027 
1028   return xfer;
1029 }
1030 
1031 gint32
thrift_compact_protocol_read_field_end(ThriftProtocol * protocol,GError ** error)1032 thrift_compact_protocol_read_field_end (ThriftProtocol *protocol,
1033                                         GError **error)
1034 {
1035   THRIFT_UNUSED_VAR (protocol);
1036   THRIFT_UNUSED_VAR (error);
1037   return 0;
1038 }
1039 
1040 gint32
thrift_compact_protocol_read_map_begin(ThriftProtocol * protocol,ThriftType * key_type,ThriftType * value_type,guint32 * size,GError ** error)1041 thrift_compact_protocol_read_map_begin (ThriftProtocol *protocol,
1042                                         ThriftType *key_type,
1043                                         ThriftType *value_type,
1044                                         guint32 *size,
1045                                         GError **error)
1046 {
1047   gint32 ret;
1048   gint32 xfer;
1049 
1050   gint8 kv_type;
1051   gint32 msize;
1052 
1053   ThriftCompactProtocol *cp;
1054   ThriftProtocol *tp = THRIFT_PROTOCOL (protocol);
1055   ThriftTransportClass *ttc = THRIFT_TRANSPORT_GET_CLASS (tp->transport);
1056 
1057   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1058 
1059   kv_type = 0;
1060   msize = 0;
1061 
1062   cp = THRIFT_COMPACT_PROTOCOL (protocol);
1063 
1064   xfer = 0;
1065 
1066   if ((ret = thrift_compact_protocol_read_varint32 (cp, &msize, error)) <0) {
1067     return -1;
1068   }
1069   xfer += ret;
1070 
1071   /* still read the kv byte if negative size */
1072   if (msize != 0) {
1073     if ((ret = thrift_protocol_read_byte (protocol, &kv_type, error)) < 0) {
1074       return -1;
1075     }
1076     xfer += ret;
1077   }
1078 
1079   if (cp->container_limit > 0 && msize > cp->container_limit) {
1080     g_set_error (error, THRIFT_PROTOCOL_ERROR,
1081                  THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
1082                  "got size over limit (%d > %d)", msize, cp->container_limit);
1083     return -1;
1084   } else if (msize > 0) {
1085     if ((ret = thrift_compact_protocol_get_ttype (cp,
1086                                                   (gint8)((guint8)kv_type
1087                                                           >> 4),
1088                                                   error)) < 0) {
1089       return -1;
1090     }
1091     *key_type = ret;
1092     if ((ret = thrift_compact_protocol_get_ttype (cp,
1093                                                   (gint8)((guint8)kv_type
1094                                                           & 0xf),
1095                                                   error)) < 0) {
1096       return -1;
1097     }
1098     *value_type = ret;
1099     *size = (guint32) msize;
1100   } else if (msize == 0) {
1101     *key_type = 0;
1102     *value_type = 0;
1103     *size = 0;
1104   } else {
1105     g_set_error (error, THRIFT_PROTOCOL_ERROR,
1106                  THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
1107                  "got negative size of %d", msize);
1108     return -1;
1109   }
1110 
1111   if(!ttc->checkReadBytesAvailable (THRIFT_TRANSPORT (tp->transport),
1112                                     msize * thrift_protocol_get_min_serialized_size (protocol, *key_type, error) +
1113                                     msize * thrift_protocol_get_min_serialized_size (protocol, *value_type, error),
1114                                     error))
1115   {
1116     return -1;
1117   }
1118 
1119   return xfer;
1120 }
1121 
1122 gint32
thrift_compact_protocol_read_map_end(ThriftProtocol * protocol,GError ** error)1123 thrift_compact_protocol_read_map_end (ThriftProtocol *protocol,
1124                                       GError **error)
1125 {
1126   THRIFT_UNUSED_VAR (protocol);
1127   THRIFT_UNUSED_VAR (error);
1128   return 0;
1129 }
1130 
1131 gint32
thrift_compact_protocol_read_list_begin(ThriftProtocol * protocol,ThriftType * element_type,guint32 * size,GError ** error)1132 thrift_compact_protocol_read_list_begin (ThriftProtocol *protocol,
1133                                          ThriftType *element_type,
1134                                          guint32 *size, GError **error)
1135 {
1136   ThriftCompactProtocol *cp;
1137   ThriftProtocol *tp = THRIFT_PROTOCOL (protocol);
1138   ThriftTransportClass *ttc = THRIFT_TRANSPORT_GET_CLASS (tp->transport);
1139   gint32 ret;
1140   gint32 xfer;
1141 
1142   gint8 size_and_type;
1143   gint32 lsize;
1144 
1145   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1146 
1147   cp = THRIFT_COMPACT_PROTOCOL (protocol);
1148 
1149   size_and_type = 0;
1150 
1151   xfer = 0;
1152 
1153   if ((ret = thrift_protocol_read_byte (protocol, &size_and_type, error)) < 0) {
1154     return -1;
1155   }
1156   xfer += ret;
1157 
1158   lsize = ((guint8)size_and_type >> 4) & 0x0f;
1159   if (lsize == 15) {
1160     if ((ret = thrift_compact_protocol_read_varint32 (cp, &lsize, error)) < 0) {
1161       return -1;
1162     }
1163     xfer += ret;
1164   }
1165 
1166   if (lsize < 0) {
1167     g_set_error (error, THRIFT_PROTOCOL_ERROR,
1168                  THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
1169                  "got negative size of %d", lsize);
1170     return -1;
1171   } else if (cp->container_limit > 0 && lsize > cp->container_limit) {
1172     g_set_error (error, THRIFT_PROTOCOL_ERROR,
1173                  THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
1174                  "got size over limit (%d > %d)", lsize, cp->container_limit);
1175     return -1;
1176   }
1177 
1178   if ((ret = thrift_compact_protocol_get_ttype (cp,
1179                                                 (gint8)(size_and_type & 0x0f),
1180                                                 error)) < 0) {
1181     return -1;
1182   }
1183   *element_type = ret;
1184   *size = (guint32) lsize;
1185 
1186   if(!ttc->checkReadBytesAvailable (THRIFT_TRANSPORT (tp->transport),
1187                                     (lsize * thrift_protocol_get_min_serialized_size (protocol, *element_type, error)),
1188                                     error))
1189   {
1190     return -1;
1191   }
1192 
1193   return xfer;
1194 }
1195 
1196 gint32
thrift_compact_protocol_read_list_end(ThriftProtocol * protocol,GError ** error)1197 thrift_compact_protocol_read_list_end (ThriftProtocol *protocol,
1198                                        GError **error)
1199 {
1200   THRIFT_UNUSED_VAR (protocol);
1201   THRIFT_UNUSED_VAR (error);
1202   return 0;
1203 }
1204 
1205 gint32
thrift_compact_protocol_read_set_begin(ThriftProtocol * protocol,ThriftType * element_type,guint32 * size,GError ** error)1206 thrift_compact_protocol_read_set_begin (ThriftProtocol *protocol,
1207                                         ThriftType *element_type,
1208                                         guint32 *size, GError **error)
1209 {
1210   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1211 
1212   return thrift_protocol_read_list_begin (protocol, element_type, size, error);
1213 }
1214 
1215 gint32
thrift_compact_protocol_read_set_end(ThriftProtocol * protocol,GError ** error)1216 thrift_compact_protocol_read_set_end (ThriftProtocol *protocol,
1217                                       GError **error)
1218 {
1219   THRIFT_UNUSED_VAR (protocol);
1220   THRIFT_UNUSED_VAR (error);
1221   return 0;
1222 }
1223 
1224 gint32
thrift_compact_protocol_read_bool(ThriftProtocol * protocol,gboolean * value,GError ** error)1225 thrift_compact_protocol_read_bool (ThriftProtocol *protocol, gboolean *value,
1226                                    GError **error)
1227 {
1228   ThriftCompactProtocol *cp;
1229 
1230   gint32 ret;
1231   gint32 xfer;
1232 
1233   gint8 val;
1234 
1235   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1236 
1237   cp = THRIFT_COMPACT_PROTOCOL (protocol);
1238 
1239   xfer = 0;
1240 
1241   if (cp->_has_bool_value == TRUE) {
1242     *value = cp->_bool_value;
1243     cp->_has_bool_value = FALSE;
1244     return 0;
1245   } else {
1246     if ((ret = thrift_protocol_read_byte (protocol, &val, error)) < 0) {
1247       return -1;
1248     }
1249     xfer += ret;
1250 
1251     *value = (val == CT_BOOLEAN_TRUE);
1252     return xfer;
1253   }
1254 }
1255 
1256 gint32
thrift_compact_protocol_read_byte(ThriftProtocol * protocol,gint8 * value,GError ** error)1257 thrift_compact_protocol_read_byte (ThriftProtocol *protocol, gint8 *value,
1258                                    GError **error)
1259 {
1260   gint32 ret;
1261   gpointer b[1];
1262 
1263   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1264 
1265   if ((ret =
1266        thrift_transport_read_all (protocol->transport,
1267                                   b, 1, error)) < 0) {
1268     return -1;
1269   }
1270   *value = *(gint8 *) b;
1271   return ret;
1272 }
1273 
1274 gint32
thrift_compact_protocol_read_i16(ThriftProtocol * protocol,gint16 * value,GError ** error)1275 thrift_compact_protocol_read_i16 (ThriftProtocol *protocol, gint16 *value,
1276                                   GError **error)
1277 {
1278   ThriftCompactProtocol *cp;
1279 
1280   gint32 ret;
1281   gint32 val;
1282   gint32 xfer;
1283 
1284   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1285 
1286   cp = THRIFT_COMPACT_PROTOCOL (protocol);
1287 
1288   xfer = 0;
1289 
1290   if ((ret = thrift_compact_protocol_read_varint32 (cp, &val, error)) < 0) {
1291     return -1;
1292   }
1293   xfer += ret;
1294 
1295   *value = (gint16) zigzag_to_i32 ((guint32) val);
1296 
1297   return xfer;
1298 }
1299 
1300 gint32
thrift_compact_protocol_read_i32(ThriftProtocol * protocol,gint32 * value,GError ** error)1301 thrift_compact_protocol_read_i32 (ThriftProtocol *protocol, gint32 *value,
1302                                   GError **error)
1303 {
1304   ThriftCompactProtocol *cp;
1305 
1306   gint32 ret;
1307   gint32 val;
1308   gint32 xfer;
1309 
1310   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1311 
1312   cp = THRIFT_COMPACT_PROTOCOL (protocol);
1313 
1314   xfer = 0;
1315 
1316   if ((ret = thrift_compact_protocol_read_varint32 (cp, &val, error)) < 0) {
1317     return -1;
1318   }
1319   xfer += ret;
1320 
1321   *value = zigzag_to_i32 ((guint32) val);
1322 
1323   return xfer;
1324 }
1325 
1326 gint32
thrift_compact_protocol_read_i64(ThriftProtocol * protocol,gint64 * value,GError ** error)1327 thrift_compact_protocol_read_i64 (ThriftProtocol *protocol, gint64 *value,
1328                                   GError **error)
1329 {
1330   ThriftCompactProtocol *cp;
1331 
1332   gint32 ret;
1333   gint64 val;
1334   gint32 xfer;
1335 
1336   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1337 
1338   cp = THRIFT_COMPACT_PROTOCOL (protocol);
1339 
1340   xfer = 0;
1341 
1342   if ((ret = thrift_compact_protocol_read_varint64 (cp, &val, error)) < 0) {
1343     return -1;
1344   }
1345   xfer += ret;
1346 
1347   *value = zigzag_to_i64 ((guint64) val);
1348 
1349   return xfer;
1350 }
1351 
1352 gint32
thrift_compact_protocol_read_double(ThriftProtocol * protocol,gdouble * value,GError ** error)1353 thrift_compact_protocol_read_double (ThriftProtocol *protocol,
1354                                      gdouble *value, GError **error)
1355 {
1356   gint32 ret;
1357   union {
1358     guint64 bits;
1359     guint8 b[8];
1360   } u;
1361 
1362   g_assert (sizeof (gdouble) == sizeof (guint64));
1363 
1364   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1365 
1366   if ((ret =
1367        thrift_transport_read_all (protocol->transport,
1368                                   u.b, 8, error)) < 0) {
1369     return -1;
1370   }
1371   u.bits = GUINT64_FROM_LE (u.bits);
1372   *value = thrift_bitwise_cast_gdouble (u.bits);
1373   return ret;
1374 }
1375 
1376 gint32
thrift_compact_protocol_read_string(ThriftProtocol * protocol,gchar ** str,GError ** error)1377 thrift_compact_protocol_read_string (ThriftProtocol *protocol,
1378                                      gchar **str, GError **error)
1379 {
1380   ThriftCompactProtocol *cp;
1381 
1382   gint32 ret;
1383   gint32 xfer;
1384 
1385   gint32 read_len;
1386 
1387   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1388 
1389   cp = THRIFT_COMPACT_PROTOCOL (protocol);
1390 
1391   xfer = 0;
1392   read_len = 0;
1393 
1394   /* read the length into read_len */
1395   if ((ret =
1396        thrift_compact_protocol_read_varint32 (cp, &read_len, error)) < 0) {
1397     return -1;
1398   }
1399   xfer += ret;
1400 
1401   if (cp->string_limit > 0 && read_len > cp->string_limit) {
1402     g_set_error (error, THRIFT_PROTOCOL_ERROR,
1403                  THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
1404                  "got size over limit (%d > %d)", read_len, cp->string_limit);
1405     *str = NULL;
1406     return -1;
1407   }
1408 
1409   if (read_len < 0) {
1410     g_set_error (error, THRIFT_PROTOCOL_ERROR,
1411                  THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
1412                  "got negative size of %d", read_len);
1413     *str = NULL;
1414     return -1;
1415   }
1416 
1417   /* allocate the memory as an array of unsigned char for binary data */
1418   *str = g_new0 (gchar, read_len + 1);
1419   if (read_len > 0) {
1420     if ((ret =
1421          thrift_transport_read_all (protocol->transport,
1422                                     *str, read_len, error)) < 0) {
1423       g_free (*str);
1424       *str = NULL;
1425       return -1;
1426     }
1427     xfer += ret;
1428   } else {
1429     **str = 0;
1430   }
1431 
1432   return xfer;
1433 }
1434 
1435 gint32
thrift_compact_protocol_read_binary(ThriftProtocol * protocol,gpointer * buf,guint32 * len,GError ** error)1436 thrift_compact_protocol_read_binary (ThriftProtocol *protocol,
1437                                      gpointer *buf, guint32 *len,
1438                                      GError **error)
1439 {
1440   ThriftCompactProtocol *cp;
1441 
1442   gint32 ret;
1443   gint32 xfer;
1444 
1445   gint32 read_len;
1446 
1447   g_return_val_if_fail (THRIFT_IS_COMPACT_PROTOCOL (protocol), -1);
1448 
1449   cp = THRIFT_COMPACT_PROTOCOL (protocol);
1450 
1451   xfer = 0;
1452   read_len = 0;
1453 
1454   /* read the length into read_len */
1455   if ((ret =
1456        thrift_compact_protocol_read_varint32 (cp, &read_len, error)) < 0) {
1457     return -1;
1458   }
1459   xfer += ret;
1460 
1461   if (cp->string_limit > 0 && read_len > cp->string_limit) {
1462     g_set_error (error, THRIFT_PROTOCOL_ERROR,
1463                  THRIFT_PROTOCOL_ERROR_SIZE_LIMIT,
1464                  "got size over limit (%d > %d)", read_len, cp->string_limit);
1465     *buf = NULL;
1466     *len = 0;
1467     return -1;
1468   }
1469 
1470   if (read_len > 0) {
1471     /* allocate the memory as an array of unsigned char for binary data */
1472     *len = (guint32) read_len;
1473     *buf = g_new (guchar, *len);
1474     if ((ret =
1475          thrift_transport_read_all (protocol->transport,
1476                                     *buf, *len, error)) < 0) {
1477       g_free (*buf);
1478       *buf = NULL;
1479       *len = 0;
1480       return -1;
1481     }
1482     xfer += ret;
1483 
1484   } else if (read_len == 0) {
1485     *len = (guint32) read_len;
1486     *buf = NULL;
1487 
1488   } else {
1489     g_set_error (error, THRIFT_PROTOCOL_ERROR,
1490                  THRIFT_PROTOCOL_ERROR_NEGATIVE_SIZE,
1491                  "got negative size of %d", read_len);
1492     *buf = NULL;
1493     *len = 0;
1494     return -1;
1495   }
1496 
1497   return xfer;
1498 }
1499 
1500 gint
thrift_compact_protocol_get_min_serialized_size(ThriftProtocol * protocol,ThriftType type,GError ** error)1501 thrift_compact_protocol_get_min_serialized_size (ThriftProtocol *protocol, ThriftType type, GError **error)
1502 {
1503   THRIFT_UNUSED_VAR (protocol);
1504 
1505   switch (type)
1506   {
1507     case T_STOP:
1508          return 0;
1509     case T_VOID:
1510          return 0;
1511     case T_BOOL:
1512          return sizeof(gint8);
1513     case T_DOUBLE:
1514          return 8;
1515     case T_BYTE:
1516          return sizeof(gint8);
1517     case T_I16:
1518          return sizeof(gint8);
1519     case T_I32:
1520          return sizeof(gint8);
1521     case T_I64:
1522 	 return sizeof(gint8);
1523     case T_STRING:
1524          return sizeof(gint8);
1525     case T_STRUCT:
1526          return 0;
1527     case T_MAP:
1528          return sizeof(gint8);
1529     case T_SET:
1530          return sizeof(gint8);
1531     case T_LIST:
1532          return sizeof(gint8);
1533     default:
1534          g_set_error(error,
1535                      THRIFT_PROTOCOL_ERROR,
1536                      THRIFT_PROTOCOL_ERROR_INVALID_DATA,
1537                      "unrecognized type");
1538          return -1;
1539   }
1540 }
1541 
1542 /* property accessor */
1543 void
thrift_compact_protocol_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)1544 thrift_compact_protocol_get_property (GObject *object, guint property_id,
1545                                       GValue *value, GParamSpec *pspec)
1546 {
1547   ThriftCompactProtocol *tc;
1548 
1549   THRIFT_UNUSED_VAR (pspec);
1550 
1551   tc = THRIFT_COMPACT_PROTOCOL (object);
1552 
1553   switch (property_id) {
1554     case PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT:
1555       g_value_set_int (value, tc->string_limit);
1556       break;
1557     case PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT:
1558       g_value_set_int (value, tc->container_limit);
1559       break;
1560   }
1561 }
1562 
1563 /* property mutator */
1564 void
thrift_compact_protocol_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)1565 thrift_compact_protocol_set_property (GObject *object, guint property_id,
1566                                       const GValue *value, GParamSpec *pspec)
1567 {
1568   ThriftCompactProtocol *tc;
1569 
1570   THRIFT_UNUSED_VAR (pspec);
1571 
1572   tc = THRIFT_COMPACT_PROTOCOL (object);
1573 
1574   switch (property_id) {
1575     case PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT:
1576       tc->string_limit = g_value_get_int (value);
1577       break;
1578     case PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT:
1579       tc->container_limit = g_value_get_int (value);
1580       break;
1581   }
1582 }
1583 
1584 /* initialize the class */
1585 static void
thrift_compact_protocol_class_init(ThriftCompactProtocolClass * klass)1586 thrift_compact_protocol_class_init (ThriftCompactProtocolClass *klass)
1587 {
1588   ThriftProtocolClass *cls;
1589   GObjectClass *gobject_class;
1590   GParamSpec *param_spec;
1591 
1592   cls = THRIFT_PROTOCOL_CLASS (klass);
1593   gobject_class = G_OBJECT_CLASS (klass);
1594   param_spec = NULL;
1595 
1596   /* setup accessors and mutators */
1597   gobject_class->get_property = thrift_compact_protocol_get_property;
1598   gobject_class->set_property = thrift_compact_protocol_set_property;
1599 
1600   param_spec = g_param_spec_int ("string_limit",
1601                                  "Max allowed string size",
1602                                  "Set the max string limit",
1603                                  0, /* min */
1604                                  G_MAXINT32, /* max */
1605                                  0, /* default value */
1606                                  G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
1607   g_object_class_install_property (gobject_class,
1608                                    PROP_THRIFT_COMPACT_PROTOCOL_STRING_LIMIT,
1609                                    param_spec);
1610 
1611   param_spec = g_param_spec_int ("container_limit",
1612                                  "Max allowed container size",
1613                                  "Set the max container limit",
1614                                  0, /* min */
1615                                  G_MAXINT32, /* max */
1616                                  0, /* default value */
1617                                  G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
1618   g_object_class_install_property (gobject_class,
1619                                    PROP_THRIFT_COMPACT_PROTOCOL_CONTAINER_LIMIT,
1620                                    param_spec);
1621 
1622   cls->write_message_begin = thrift_compact_protocol_write_message_begin;
1623   cls->write_message_end = thrift_compact_protocol_write_message_end;
1624   cls->write_struct_begin = thrift_compact_protocol_write_struct_begin;
1625   cls->write_struct_end = thrift_compact_protocol_write_struct_end;
1626   cls->write_field_begin = thrift_compact_protocol_write_field_begin;
1627   cls->write_field_end = thrift_compact_protocol_write_field_end;
1628   cls->write_field_stop = thrift_compact_protocol_write_field_stop;
1629   cls->write_map_begin = thrift_compact_protocol_write_map_begin;
1630   cls->write_map_end = thrift_compact_protocol_write_map_end;
1631   cls->write_list_begin = thrift_compact_protocol_write_list_begin;
1632   cls->write_list_end = thrift_compact_protocol_write_list_end;
1633   cls->write_set_begin = thrift_compact_protocol_write_set_begin;
1634   cls->write_set_end = thrift_compact_protocol_write_set_end;
1635   cls->write_bool = thrift_compact_protocol_write_bool;
1636   cls->write_byte = thrift_compact_protocol_write_byte;
1637   cls->write_i16 = thrift_compact_protocol_write_i16;
1638   cls->write_i32 = thrift_compact_protocol_write_i32;
1639   cls->write_i64 = thrift_compact_protocol_write_i64;
1640   cls->write_double = thrift_compact_protocol_write_double;
1641   cls->write_string = thrift_compact_protocol_write_string;
1642   cls->write_binary = thrift_compact_protocol_write_binary;
1643   cls->read_message_begin = thrift_compact_protocol_read_message_begin;
1644   cls->read_message_end = thrift_compact_protocol_read_message_end;
1645   cls->read_struct_begin = thrift_compact_protocol_read_struct_begin;
1646   cls->read_struct_end = thrift_compact_protocol_read_struct_end;
1647   cls->read_field_begin = thrift_compact_protocol_read_field_begin;
1648   cls->read_field_end = thrift_compact_protocol_read_field_end;
1649   cls->read_map_begin = thrift_compact_protocol_read_map_begin;
1650   cls->read_map_end = thrift_compact_protocol_read_map_end;
1651   cls->read_list_begin = thrift_compact_protocol_read_list_begin;
1652   cls->read_list_end = thrift_compact_protocol_read_list_end;
1653   cls->read_set_begin = thrift_compact_protocol_read_set_begin;
1654   cls->read_set_end = thrift_compact_protocol_read_set_end;
1655   cls->read_bool = thrift_compact_protocol_read_bool;
1656   cls->read_byte = thrift_compact_protocol_read_byte;
1657   cls->read_i16 = thrift_compact_protocol_read_i16;
1658   cls->read_i32 = thrift_compact_protocol_read_i32;
1659   cls->read_i64 = thrift_compact_protocol_read_i64;
1660   cls->read_double = thrift_compact_protocol_read_double;
1661   cls->read_string = thrift_compact_protocol_read_string;
1662   cls->read_binary = thrift_compact_protocol_read_binary;
1663   cls->get_min_serialized_size = thrift_compact_protocol_get_min_serialized_size;
1664 }
1665 
1666 static void
thrift_compact_protocol_init(ThriftCompactProtocol * self)1667 thrift_compact_protocol_init (ThriftCompactProtocol *self)
1668 {
1669   g_queue_init (&(self->_last_field));
1670 }
1671