pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Merged in default (pull request #665)
2019-12-30, Gary Kramlich
8066acc5ed93
Merged in default (pull request #665)
Convert most Xfer UI ops to signals
Approved-by: Gary Kramlich
/* purple
*
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include
<string.h>
#include
"thrift.h"
typedef
struct
{
GByteArray
*
bytes
;
gboolean
internal
;
guint
offset
;
guint
pos
;
guint
lastbool
;
}
FbThriftPrivate
;
/**
* FbThrift:
*
* Represents a reader/writer for compact Thrift data.
*/
struct
_FbThrift
{
GObject
parent
;
FbThriftPrivate
*
priv
;
};
G_DEFINE_TYPE_WITH_PRIVATE
(
FbThrift
,
fb_thrift
,
G_TYPE_OBJECT
);
static
void
fb_thrift_dispose
(
GObject
*
obj
)
{
FbThriftPrivate
*
priv
=
FB_THRIFT
(
obj
)
->
priv
;
if
(
priv
->
internal
)
{
g_byte_array_free
(
priv
->
bytes
,
TRUE
);
}
}
static
void
fb_thrift_class_init
(
FbThriftClass
*
klass
)
{
GObjectClass
*
gklass
=
G_OBJECT_CLASS
(
klass
);
gklass
->
dispose
=
fb_thrift_dispose
;
}
static
void
fb_thrift_init
(
FbThrift
*
thft
)
{
FbThriftPrivate
*
priv
=
fb_thrift_get_instance_private
(
thft
);
thft
->
priv
=
priv
;
}
FbThrift
*
fb_thrift_new
(
GByteArray
*
bytes
,
guint
offset
)
{
FbThrift
*
thft
;
FbThriftPrivate
*
priv
;
thft
=
g_object_new
(
FB_TYPE_THRIFT
,
NULL
);
priv
=
thft
->
priv
;
if
(
bytes
!=
NULL
)
{
priv
->
bytes
=
bytes
;
priv
->
offset
=
offset
;
priv
->
pos
=
offset
;
}
else
{
priv
->
bytes
=
g_byte_array_new
();
priv
->
internal
=
TRUE
;
}
return
thft
;
}
const
GByteArray
*
fb_thrift_get_bytes
(
FbThrift
*
thft
)
{
FbThriftPrivate
*
priv
;
g_return_val_if_fail
(
FB_IS_THRIFT
(
thft
),
NULL
);
priv
=
thft
->
priv
;
return
priv
->
bytes
;
}
guint
fb_thrift_get_pos
(
FbThrift
*
thft
)
{
FbThriftPrivate
*
priv
;
g_return_val_if_fail
(
FB_IS_THRIFT
(
thft
),
0
);
priv
=
thft
->
priv
;
return
priv
->
pos
;
}
void
fb_thrift_set_pos
(
FbThrift
*
thft
,
guint
pos
)
{
FbThriftPrivate
*
priv
;
g_return_if_fail
(
FB_IS_THRIFT
(
thft
));
priv
=
thft
->
priv
;
priv
->
pos
=
pos
;
}
void
fb_thrift_reset
(
FbThrift
*
thft
)
{
FbThriftPrivate
*
priv
;
g_return_if_fail
(
FB_IS_THRIFT
(
thft
));
priv
=
thft
->
priv
;
priv
->
pos
=
priv
->
offset
;
}
gboolean
fb_thrift_read
(
FbThrift
*
thft
,
gpointer
data
,
guint
size
)
{
FbThriftPrivate
*
priv
;
g_return_val_if_fail
(
FB_IS_THRIFT
(
thft
),
FALSE
);
priv
=
thft
->
priv
;
if
((
priv
->
pos
+
size
)
>
priv
->
bytes
->
len
)
{
return
FALSE
;
}
if
((
data
!=
NULL
)
&&
(
size
>
0
))
{
memcpy
(
data
,
priv
->
bytes
->
data
+
priv
->
pos
,
size
);
}
priv
->
pos
+=
size
;
return
TRUE
;
}
gboolean
fb_thrift_read_bool
(
FbThrift
*
thft
,
gboolean
*
value
)
{
FbThriftPrivate
*
priv
;
guint8
byte
;
g_return_val_if_fail
(
FB_IS_THRIFT
(
thft
),
FALSE
);
priv
=
thft
->
priv
;
if
((
priv
->
lastbool
&
0x03
)
!=
0x01
)
{
if
(
!
fb_thrift_read_byte
(
thft
,
&
byte
))
{
return
FALSE
;
}
if
(
value
!=
NULL
)
{
*
value
=
(
byte
&
0x0F
)
==
0x01
;
}
priv
->
lastbool
=
0
;
return
TRUE
;
}
if
(
value
!=
NULL
)
{
*
value
=
((
priv
->
lastbool
&
0x04
)
>>
2
)
!=
0
;
}
priv
->
lastbool
=
0
;
return
TRUE
;
}
gboolean
fb_thrift_read_byte
(
FbThrift
*
thft
,
guint8
*
value
)
{
return
fb_thrift_read
(
thft
,
value
,
sizeof
*
value
);
}
gboolean
fb_thrift_read_dbl
(
FbThrift
*
thft
,
gdouble
*
value
)
{
gint64
i64
;
/* Almost always 8, but check anyways */
static
const
gsize
size
=
MIN
(
sizeof
value
,
sizeof
i64
);
if
(
!
fb_thrift_read_i64
(
thft
,
&
i64
))
{
return
FALSE
;
}
if
(
value
!=
NULL
)
{
memcpy
(
value
,
&
i64
,
size
);
}
return
TRUE
;
}
gboolean
fb_thrift_read_i16
(
FbThrift
*
thft
,
gint16
*
value
)
{
gint64
i64
;
if
(
!
fb_thrift_read_i64
(
thft
,
&
i64
))
{
return
FALSE
;
}
if
(
value
!=
NULL
)
{
*
value
=
i64
;
}
return
TRUE
;
}
gboolean
fb_thrift_read_vi16
(
FbThrift
*
thft
,
guint16
*
value
)
{
guint64
u64
;
if
(
!
fb_thrift_read_vi64
(
thft
,
&
u64
))
{
return
FALSE
;
}
if
(
value
!=
NULL
)
{
*
value
=
u64
;
}
return
TRUE
;
}
gboolean
fb_thrift_read_i32
(
FbThrift
*
thft
,
gint32
*
value
)
{
gint64
i64
;
if
(
!
fb_thrift_read_i64
(
thft
,
&
i64
))
{
return
FALSE
;
}
if
(
value
!=
NULL
)
{
*
value
=
i64
;
}
return
TRUE
;
}
gboolean
fb_thrift_read_vi32
(
FbThrift
*
thft
,
guint32
*
value
)
{
guint64
u64
;
if
(
!
fb_thrift_read_vi64
(
thft
,
&
u64
))
{
return
FALSE
;
}
if
(
value
!=
NULL
)
{
*
value
=
u64
;
}
return
TRUE
;
}
gboolean
fb_thrift_read_i64
(
FbThrift
*
thft
,
gint64
*
value
)
{
guint64
u64
;
if
(
!
fb_thrift_read_vi64
(
thft
,
&
u64
))
{
return
FALSE
;
}
if
(
value
!=
NULL
)
{
/* Convert from zigzag to integer */
*
value
=
(
u64
>>
0x01
)
^
-
(
u64
&
0x01
);
}
return
TRUE
;
}
gboolean
fb_thrift_read_vi64
(
FbThrift
*
thft
,
guint64
*
value
)
{
guint
i
=
0
;
guint8
byte
;
guint64
u64
=
0
;
do
{
if
(
!
fb_thrift_read_byte
(
thft
,
&
byte
))
{
return
FALSE
;
}
u64
|=
((
guint64
)
(
byte
&
0x7F
))
<<
i
;
i
+=
7
;
}
while
((
byte
&
0x80
)
==
0x80
);
if
(
value
!=
NULL
)
{
*
value
=
u64
;
}
return
TRUE
;
}
gboolean
fb_thrift_read_str
(
FbThrift
*
thft
,
gchar
**
value
)
{
guint8
*
data
;
guint32
size
;
if
(
!
fb_thrift_read_vi32
(
thft
,
&
size
))
{
return
FALSE
;
}
if
(
value
!=
NULL
)
{
data
=
g_new
(
guint8
,
size
+
1
);
data
[
size
]
=
0
;
}
else
{
data
=
NULL
;
}
if
(
!
fb_thrift_read
(
thft
,
data
,
size
))
{
g_free
(
data
);
return
FALSE
;
}
if
(
value
!=
NULL
)
{
*
value
=
(
gchar
*
)
data
;
}
return
TRUE
;
}
gboolean
fb_thrift_read_field
(
FbThrift
*
thft
,
FbThriftType
*
type
,
gint16
*
id
,
gint16
lastid
)
{
FbThriftPrivate
*
priv
;
gint16
i16
;
guint8
byte
;
g_return_val_if_fail
(
FB_IS_THRIFT
(
thft
),
FALSE
);
g_return_val_if_fail
(
type
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
id
!=
NULL
,
FALSE
);
priv
=
thft
->
priv
;
if
(
!
fb_thrift_read_byte
(
thft
,
&
byte
))
{
return
FALSE
;
}
if
(
byte
==
FB_THRIFT_TYPE_STOP
)
{
*
type
=
FB_THRIFT_TYPE_STOP
;
return
FALSE
;
}
*
type
=
fb_thrift_ct2t
(
byte
&
0x0F
);
i16
=
(
byte
&
0xF0
)
>>
4
;
if
(
i16
==
0
)
{
if
(
!
fb_thrift_read_i16
(
thft
,
id
))
{
return
FALSE
;
}
}
else
{
*
id
=
lastid
+
i16
;
}
if
(
*
type
==
FB_THRIFT_TYPE_BOOL
)
{
priv
->
lastbool
=
0x01
;
if
((
byte
&
0x0F
)
==
0x01
)
{
priv
->
lastbool
|=
0x01
<<
2
;
}
}
return
TRUE
;
}
gboolean
fb_thrift_read_stop
(
FbThrift
*
thft
)
{
guint8
byte
;
return
fb_thrift_read_byte
(
thft
,
&
byte
)
&&
(
byte
==
FB_THRIFT_TYPE_STOP
);
}
gboolean
fb_thrift_read_isstop
(
FbThrift
*
thft
)
{
FbThriftPrivate
*
priv
;
guint8
byte
;
g_return_val_if_fail
(
FB_IS_THRIFT
(
thft
),
FALSE
);
priv
=
thft
->
priv
;
if
(
!
fb_thrift_read_byte
(
thft
,
&
byte
))
{
return
FALSE
;
}
priv
->
pos
--
;
return
byte
==
FB_THRIFT_TYPE_STOP
;
}
gboolean
fb_thrift_read_list
(
FbThrift
*
thft
,
FbThriftType
*
type
,
guint
*
size
)
{
guint8
byte
;
guint32
u32
;
g_return_val_if_fail
(
type
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
size
!=
NULL
,
FALSE
);
if
(
!
fb_thrift_read_byte
(
thft
,
&
byte
))
{
return
FALSE
;
}
*
type
=
fb_thrift_ct2t
(
byte
&
0x0F
);
*
size
=
(
byte
&
0xF0
)
>>
4
;
if
(
*
size
==
0x0F
)
{
if
(
!
fb_thrift_read_vi32
(
thft
,
&
u32
))
{
return
FALSE
;
}
*
size
=
u32
;
}
return
TRUE
;
}
gboolean
fb_thrift_read_map
(
FbThrift
*
thft
,
FbThriftType
*
ktype
,
FbThriftType
*
vtype
,
guint
*
size
)
{
gint32
i32
;
guint8
byte
;
g_return_val_if_fail
(
ktype
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
vtype
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
size
!=
NULL
,
FALSE
);
if
(
!
fb_thrift_read_i32
(
thft
,
&
i32
))
{
return
FALSE
;
}
if
(
i32
!=
0
)
{
if
(
!
fb_thrift_read_byte
(
thft
,
&
byte
))
{
return
FALSE
;
}
*
ktype
=
fb_thrift_ct2t
((
byte
&
0xF0
)
>>
4
);
*
vtype
=
fb_thrift_ct2t
(
byte
&
0x0F
);
}
else
{
*
ktype
=
0
;
*
vtype
=
0
;
}
*
size
=
i32
;
return
TRUE
;
}
gboolean
fb_thrift_read_set
(
FbThrift
*
thft
,
FbThriftType
*
type
,
guint
*
size
)
{
return
fb_thrift_read_list
(
thft
,
type
,
size
);
}
void
fb_thrift_write
(
FbThrift
*
thft
,
gconstpointer
data
,
guint
size
)
{
FbThriftPrivate
*
priv
;
g_return_if_fail
(
FB_IS_THRIFT
(
thft
));
priv
=
thft
->
priv
;
g_byte_array_append
(
priv
->
bytes
,
data
,
size
);
priv
->
pos
+=
size
;
}
void
fb_thrift_write_bool
(
FbThrift
*
thft
,
gboolean
value
)
{
FbThriftPrivate
*
priv
;
guint
pos
;
g_return_if_fail
(
FB_IS_THRIFT
(
thft
));
priv
=
thft
->
priv
;
if
((
priv
->
lastbool
&
0x03
)
!=
0x02
)
{
fb_thrift_write_byte
(
thft
,
value
?
0x01
:
0x02
);
return
;
}
pos
=
priv
->
lastbool
>>
3
;
priv
->
lastbool
=
0
;
if
((
pos
>=
priv
->
offset
)
&&
(
pos
<
priv
->
bytes
->
len
))
{
priv
->
bytes
->
data
[
pos
]
&=
~
0x0F
;
priv
->
bytes
->
data
[
pos
]
|=
value
?
0x01
:
0x02
;
}
}
void
fb_thrift_write_byte
(
FbThrift
*
thft
,
guint8
value
)
{
fb_thrift_write
(
thft
,
&
value
,
sizeof
value
);
}
void
fb_thrift_write_dbl
(
FbThrift
*
thft
,
gdouble
value
)
{
gint64
i64
;
/* Almost always 8, but check anyways */
static
const
gsize
size
=
MIN
(
sizeof
value
,
sizeof
i64
);
memcpy
(
&
i64
,
&
value
,
size
);
fb_thrift_write_i64
(
thft
,
i64
);
}
void
fb_thrift_write_i16
(
FbThrift
*
thft
,
gint16
value
)
{
fb_thrift_write_i64
(
thft
,
value
);
}
void
fb_thrift_write_vi16
(
FbThrift
*
thft
,
guint16
value
)
{
fb_thrift_write_vi64
(
thft
,
value
);
}
void
fb_thrift_write_i32
(
FbThrift
*
thft
,
gint32
value
)
{
value
=
(
value
<<
1
)
^
(
value
>>
31
);
fb_thrift_write_vi64
(
thft
,
value
);
}
void
fb_thrift_write_vi32
(
FbThrift
*
thft
,
guint32
value
)
{
fb_thrift_write_vi64
(
thft
,
value
);
}
void
fb_thrift_write_i64
(
FbThrift
*
thft
,
gint64
value
)
{
value
=
(
value
<<
1
)
^
(
value
>>
63
);
fb_thrift_write_vi64
(
thft
,
value
);
}
void
fb_thrift_write_vi64
(
FbThrift
*
thft
,
guint64
value
)
{
gboolean
last
;
guint8
byte
;
do
{
last
=
(
value
&
~
0x7F
)
==
0
;
byte
=
value
&
0x7F
;
if
(
!
last
)
{
byte
|=
0x80
;
value
>>=
7
;
}
fb_thrift_write_byte
(
thft
,
byte
);
}
while
(
!
last
);
}
void
fb_thrift_write_str
(
FbThrift
*
thft
,
const
gchar
*
value
)
{
guint32
size
;
g_return_if_fail
(
value
!=
NULL
);
size
=
strlen
(
value
);
fb_thrift_write_vi32
(
thft
,
size
);
fb_thrift_write
(
thft
,
value
,
size
);
}
void
fb_thrift_write_field
(
FbThrift
*
thft
,
FbThriftType
type
,
gint16
id
,
gint16
lastid
)
{
FbThriftPrivate
*
priv
;
gint16
diff
;
g_return_if_fail
(
FB_IS_THRIFT
(
thft
));
priv
=
thft
->
priv
;
if
(
type
==
FB_THRIFT_TYPE_BOOL
)
{
priv
->
lastbool
=
(
priv
->
pos
<<
3
)
|
0x02
;
}
type
=
fb_thrift_t2ct
(
type
);
diff
=
id
-
lastid
;
if
((
id
<=
lastid
)
||
(
diff
>
0x0F
))
{
fb_thrift_write_byte
(
thft
,
type
);
fb_thrift_write_i16
(
thft
,
id
);
}
else
{
fb_thrift_write_byte
(
thft
,
(
diff
<<
4
)
|
type
);
}
}
void
fb_thrift_write_stop
(
FbThrift
*
thft
)
{
fb_thrift_write_byte
(
thft
,
FB_THRIFT_TYPE_STOP
);
}
void
fb_thrift_write_list
(
FbThrift
*
thft
,
FbThriftType
type
,
guint
size
)
{
type
=
fb_thrift_t2ct
(
type
);
if
(
size
<=
14
)
{
fb_thrift_write_byte
(
thft
,
(
size
<<
4
)
|
type
);
return
;
}
fb_thrift_write_vi32
(
thft
,
size
);
fb_thrift_write_byte
(
thft
,
0xF0
|
type
);
}
void
fb_thrift_write_map
(
FbThrift
*
thft
,
FbThriftType
ktype
,
FbThriftType
vtype
,
guint
size
)
{
if
(
size
==
0
)
{
fb_thrift_write_byte
(
thft
,
0
);
return
;
}
ktype
=
fb_thrift_t2ct
(
ktype
);
vtype
=
fb_thrift_t2ct
(
vtype
);
fb_thrift_write_vi32
(
thft
,
size
);
fb_thrift_write_byte
(
thft
,
(
ktype
<<
4
)
|
vtype
);
}
void
fb_thrift_write_set
(
FbThrift
*
thft
,
FbThriftType
type
,
guint
size
)
{
fb_thrift_write_list
(
thft
,
type
,
size
);
}
guint8
fb_thrift_t2ct
(
FbThriftType
type
)
{
static
const
guint8
types
[]
=
{
[
FB_THRIFT_TYPE_STOP
]
=
0
,
[
FB_THRIFT_TYPE_VOID
]
=
0
,
[
FB_THRIFT_TYPE_BOOL
]
=
2
,
[
FB_THRIFT_TYPE_BYTE
]
=
3
,
[
FB_THRIFT_TYPE_DOUBLE
]
=
7
,
[
5
]
=
0
,
[
FB_THRIFT_TYPE_I16
]
=
4
,
[
7
]
=
0
,
[
FB_THRIFT_TYPE_I32
]
=
5
,
[
9
]
=
0
,
[
FB_THRIFT_TYPE_I64
]
=
6
,
[
FB_THRIFT_TYPE_STRING
]
=
8
,
[
FB_THRIFT_TYPE_STRUCT
]
=
12
,
[
FB_THRIFT_TYPE_MAP
]
=
11
,
[
FB_THRIFT_TYPE_SET
]
=
10
,
[
FB_THRIFT_TYPE_LIST
]
=
9
};
g_return_val_if_fail
(
type
<
G_N_ELEMENTS
(
types
),
0
);
return
types
[
type
];
}
FbThriftType
fb_thrift_ct2t
(
guint8
type
)
{
static
const
guint8
types
[]
=
{
[
0
]
=
FB_THRIFT_TYPE_STOP
,
[
1
]
=
FB_THRIFT_TYPE_BOOL
,
[
2
]
=
FB_THRIFT_TYPE_BOOL
,
[
3
]
=
FB_THRIFT_TYPE_BYTE
,
[
4
]
=
FB_THRIFT_TYPE_I16
,
[
5
]
=
FB_THRIFT_TYPE_I32
,
[
6
]
=
FB_THRIFT_TYPE_I64
,
[
7
]
=
FB_THRIFT_TYPE_DOUBLE
,
[
8
]
=
FB_THRIFT_TYPE_STRING
,
[
9
]
=
FB_THRIFT_TYPE_LIST
,
[
10
]
=
FB_THRIFT_TYPE_SET
,
[
11
]
=
FB_THRIFT_TYPE_MAP
,
[
12
]
=
FB_THRIFT_TYPE_STRUCT
};
g_return_val_if_fail
(
type
<
G_N_ELEMENTS
(
types
),
0
);
return
types
[
type
];
}