| 1 /* |
|
| 2 * Purple's oscar protocol plugin |
|
| 3 * This file is the legal property of its developers. |
|
| 4 * Please see the AUTHORS file distributed alongside this file. |
|
| 5 * |
|
| 6 * This library is free software; you can redistribute it and/or |
|
| 7 * modify it under the terms of the GNU Lesser General Public |
|
| 8 * License as published by the Free Software Foundation; either |
|
| 9 * version 2 of the License, or (at your option) any later version. |
|
| 10 * |
|
| 11 * This library is distributed in the hope that it will be useful, |
|
| 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
| 14 * Lesser General Public License for more details. |
|
| 15 * |
|
| 16 * You should have received a copy of the GNU Lesser General Public |
|
| 17 * License along with this library; if not, write to the Free Software |
|
| 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
|
| 19 */ |
|
| 20 |
|
| 21 /* |
|
| 22 * This file contains all functions needed to use bstreams. |
|
| 23 */ |
|
| 24 |
|
| 25 #include "oscar.h" |
|
| 26 |
|
| 27 int byte_stream_new(ByteStream *bs, size_t len) |
|
| 28 { |
|
| 29 if (bs == NULL) |
|
| 30 return -1; |
|
| 31 |
|
| 32 return byte_stream_init(bs, g_malloc(len), len); |
|
| 33 } |
|
| 34 |
|
| 35 int byte_stream_init(ByteStream *bs, guint8 *data, size_t len) |
|
| 36 { |
|
| 37 if (bs == NULL) |
|
| 38 return -1; |
|
| 39 |
|
| 40 bs->data = data; |
|
| 41 bs->len = len; |
|
| 42 bs->offset = 0; |
|
| 43 |
|
| 44 return 0; |
|
| 45 } |
|
| 46 |
|
| 47 void byte_stream_destroy(ByteStream *bs) |
|
| 48 { |
|
| 49 g_free(bs->data); |
|
| 50 } |
|
| 51 |
|
| 52 size_t byte_stream_bytes_left(ByteStream *bs) |
|
| 53 { |
|
| 54 g_return_val_if_fail(bs != NULL, 0); |
|
| 55 g_return_val_if_fail(bs->len >= bs->offset, 0); |
|
| 56 |
|
| 57 return bs->len - bs->offset; |
|
| 58 } |
|
| 59 |
|
| 60 int byte_stream_curpos(ByteStream *bs) |
|
| 61 { |
|
| 62 return bs->offset; |
|
| 63 } |
|
| 64 |
|
| 65 int byte_stream_setpos(ByteStream *bs, size_t off) |
|
| 66 { |
|
| 67 g_return_val_if_fail(off <= bs->len, -1); |
|
| 68 |
|
| 69 bs->offset = off; |
|
| 70 return off; |
|
| 71 } |
|
| 72 |
|
| 73 void byte_stream_rewind(ByteStream *bs) |
|
| 74 { |
|
| 75 byte_stream_setpos(bs, 0); |
|
| 76 } |
|
| 77 |
|
| 78 /* |
|
| 79 * N can be negative, which can be used for going backwards |
|
| 80 * in a bstream. |
|
| 81 */ |
|
| 82 int byte_stream_advance(ByteStream *bs, int n) |
|
| 83 { |
|
| 84 g_return_val_if_fail(byte_stream_curpos(bs) + n >= 0, 0); |
|
| 85 g_return_val_if_fail((gsize)n <= byte_stream_bytes_left(bs), 0); |
|
| 86 |
|
| 87 bs->offset += n; |
|
| 88 return n; |
|
| 89 } |
|
| 90 |
|
| 91 guint8 byte_stream_get8(ByteStream *bs) |
|
| 92 { |
|
| 93 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0); |
|
| 94 |
|
| 95 bs->offset++; |
|
| 96 return aimutil_get8(bs->data + bs->offset - 1); |
|
| 97 } |
|
| 98 |
|
| 99 guint16 byte_stream_get16(ByteStream *bs) |
|
| 100 { |
|
| 101 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0); |
|
| 102 |
|
| 103 bs->offset += 2; |
|
| 104 return aimutil_get16(bs->data + bs->offset - 2); |
|
| 105 } |
|
| 106 |
|
| 107 guint32 byte_stream_get32(ByteStream *bs) |
|
| 108 { |
|
| 109 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0); |
|
| 110 |
|
| 111 bs->offset += 4; |
|
| 112 return aimutil_get32(bs->data + bs->offset - 4); |
|
| 113 } |
|
| 114 |
|
| 115 guint8 byte_stream_getle8(ByteStream *bs) |
|
| 116 { |
|
| 117 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0); |
|
| 118 |
|
| 119 bs->offset++; |
|
| 120 return aimutil_getle8(bs->data + bs->offset - 1); |
|
| 121 } |
|
| 122 |
|
| 123 guint16 byte_stream_getle16(ByteStream *bs) |
|
| 124 { |
|
| 125 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0); |
|
| 126 |
|
| 127 bs->offset += 2; |
|
| 128 return aimutil_getle16(bs->data + bs->offset - 2); |
|
| 129 } |
|
| 130 |
|
| 131 guint32 byte_stream_getle32(ByteStream *bs) |
|
| 132 { |
|
| 133 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0); |
|
| 134 |
|
| 135 bs->offset += 4; |
|
| 136 return aimutil_getle32(bs->data + bs->offset - 4); |
|
| 137 } |
|
| 138 |
|
| 139 static void byte_stream_getrawbuf_nocheck(ByteStream *bs, guint8 *buf, size_t len) |
|
| 140 { |
|
| 141 memcpy(buf, bs->data + bs->offset, len); |
|
| 142 bs->offset += len; |
|
| 143 } |
|
| 144 |
|
| 145 int byte_stream_getrawbuf(ByteStream *bs, guint8 *buf, size_t len) |
|
| 146 { |
|
| 147 g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0); |
|
| 148 |
|
| 149 byte_stream_getrawbuf_nocheck(bs, buf, len); |
|
| 150 return len; |
|
| 151 } |
|
| 152 |
|
| 153 guint8 *byte_stream_getraw(ByteStream *bs, size_t len) |
|
| 154 { |
|
| 155 guint8 *ob; |
|
| 156 |
|
| 157 g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, NULL); |
|
| 158 |
|
| 159 ob = g_malloc(len); |
|
| 160 byte_stream_getrawbuf_nocheck(bs, ob, len); |
|
| 161 return ob; |
|
| 162 } |
|
| 163 |
|
| 164 char *byte_stream_getstr(ByteStream *bs, size_t len) |
|
| 165 { |
|
| 166 char *ob; |
|
| 167 |
|
| 168 g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, NULL); |
|
| 169 |
|
| 170 ob = g_malloc(len + 1); |
|
| 171 byte_stream_getrawbuf_nocheck(bs, (guint8 *)ob, len); |
|
| 172 ob[len] = '\0'; |
|
| 173 return ob; |
|
| 174 } |
|
| 175 |
|
| 176 int byte_stream_put8(ByteStream *bs, guint8 v) |
|
| 177 { |
|
| 178 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0); |
|
| 179 |
|
| 180 bs->offset += aimutil_put8(bs->data + bs->offset, v); |
|
| 181 return 1; |
|
| 182 } |
|
| 183 |
|
| 184 int byte_stream_put16(ByteStream *bs, guint16 v) |
|
| 185 { |
|
| 186 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0); |
|
| 187 |
|
| 188 bs->offset += aimutil_put16(bs->data + bs->offset, v); |
|
| 189 return 2; |
|
| 190 } |
|
| 191 |
|
| 192 int byte_stream_put32(ByteStream *bs, guint32 v) |
|
| 193 { |
|
| 194 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0); |
|
| 195 |
|
| 196 bs->offset += aimutil_put32(bs->data + bs->offset, v); |
|
| 197 return 1; |
|
| 198 } |
|
| 199 |
|
| 200 int byte_stream_putle8(ByteStream *bs, guint8 v) |
|
| 201 { |
|
| 202 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 1, 0); |
|
| 203 |
|
| 204 bs->offset += aimutil_putle8(bs->data + bs->offset, v); |
|
| 205 return 1; |
|
| 206 } |
|
| 207 |
|
| 208 int byte_stream_putle16(ByteStream *bs, guint16 v) |
|
| 209 { |
|
| 210 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 2, 0); |
|
| 211 |
|
| 212 bs->offset += aimutil_putle16(bs->data + bs->offset, v); |
|
| 213 return 2; |
|
| 214 } |
|
| 215 |
|
| 216 int byte_stream_putle32(ByteStream *bs, guint32 v) |
|
| 217 { |
|
| 218 g_return_val_if_fail(byte_stream_bytes_left(bs) >= 4, 0); |
|
| 219 |
|
| 220 bs->offset += aimutil_putle32(bs->data + bs->offset, v); |
|
| 221 return 1; |
|
| 222 } |
|
| 223 |
|
| 224 |
|
| 225 int byte_stream_putraw(ByteStream *bs, const guint8 *v, size_t len) |
|
| 226 { |
|
| 227 g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0); |
|
| 228 |
|
| 229 memcpy(bs->data + bs->offset, v, len); |
|
| 230 bs->offset += len; |
|
| 231 return len; |
|
| 232 } |
|
| 233 |
|
| 234 int byte_stream_putstr(ByteStream *bs, const char *str) |
|
| 235 { |
|
| 236 return byte_stream_putraw(bs, (guint8 *)str, strlen(str)); |
|
| 237 } |
|
| 238 |
|
| 239 int byte_stream_putbs(ByteStream *bs, ByteStream *srcbs, size_t len) |
|
| 240 { |
|
| 241 g_return_val_if_fail(byte_stream_bytes_left(srcbs) >= len, 0); |
|
| 242 g_return_val_if_fail(byte_stream_bytes_left(bs) >= len, 0); |
|
| 243 |
|
| 244 memcpy(bs->data + bs->offset, srcbs->data + srcbs->offset, len); |
|
| 245 bs->offset += len; |
|
| 246 srcbs->offset += len; |
|
| 247 return len; |
|
| 248 } |
|
| 249 |
|
| 250 int byte_stream_putuid(ByteStream *bs, OscarData *od) |
|
| 251 { |
|
| 252 PurpleAccount *account; |
|
| 253 |
|
| 254 account = purple_connection_get_account(od->gc); |
|
| 255 |
|
| 256 return byte_stream_putle32(bs, atoi(purple_account_get_username(account))); |
|
| 257 } |
|
| 258 |
|
| 259 void byte_stream_put_bart_asset(ByteStream *bs, guint16 type, ByteStream *data) |
|
| 260 { |
|
| 261 byte_stream_put16(bs, type); |
|
| 262 |
|
| 263 if (data != NULL && data->len > 0) { |
|
| 264 /* Flags. 0x04 means "this asset has data attached to it" */ |
|
| 265 byte_stream_put8(bs, 0x04); /* Flags */ |
|
| 266 byte_stream_put8(bs, data->len); /* Length */ |
|
| 267 byte_stream_rewind(data); |
|
| 268 byte_stream_putbs(bs, data, data->len); /* Data */ |
|
| 269 } else { |
|
| 270 byte_stream_put8(bs, 0x00); /* No flags */ |
|
| 271 byte_stream_put8(bs, 0x00); /* Length */ |
|
| 272 /* No data */ |
|
| 273 } |
|
| 274 } |
|
| 275 |
|
| 276 void byte_stream_put_bart_asset_str(ByteStream *bs, guint16 type, const char *datastr) |
|
| 277 { |
|
| 278 ByteStream data; |
|
| 279 size_t len = datastr != NULL ? strlen(datastr) : 0; |
|
| 280 |
|
| 281 if (len > 0) { |
|
| 282 byte_stream_new(&data, 2 + len + 2); |
|
| 283 byte_stream_put16(&data, len); /* Length */ |
|
| 284 byte_stream_putstr(&data, datastr); /* String */ |
|
| 285 byte_stream_put16(&data, 0x0000); /* Unknown */ |
|
| 286 byte_stream_put_bart_asset(bs, type, &data); |
|
| 287 byte_stream_destroy(&data); |
|
| 288 } else { |
|
| 289 byte_stream_put_bart_asset(bs, type, NULL); |
|
| 290 } |
|
| 291 } |
|