3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
38 * Represents a reader/writer for compact Thrift data.
43 FbThriftPrivate
*priv
;
46 G_DEFINE_TYPE_WITH_PRIVATE(FbThrift
, fb_thrift
, G_TYPE_OBJECT
);
49 fb_thrift_dispose(GObject
*obj
)
51 FbThriftPrivate
*priv
= FB_THRIFT(obj
)->priv
;
54 g_byte_array_free(priv
->bytes
, TRUE
);
59 fb_thrift_class_init(FbThriftClass
*klass
)
61 GObjectClass
*gklass
= G_OBJECT_CLASS(klass
);
63 gklass
->dispose
= fb_thrift_dispose
;
67 fb_thrift_init(FbThrift
*thft
)
69 FbThriftPrivate
*priv
= fb_thrift_get_instance_private(thft
);
75 fb_thrift_new(GByteArray
*bytes
, guint offset
)
78 FbThriftPrivate
*priv
;
80 thft
= g_object_new(FB_TYPE_THRIFT
, NULL
);
85 priv
->offset
= offset
;
88 priv
->bytes
= g_byte_array_new();
89 priv
->internal
= TRUE
;
96 fb_thrift_get_bytes(FbThrift
*thft
)
98 FbThriftPrivate
*priv
;
100 g_return_val_if_fail(FB_IS_THRIFT(thft
), NULL
);
106 fb_thrift_get_pos(FbThrift
*thft
)
108 FbThriftPrivate
*priv
;
110 g_return_val_if_fail(FB_IS_THRIFT(thft
), 0);
116 fb_thrift_set_pos(FbThrift
*thft
, guint pos
)
118 FbThriftPrivate
*priv
;
120 g_return_if_fail(FB_IS_THRIFT(thft
));
126 fb_thrift_reset(FbThrift
*thft
)
128 FbThriftPrivate
*priv
;
130 g_return_if_fail(FB_IS_THRIFT(thft
));
132 priv
->pos
= priv
->offset
;
136 fb_thrift_read(FbThrift
*thft
, gpointer data
, guint size
)
138 FbThriftPrivate
*priv
;
140 g_return_val_if_fail(FB_IS_THRIFT(thft
), FALSE
);
143 if ((priv
->pos
+ size
) > priv
->bytes
->len
) {
147 if ((data
!= NULL
) && (size
> 0)) {
148 memcpy(data
, priv
->bytes
->data
+ priv
->pos
, size
);
156 fb_thrift_read_bool(FbThrift
*thft
, gboolean
*value
)
158 FbThriftPrivate
*priv
;
161 g_return_val_if_fail(FB_IS_THRIFT(thft
), FALSE
);
164 if ((priv
->lastbool
& 0x03) != 0x01) {
165 if (!fb_thrift_read_byte(thft
, &byte
)) {
170 *value
= (byte
& 0x0F) == 0x01;
178 *value
= ((priv
->lastbool
& 0x04) >> 2) != 0;
186 fb_thrift_read_byte(FbThrift
*thft
, guint8
*value
)
188 return fb_thrift_read(thft
, value
, sizeof *value
);
192 fb_thrift_read_dbl(FbThrift
*thft
, gdouble
*value
)
196 /* Almost always 8, but check anyways */
197 static const gsize size
= MIN(sizeof value
, sizeof i64
);
199 if (!fb_thrift_read_i64(thft
, &i64
)) {
204 memcpy(value
, &i64
, size
);
211 fb_thrift_read_i16(FbThrift
*thft
, gint16
*value
)
215 if (!fb_thrift_read_i64(thft
, &i64
)) {
227 fb_thrift_read_vi16(FbThrift
*thft
, guint16
*value
)
231 if (!fb_thrift_read_vi64(thft
, &u64
)) {
243 fb_thrift_read_i32(FbThrift
*thft
, gint32
*value
)
247 if (!fb_thrift_read_i64(thft
, &i64
)) {
259 fb_thrift_read_vi32(FbThrift
*thft
, guint32
*value
)
263 if (!fb_thrift_read_vi64(thft
, &u64
)) {
275 fb_thrift_read_i64(FbThrift
*thft
, gint64
*value
)
279 if (!fb_thrift_read_vi64(thft
, &u64
)) {
284 /* Convert from zigzag to integer */
285 *value
= (u64
>> 0x01) ^ -(u64
& 0x01);
292 fb_thrift_read_vi64(FbThrift
*thft
, guint64
*value
)
299 if (!fb_thrift_read_byte(thft
, &byte
)) {
303 u64
|= ((guint64
) (byte
& 0x7F)) << i
;
305 } while ((byte
& 0x80) == 0x80);
315 fb_thrift_read_str(FbThrift
*thft
, gchar
**value
)
320 if (!fb_thrift_read_vi32(thft
, &size
)) {
325 data
= g_new(guint8
, size
+ 1);
331 if (!fb_thrift_read(thft
, data
, size
)) {
337 *value
= (gchar
*) data
;
344 fb_thrift_read_field(FbThrift
*thft
, FbThriftType
*type
, gint16
*id
,
347 FbThriftPrivate
*priv
;
351 g_return_val_if_fail(FB_IS_THRIFT(thft
), FALSE
);
352 g_return_val_if_fail(type
!= NULL
, FALSE
);
353 g_return_val_if_fail(id
!= NULL
, FALSE
);
356 if (!fb_thrift_read_byte(thft
, &byte
)) {
360 if (byte
== FB_THRIFT_TYPE_STOP
) {
361 *type
= FB_THRIFT_TYPE_STOP
;
365 *type
= fb_thrift_ct2t(byte
& 0x0F);
366 i16
= (byte
& 0xF0) >> 4;
369 if (!fb_thrift_read_i16(thft
, id
)) {
376 if (*type
== FB_THRIFT_TYPE_BOOL
) {
377 priv
->lastbool
= 0x01;
379 if ((byte
& 0x0F) == 0x01) {
380 priv
->lastbool
|= 0x01 << 2;
388 fb_thrift_read_stop(FbThrift
*thft
)
392 return fb_thrift_read_byte(thft
, &byte
) &&
393 (byte
== FB_THRIFT_TYPE_STOP
);
397 fb_thrift_read_isstop(FbThrift
*thft
)
399 FbThriftPrivate
*priv
;
402 g_return_val_if_fail(FB_IS_THRIFT(thft
), FALSE
);
405 if (!fb_thrift_read_byte(thft
, &byte
)) {
410 return byte
== FB_THRIFT_TYPE_STOP
;
414 fb_thrift_read_list(FbThrift
*thft
, FbThriftType
*type
, guint
*size
)
419 g_return_val_if_fail(type
!= NULL
, FALSE
);
420 g_return_val_if_fail(size
!= NULL
, FALSE
);
422 if (!fb_thrift_read_byte(thft
, &byte
)) {
426 *type
= fb_thrift_ct2t(byte
& 0x0F);
427 *size
= (byte
& 0xF0) >> 4;
430 if (!fb_thrift_read_vi32(thft
, &u32
)) {
441 fb_thrift_read_map(FbThrift
*thft
, FbThriftType
*ktype
, FbThriftType
*vtype
,
447 g_return_val_if_fail(ktype
!= NULL
, FALSE
);
448 g_return_val_if_fail(vtype
!= NULL
, FALSE
);
449 g_return_val_if_fail(size
!= NULL
, FALSE
);
451 if (!fb_thrift_read_i32(thft
, &i32
)) {
456 if (!fb_thrift_read_byte(thft
, &byte
)) {
460 *ktype
= fb_thrift_ct2t((byte
& 0xF0) >> 4);
461 *vtype
= fb_thrift_ct2t(byte
& 0x0F);
472 fb_thrift_read_set(FbThrift
*thft
, FbThriftType
*type
, guint
*size
)
474 return fb_thrift_read_list(thft
, type
, size
);
478 fb_thrift_write(FbThrift
*thft
, gconstpointer data
, guint size
)
480 FbThriftPrivate
*priv
;
482 g_return_if_fail(FB_IS_THRIFT(thft
));
485 g_byte_array_append(priv
->bytes
, data
, size
);
490 fb_thrift_write_bool(FbThrift
*thft
, gboolean value
)
492 FbThriftPrivate
*priv
;
495 g_return_if_fail(FB_IS_THRIFT(thft
));
498 if ((priv
->lastbool
& 0x03) != 0x02) {
499 fb_thrift_write_byte(thft
, value
? 0x01 : 0x02);
503 pos
= priv
->lastbool
>> 3;
506 if ((pos
>= priv
->offset
) && (pos
< priv
->bytes
->len
)) {
507 priv
->bytes
->data
[pos
] &= ~0x0F;
508 priv
->bytes
->data
[pos
] |= value
? 0x01 : 0x02;
513 fb_thrift_write_byte(FbThrift
*thft
, guint8 value
)
515 fb_thrift_write(thft
, &value
, sizeof value
);
519 fb_thrift_write_dbl(FbThrift
*thft
, gdouble value
)
523 /* Almost always 8, but check anyways */
524 static const gsize size
= MIN(sizeof value
, sizeof i64
);
526 memcpy(&i64
, &value
, size
);
527 fb_thrift_write_i64(thft
, i64
);
531 fb_thrift_write_i16(FbThrift
*thft
, gint16 value
)
533 fb_thrift_write_i64(thft
, value
);
537 fb_thrift_write_vi16(FbThrift
*thft
, guint16 value
)
539 fb_thrift_write_vi64(thft
, value
);
543 fb_thrift_write_i32(FbThrift
*thft
, gint32 value
)
545 value
= (value
<< 1) ^ (value
>> 31);
546 fb_thrift_write_vi64(thft
, value
);
550 fb_thrift_write_vi32(FbThrift
*thft
, guint32 value
)
552 fb_thrift_write_vi64(thft
, value
);
556 fb_thrift_write_i64(FbThrift
*thft
, gint64 value
)
558 value
= (value
<< 1) ^ (value
>> 63);
559 fb_thrift_write_vi64(thft
, value
);
563 fb_thrift_write_vi64(FbThrift
*thft
, guint64 value
)
569 last
= (value
& ~0x7F) == 0;
577 fb_thrift_write_byte(thft
, byte
);
582 fb_thrift_write_str(FbThrift
*thft
, const gchar
*value
)
586 g_return_if_fail(value
!= NULL
);
588 size
= strlen(value
);
589 fb_thrift_write_vi32(thft
, size
);
590 fb_thrift_write(thft
, value
, size
);
594 fb_thrift_write_field(FbThrift
*thft
, FbThriftType type
, gint16 id
,
597 FbThriftPrivate
*priv
;
600 g_return_if_fail(FB_IS_THRIFT(thft
));
603 if (type
== FB_THRIFT_TYPE_BOOL
) {
604 priv
->lastbool
= (priv
->pos
<< 3) | 0x02;
607 type
= fb_thrift_t2ct(type
);
610 if ((id
<= lastid
) || (diff
> 0x0F)) {
611 fb_thrift_write_byte(thft
, type
);
612 fb_thrift_write_i16(thft
, id
);
614 fb_thrift_write_byte(thft
, (diff
<< 4) | type
);
619 fb_thrift_write_stop(FbThrift
*thft
)
621 fb_thrift_write_byte(thft
, FB_THRIFT_TYPE_STOP
);
625 fb_thrift_write_list(FbThrift
*thft
, FbThriftType type
, guint size
)
627 type
= fb_thrift_t2ct(type
);
630 fb_thrift_write_byte(thft
, (size
<< 4) | type
);
634 fb_thrift_write_vi32(thft
, size
);
635 fb_thrift_write_byte(thft
, 0xF0 | type
);
639 fb_thrift_write_map(FbThrift
*thft
, FbThriftType ktype
, FbThriftType vtype
,
643 fb_thrift_write_byte(thft
, 0);
647 ktype
= fb_thrift_t2ct(ktype
);
648 vtype
= fb_thrift_t2ct(vtype
);
650 fb_thrift_write_vi32(thft
, size
);
651 fb_thrift_write_byte(thft
, (ktype
<< 4) | vtype
);
655 fb_thrift_write_set(FbThrift
*thft
, FbThriftType type
, guint size
)
657 fb_thrift_write_list(thft
, type
, size
);
661 fb_thrift_t2ct(FbThriftType type
)
663 static const guint8 types
[] = {
664 [FB_THRIFT_TYPE_STOP
] = 0,
665 [FB_THRIFT_TYPE_VOID
] = 0,
666 [FB_THRIFT_TYPE_BOOL
] = 2,
667 [FB_THRIFT_TYPE_BYTE
] = 3,
668 [FB_THRIFT_TYPE_DOUBLE
] = 7,
670 [FB_THRIFT_TYPE_I16
] = 4,
672 [FB_THRIFT_TYPE_I32
] = 5,
674 [FB_THRIFT_TYPE_I64
] = 6,
675 [FB_THRIFT_TYPE_STRING
] = 8,
676 [FB_THRIFT_TYPE_STRUCT
] = 12,
677 [FB_THRIFT_TYPE_MAP
] = 11,
678 [FB_THRIFT_TYPE_SET
] = 10,
679 [FB_THRIFT_TYPE_LIST
] = 9
682 g_return_val_if_fail(type
< G_N_ELEMENTS(types
), 0);
687 fb_thrift_ct2t(guint8 type
)
689 static const guint8 types
[] = {
690 [0] = FB_THRIFT_TYPE_STOP
,
691 [1] = FB_THRIFT_TYPE_BOOL
,
692 [2] = FB_THRIFT_TYPE_BOOL
,
693 [3] = FB_THRIFT_TYPE_BYTE
,
694 [4] = FB_THRIFT_TYPE_I16
,
695 [5] = FB_THRIFT_TYPE_I32
,
696 [6] = FB_THRIFT_TYPE_I64
,
697 [7] = FB_THRIFT_TYPE_DOUBLE
,
698 [8] = FB_THRIFT_TYPE_STRING
,
699 [9] = FB_THRIFT_TYPE_LIST
,
700 [10] = FB_THRIFT_TYPE_SET
,
701 [11] = FB_THRIFT_TYPE_MAP
,
702 [12] = FB_THRIFT_TYPE_STRUCT
705 g_return_val_if_fail(type
< G_N_ELEMENTS(types
), 0);