00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <stdarg.h>
00018 #include <string.h>
00019 #include <stdlib.h>
00020
00021 #include <errno.h>
00022 #include <time.h>
00023 #include <assert.h>
00024
00025 #include "xmmspriv/xmms_list.h"
00026 #include "xmmsc/xmmsc_ipc_transport.h"
00027 #include "xmmsc/xmmsc_ipc_msg.h"
00028 #include "xmmsc/xmmsc_util.h"
00029 #include "xmmsc/xmmsc_sockets.h"
00030 #include "xmmsc/xmmsc_stdint.h"
00031 #include "xmmsc/xmmsv_coll.h"
00032
00033
00034 typedef union {
00035 struct {
00036 uint32_t object;
00037 uint32_t cmd;
00038 uint32_t cookie;
00039 uint32_t length;
00040 uint8_t data[0];
00041 } header;
00042 uint8_t rawdata[0];
00043 } xmms_ipc_msg_data_t;
00044
00045 struct xmms_ipc_msg_St {
00046 xmms_ipc_msg_data_t *data;
00047 uint32_t get_pos;
00048 uint32_t size;
00049 uint32_t xfered;
00050 };
00051
00052 static void xmms_ipc_msg_store_uint32 (xmms_ipc_msg_t *msg, uint32_t offset, uint32_t v);
00053
00054 static uint32_t internal_ipc_msg_put_bin (xmms_ipc_msg_t *msg, const unsigned char *data, unsigned int len);
00055 static uint32_t internal_ipc_msg_put_error (xmms_ipc_msg_t *msg, const char *errmsg);
00056 static uint32_t internal_ipc_msg_put_uint32 (xmms_ipc_msg_t *msg, uint32_t v);
00057 static uint32_t internal_ipc_msg_put_int32 (xmms_ipc_msg_t *msg, int32_t v);
00058 static uint32_t internal_ipc_msg_put_string (xmms_ipc_msg_t *msg, const char *str);
00059 static uint32_t internal_ipc_msg_put_collection (xmms_ipc_msg_t *msg, xmmsv_coll_t *coll);
00060 static uint32_t internal_ipc_msg_put_value_list (xmms_ipc_msg_t *msg, xmmsv_t *v);
00061 static uint32_t internal_ipc_msg_put_value_dict (xmms_ipc_msg_t *msg, xmmsv_t *v);
00062
00063 static bool xmms_ipc_msg_get_error_alloc (xmms_ipc_msg_t *msg, char **buf, unsigned int *len);
00064 static bool xmms_ipc_msg_get_uint32 (xmms_ipc_msg_t *msg, uint32_t *v);
00065 static bool xmms_ipc_msg_get_int32 (xmms_ipc_msg_t *msg, int32_t *v);
00066 static bool xmms_ipc_msg_get_string_alloc (xmms_ipc_msg_t *msg, char **buf, unsigned int *len);
00067 static bool xmms_ipc_msg_get_collection_alloc (xmms_ipc_msg_t *msg, xmmsv_coll_t **coll);
00068 static bool xmms_ipc_msg_get_bin_alloc (xmms_ipc_msg_t *msg, unsigned char **buf, unsigned int *len);
00069
00070 static bool xmms_ipc_msg_get_value_alloc (xmms_ipc_msg_t *msg, xmmsv_t **val);
00071 static bool xmms_ipc_msg_get_value_of_type_alloc (xmms_ipc_msg_t *msg, xmmsv_type_t type, xmmsv_t **val);
00072
00073 static void
00074 xmms_ipc_append_coll_attr (const char *key, xmmsv_t *value, void *userdata)
00075 {
00076 xmms_ipc_msg_t *msg = (xmms_ipc_msg_t *)userdata;
00077 const char *s;
00078 int r;
00079
00080 r = xmmsv_get_string (value, &s);
00081 x_return_if_fail (r);
00082
00083 internal_ipc_msg_put_string (msg, key);
00084 internal_ipc_msg_put_string (msg, s);
00085 }
00086
00087 static void
00088 xmms_ipc_count_coll_attr (const char *key, xmmsv_t *value, void *userdata)
00089 {
00090 int *n = (int *)userdata;
00091 ++(*n);
00092 }
00093
00094
00095 xmms_ipc_msg_t *
00096 xmms_ipc_msg_alloc (void)
00097 {
00098 xmms_ipc_msg_t *msg;
00099
00100 msg = x_new0 (xmms_ipc_msg_t, 1);
00101 msg->data = malloc (XMMS_IPC_MSG_DEFAULT_SIZE);
00102 memset (msg->data, 0, XMMS_IPC_MSG_HEAD_LEN);
00103 msg->size = XMMS_IPC_MSG_DEFAULT_SIZE;
00104
00105 return msg;
00106 }
00107
00108 xmms_ipc_msg_t *
00109 xmms_ipc_msg_new (uint32_t object, uint32_t cmd)
00110 {
00111 xmms_ipc_msg_t *msg;
00112
00113 msg = xmms_ipc_msg_alloc ();
00114
00115 xmms_ipc_msg_set_cmd (msg, cmd);
00116 xmms_ipc_msg_set_object (msg, object);
00117
00118 return msg;
00119 }
00120
00121 void
00122 xmms_ipc_msg_destroy (xmms_ipc_msg_t *msg)
00123 {
00124 x_return_if_fail (msg);
00125
00126 free (msg->data);
00127 free (msg);
00128 }
00129
00130 void
00131 xmms_ipc_msg_set_length (xmms_ipc_msg_t *msg, uint32_t len)
00132 {
00133 x_return_if_fail (msg);
00134
00135 msg->data->header.length = htonl (len);
00136 }
00137
00138 uint32_t
00139 xmms_ipc_msg_get_length (const xmms_ipc_msg_t *msg)
00140 {
00141 x_return_val_if_fail (msg, 0);
00142
00143 return ntohl (msg->data->header.length);
00144 }
00145
00146 uint32_t
00147 xmms_ipc_msg_get_object (const xmms_ipc_msg_t *msg)
00148 {
00149 x_return_val_if_fail (msg, 0);
00150
00151 return ntohl (msg->data->header.object);
00152 }
00153
00154 void
00155 xmms_ipc_msg_set_object (xmms_ipc_msg_t *msg, uint32_t object)
00156 {
00157 x_return_if_fail (msg);
00158
00159 msg->data->header.object = htonl (object);
00160 }
00161
00162 uint32_t
00163 xmms_ipc_msg_get_cmd (const xmms_ipc_msg_t *msg)
00164 {
00165 x_return_val_if_fail (msg, 0);
00166
00167 return ntohl (msg->data->header.cmd);
00168 }
00169
00170 void
00171 xmms_ipc_msg_set_cmd (xmms_ipc_msg_t *msg, uint32_t cmd)
00172 {
00173 x_return_if_fail (msg);
00174
00175 msg->data->header.cmd = htonl (cmd);
00176 }
00177
00178 void
00179 xmms_ipc_msg_set_cookie (xmms_ipc_msg_t *msg, uint32_t cookie)
00180 {
00181 msg->data->header.cookie = htonl (cookie);
00182 }
00183
00184 uint32_t
00185 xmms_ipc_msg_get_cookie (const xmms_ipc_msg_t *msg)
00186 {
00187 x_return_val_if_fail (msg, 0);
00188
00189 return ntohl (msg->data->header.cookie);
00190 }
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 bool
00201 xmms_ipc_msg_write_transport (xmms_ipc_msg_t *msg,
00202 xmms_ipc_transport_t *transport,
00203 bool *disconnected)
00204 {
00205 char *buf;
00206 unsigned int ret, len;
00207
00208 x_return_val_if_fail (msg, false);
00209 x_return_val_if_fail (msg->data, false);
00210 x_return_val_if_fail (transport, false);
00211
00212 len = xmms_ipc_msg_get_length (msg) + XMMS_IPC_MSG_HEAD_LEN;
00213
00214 x_return_val_if_fail (len > msg->xfered, true);
00215
00216 buf = (char *) (msg->data->rawdata + msg->xfered);
00217 ret = xmms_ipc_transport_write (transport, buf, len - msg->xfered);
00218
00219 if (ret == SOCKET_ERROR) {
00220 if (xmms_socket_error_recoverable ()) {
00221 return false;
00222 }
00223
00224 if (disconnected) {
00225 *disconnected = true;
00226 }
00227
00228 return false;
00229 } else if (!ret) {
00230 if (disconnected) {
00231 *disconnected = true;
00232 }
00233 } else {
00234 msg->xfered += ret;
00235 }
00236
00237 return (len == msg->xfered);
00238 }
00239
00240
00241
00242
00243
00244
00245 bool
00246 xmms_ipc_msg_read_transport (xmms_ipc_msg_t *msg,
00247 xmms_ipc_transport_t *transport,
00248 bool *disconnected)
00249 {
00250 char *buf;
00251 unsigned int ret, len;
00252
00253 x_return_val_if_fail (msg, false);
00254 x_return_val_if_fail (transport, false);
00255
00256 while (true) {
00257 len = XMMS_IPC_MSG_HEAD_LEN;
00258
00259 if (msg->xfered >= XMMS_IPC_MSG_HEAD_LEN) {
00260 len += xmms_ipc_msg_get_length (msg);
00261
00262 if (len > msg->size) {
00263 void *newbuf;
00264 newbuf = realloc (msg->data, len);
00265 if (!newbuf) {
00266 if (disconnected) {
00267 *disconnected = true;
00268 }
00269 return false;
00270 }
00271 msg->size = len;
00272 msg->data = newbuf;
00273 }
00274
00275 if (msg->xfered == len) {
00276 return true;
00277 }
00278 }
00279
00280 x_return_val_if_fail (msg->xfered < len, false);
00281
00282 buf = (char *) (msg->data->rawdata + msg->xfered);
00283 ret = xmms_ipc_transport_read (transport, buf, len - msg->xfered);
00284
00285 if (ret == SOCKET_ERROR) {
00286 if (xmms_socket_error_recoverable ()) {
00287 return false;
00288 }
00289
00290 if (disconnected) {
00291 *disconnected = true;
00292 }
00293
00294 return false;
00295 } else if (ret == 0) {
00296 if (disconnected) {
00297 *disconnected = true;
00298 }
00299
00300 return false;
00301 } else {
00302 msg->xfered += ret;
00303 }
00304 }
00305 }
00306
00307 static uint32_t
00308 xmms_ipc_msg_put_data (xmms_ipc_msg_t *msg, const void *data, unsigned int len)
00309 {
00310 uint32_t total;
00311
00312 x_return_val_if_fail (msg, -1);
00313
00314 total = xmms_ipc_msg_get_length (msg) + XMMS_IPC_MSG_HEAD_LEN + len;
00315
00316 if (total > msg->size) {
00317 int realloc_size = XMMS_IPC_MSG_DEFAULT_SIZE;
00318
00319 if (len > XMMS_IPC_MSG_DEFAULT_SIZE) {
00320 realloc_size = len;
00321 }
00322
00323
00324 msg->data = realloc (msg->data, msg->size + realloc_size);
00325 msg->size += realloc_size;
00326 }
00327
00328 total = xmms_ipc_msg_get_length (msg);
00329 memcpy (&msg->data->header.data[total], data, len);
00330 xmms_ipc_msg_set_length (msg, total + len);
00331
00332
00333
00334
00335
00336
00337 return total;
00338 }
00339
00340 static uint32_t
00341 internal_ipc_msg_put_bin (xmms_ipc_msg_t *msg,
00342 const unsigned char *data,
00343 unsigned int len)
00344 {
00345 internal_ipc_msg_put_uint32 (msg, len);
00346
00347 return xmms_ipc_msg_put_data (msg, data, len);
00348 }
00349
00350 static uint32_t
00351 internal_ipc_msg_put_error (xmms_ipc_msg_t *msg, const char *errmsg)
00352 {
00353 if (!msg) {
00354 return -1;
00355 }
00356
00357 if (!errmsg) {
00358 return internal_ipc_msg_put_uint32 (msg, 0);
00359 }
00360
00361 internal_ipc_msg_put_uint32 (msg, strlen (errmsg) + 1);
00362
00363 return xmms_ipc_msg_put_data (msg, errmsg, strlen (errmsg) + 1);
00364 }
00365
00366 static uint32_t
00367 internal_ipc_msg_put_uint32 (xmms_ipc_msg_t *msg, uint32_t v)
00368 {
00369 v = htonl (v);
00370
00371 return xmms_ipc_msg_put_data (msg, &v, sizeof (v));
00372 }
00373
00374 static void
00375 xmms_ipc_msg_store_uint32 (xmms_ipc_msg_t *msg,
00376 uint32_t offset, uint32_t v)
00377 {
00378 v = htonl (v);
00379
00380 memcpy (&msg->data->header.data[offset], &v, sizeof (v));
00381 }
00382
00383 static uint32_t
00384 internal_ipc_msg_put_int32 (xmms_ipc_msg_t *msg, int32_t v)
00385 {
00386 v = htonl (v);
00387
00388 return xmms_ipc_msg_put_data (msg, &v, sizeof (v));
00389 }
00390
00391 static uint32_t
00392 internal_ipc_msg_put_string (xmms_ipc_msg_t *msg, const char *str)
00393 {
00394 if (!msg) {
00395 return -1;
00396 }
00397
00398 if (!str) {
00399 return internal_ipc_msg_put_uint32 (msg, 0);
00400 }
00401
00402 internal_ipc_msg_put_uint32 (msg, strlen (str) + 1);
00403
00404 return xmms_ipc_msg_put_data (msg, str, strlen (str) + 1);
00405 }
00406
00407 static uint32_t
00408 internal_ipc_msg_put_collection (xmms_ipc_msg_t *msg, xmmsv_coll_t *coll)
00409 {
00410 xmmsv_list_iter_t *it;
00411 xmmsv_t *v, *attrs;
00412 int n;
00413 uint32_t ret, *idlist;
00414 xmmsv_coll_t *op;
00415
00416 if (!msg || !coll) {
00417 return -1;
00418 }
00419
00420
00421 internal_ipc_msg_put_uint32 (msg, xmmsv_coll_get_type (coll));
00422
00423
00424 attrs = xmmsv_coll_attributes_get (coll);
00425 n = 0;
00426
00427 xmmsv_dict_foreach (attrs, xmms_ipc_count_coll_attr, &n);
00428 internal_ipc_msg_put_uint32 (msg, n);
00429
00430 xmmsv_dict_foreach (attrs, xmms_ipc_append_coll_attr, msg);
00431
00432 attrs = NULL;
00433
00434
00435 idlist = xmmsv_coll_get_idlist (coll);
00436 for (n = 0; idlist[n] != 0; n++) { }
00437
00438 internal_ipc_msg_put_uint32 (msg, n);
00439 for (n = 0; idlist[n] != 0; n++) {
00440 internal_ipc_msg_put_uint32 (msg, idlist[n]);
00441 }
00442
00443
00444 n = 0;
00445 if (xmmsv_coll_get_type (coll) != XMMS_COLLECTION_TYPE_REFERENCE) {
00446 n = xmmsv_list_get_size (xmmsv_coll_operands_get (coll));
00447 }
00448
00449 ret = internal_ipc_msg_put_uint32 (msg, n);
00450
00451 if (n > 0) {
00452 xmmsv_get_list_iter (xmmsv_coll_operands_get (coll), &it);
00453
00454 while (xmmsv_list_iter_entry (it, &v)) {
00455 if (!xmmsv_get_coll (v, &op)) {
00456 x_api_error ("Non collection operand", 0);
00457 }
00458
00459 internal_ipc_msg_put_int32 (msg, XMMSV_TYPE_COLL);
00460
00461 ret = internal_ipc_msg_put_collection (msg, op);
00462 xmmsv_list_iter_next (it);
00463 }
00464 }
00465
00466 return ret;
00467 }
00468
00469 uint32_t
00470 xmms_ipc_msg_put_value (xmms_ipc_msg_t *msg, xmmsv_t *v)
00471 {
00472 uint32_t ret;
00473 int32_t i;
00474 const char *s;
00475 xmmsv_coll_t *c;
00476 const unsigned char *bc;
00477 unsigned int bl;
00478 xmmsv_type_t type;
00479
00480 type = xmmsv_get_type (v);
00481 internal_ipc_msg_put_int32 (msg, type);
00482
00483
00484
00485
00486 switch (type) {
00487 case XMMSV_TYPE_ERROR:
00488 if (!xmmsv_get_error (v, &s)) {
00489 return -1;
00490 }
00491 ret = internal_ipc_msg_put_error (msg, s);
00492 break;
00493 case XMMSV_TYPE_INT32:
00494 if (!xmmsv_get_int (v, &i)) {
00495 return -1;
00496 }
00497 ret = internal_ipc_msg_put_int32 (msg, i);
00498 break;
00499 case XMMSV_TYPE_STRING:
00500 if (!xmmsv_get_string (v, &s)) {
00501 return -1;
00502 }
00503 ret = internal_ipc_msg_put_string (msg, s);
00504 break;
00505 case XMMSV_TYPE_COLL:
00506 if (!xmmsv_get_coll (v, &c)) {
00507 return -1;
00508 }
00509 ret = internal_ipc_msg_put_collection (msg, c);
00510 break;
00511 case XMMSV_TYPE_BIN:
00512 if (!xmmsv_get_bin (v, &bc, &bl)) {
00513 return -1;
00514 }
00515 ret = internal_ipc_msg_put_bin (msg, bc, bl);
00516 break;
00517 case XMMSV_TYPE_LIST:
00518 ret = internal_ipc_msg_put_value_list (msg, v);
00519 break;
00520 case XMMSV_TYPE_DICT:
00521 ret = internal_ipc_msg_put_value_dict (msg, v);
00522 break;
00523
00524 case XMMSV_TYPE_NONE:
00525
00526
00527
00528
00529 ret = xmms_ipc_msg_get_length (msg);
00530 break;
00531 default:
00532 x_internal_error ("Tried to serialize value of unsupported type");
00533 return -1;
00534 }
00535
00536 return ret;
00537 }
00538
00539 static uint32_t
00540 internal_ipc_msg_put_value_list (xmms_ipc_msg_t *msg, xmmsv_t *v)
00541 {
00542 xmmsv_list_iter_t *it;
00543 xmmsv_t *entry;
00544 uint32_t ret, offset, count;
00545
00546 if (!xmmsv_get_list_iter (v, &it)) {
00547 return -1;
00548 }
00549
00550
00551 offset = internal_ipc_msg_put_uint32 (msg, 0);
00552
00553 count = 0;
00554 while (xmmsv_list_iter_valid (it)) {
00555 xmmsv_list_iter_entry (it, &entry);
00556 ret = xmms_ipc_msg_put_value (msg, entry);
00557 xmmsv_list_iter_next (it);
00558 count++;
00559 }
00560
00561
00562 xmms_ipc_msg_store_uint32 (msg, offset, count);
00563
00564 return ret;
00565 }
00566
00567 static uint32_t
00568 internal_ipc_msg_put_value_dict (xmms_ipc_msg_t *msg, xmmsv_t *v)
00569 {
00570 xmmsv_dict_iter_t *it;
00571 const char *key;
00572 xmmsv_t *entry;
00573 uint32_t ret, offset, count;
00574
00575 if (!xmmsv_get_dict_iter (v, &it)) {
00576 return -1;
00577 }
00578
00579
00580 offset = internal_ipc_msg_put_uint32 (msg, 0);
00581
00582 count = 0;
00583 while (xmmsv_dict_iter_valid (it)) {
00584 xmmsv_dict_iter_pair (it, &key, &entry);
00585 ret = internal_ipc_msg_put_string (msg, key);
00586 ret = xmms_ipc_msg_put_value (msg, entry);
00587 xmmsv_dict_iter_next (it);
00588 count++;
00589 }
00590
00591
00592 xmms_ipc_msg_store_uint32 (msg, offset, count);
00593
00594 return ret;
00595 }
00596
00597
00598 static bool
00599 xmms_ipc_msg_get_data (xmms_ipc_msg_t *msg, void *buf, unsigned int len)
00600 {
00601 if (!msg)
00602 return false;
00603
00604 if (len > xmms_ipc_msg_get_length (msg) - msg->get_pos)
00605 return false;
00606
00607 if (buf) {
00608 memcpy (buf, &msg->data->header.data[msg->get_pos], len);
00609 }
00610
00611 msg->get_pos += len;
00612
00613 return true;
00614 }
00615
00616 static bool
00617 xmms_ipc_msg_get_error_alloc (xmms_ipc_msg_t *msg, char **buf,
00618 unsigned int *len)
00619 {
00620
00621 return xmms_ipc_msg_get_string_alloc (msg, buf, len);
00622 }
00623
00624 static bool
00625 xmms_ipc_msg_get_uint32 (xmms_ipc_msg_t *msg, uint32_t *v)
00626 {
00627 bool ret;
00628
00629 ret = xmms_ipc_msg_get_data (msg, v, sizeof (*v));
00630
00631 if (v) {
00632 *v = ntohl (*v);
00633 }
00634
00635 return ret;
00636 }
00637
00638 static bool
00639 xmms_ipc_msg_get_int32 (xmms_ipc_msg_t *msg, int32_t *v)
00640 {
00641 bool ret;
00642
00643 ret = xmms_ipc_msg_get_data (msg, v, sizeof (*v));
00644
00645 if (v) {
00646 *v = ntohl (*v);
00647 }
00648
00649 return ret;
00650 }
00651
00652 static bool
00653 xmms_ipc_msg_get_string_alloc (xmms_ipc_msg_t *msg, char **buf,
00654 unsigned int *len)
00655 {
00656 char *str;
00657 unsigned int l;
00658
00659 if (!xmms_ipc_msg_get_uint32 (msg, &l)) {
00660 return false;
00661 }
00662
00663 if (l > xmms_ipc_msg_get_length (msg) - msg->get_pos)
00664 return false;
00665
00666 str = x_malloc (l + 1);
00667 if (!str) {
00668 return false;
00669 }
00670
00671 if (!xmms_ipc_msg_get_data (msg, str, l)) {
00672 free (str);
00673 return false;
00674 }
00675
00676 str[l] = '\0';
00677
00678 *buf = str;
00679 *len = l;
00680
00681 return true;
00682 }
00683
00684 static bool
00685 xmms_ipc_msg_get_bin_alloc (xmms_ipc_msg_t *msg,
00686 unsigned char **buf,
00687 unsigned int *len)
00688 {
00689 unsigned char *b;
00690 unsigned int l;
00691
00692 if (!xmms_ipc_msg_get_uint32 (msg, &l)) {
00693 return false;
00694 }
00695
00696 if (l > xmms_ipc_msg_get_length (msg) - msg->get_pos)
00697 return false;
00698
00699 b = x_malloc (l);
00700 if (!b) {
00701 return false;
00702 }
00703
00704 if (!xmms_ipc_msg_get_data (msg, b, l)) {
00705 free (b);
00706 return false;
00707 }
00708
00709 *buf = b;
00710 *len = l;
00711
00712 return true;
00713 }
00714
00715 static bool
00716 xmms_ipc_msg_get_collection_alloc (xmms_ipc_msg_t *msg, xmmsv_coll_t **coll)
00717 {
00718 unsigned int i;
00719 unsigned int type;
00720 unsigned int n_items;
00721 unsigned int id;
00722 uint32_t *idlist = NULL;
00723 char *key, *val;
00724
00725
00726 if (!xmms_ipc_msg_get_uint32 (msg, &type)) {
00727 return false;
00728 }
00729
00730 *coll = xmmsv_coll_new (type);
00731
00732
00733 if (!xmms_ipc_msg_get_uint32 (msg, &n_items)) {
00734 goto err;
00735 }
00736
00737 for (i = 0; i < n_items; i++) {
00738 unsigned int len;
00739 if (!xmms_ipc_msg_get_string_alloc (msg, &key, &len)) {
00740 goto err;
00741 }
00742 if (!xmms_ipc_msg_get_string_alloc (msg, &val, &len)) {
00743 free (key);
00744 goto err;
00745 }
00746
00747 xmmsv_coll_attribute_set (*coll, key, val);
00748 free (key);
00749 free (val);
00750 }
00751
00752
00753 if (!xmms_ipc_msg_get_uint32 (msg, &n_items)) {
00754 goto err;
00755 }
00756
00757 if (!(idlist = x_new (uint32_t, n_items + 1))) {
00758 goto err;
00759 }
00760
00761 for (i = 0; i < n_items; i++) {
00762 if (!xmms_ipc_msg_get_uint32 (msg, &id)) {
00763 goto err;
00764 }
00765
00766 idlist[i] = id;
00767 }
00768
00769 idlist[i] = 0;
00770 xmmsv_coll_set_idlist (*coll, idlist);
00771 free (idlist);
00772 idlist = NULL;
00773
00774
00775 if (!xmms_ipc_msg_get_uint32 (msg, &n_items)) {
00776 goto err;
00777 }
00778
00779 for (i = 0; i < n_items; i++) {
00780 xmmsv_coll_t *operand;
00781 xmmsv_type_t type;
00782
00783 if (!xmms_ipc_msg_get_uint32 (msg, &type) ||
00784 type != XMMSV_TYPE_COLL ||
00785 !xmms_ipc_msg_get_collection_alloc (msg, &operand)) {
00786 goto err;
00787 }
00788
00789 xmmsv_coll_add_operand (*coll, operand);
00790 xmmsv_coll_unref (operand);
00791 }
00792
00793 return true;
00794
00795 err:
00796 if (idlist != NULL) {
00797 free (idlist);
00798 }
00799
00800 xmmsv_coll_unref (*coll);
00801
00802 return false;
00803 }
00804
00805
00806 static int
00807 xmmsc_deserialize_dict (xmms_ipc_msg_t *msg, xmmsv_t **val)
00808 {
00809 xmmsv_t *dict;
00810 unsigned int len, ignore;
00811 char *key;
00812
00813 dict = xmmsv_new_dict ();
00814
00815 if (!xmms_ipc_msg_get_uint32 (msg, &len)) {
00816 goto err;
00817 }
00818
00819 while (len--) {
00820 xmmsv_t *v;
00821
00822 if (!xmms_ipc_msg_get_string_alloc (msg, &key, &ignore)) {
00823 goto err;
00824 }
00825
00826 if (!xmms_ipc_msg_get_value_alloc (msg, &v)) {
00827 free (key);
00828 goto err;
00829 }
00830
00831 xmmsv_dict_set (dict, key, v);
00832 free (key);
00833 xmmsv_unref (v);
00834 }
00835
00836 *val = dict;
00837
00838 return true;
00839
00840 err:
00841 x_internal_error ("Message from server did not parse correctly!");
00842 xmmsv_unref (dict);
00843 return false;
00844 }
00845
00846 static int
00847 xmmsc_deserialize_list (xmms_ipc_msg_t *msg, xmmsv_t **val)
00848 {
00849 xmmsv_t *list;
00850 unsigned int len;
00851
00852 list = xmmsv_new_list ();
00853
00854 if (!xmms_ipc_msg_get_uint32 (msg, &len)) {
00855 goto err;
00856 }
00857
00858 while (len--) {
00859 xmmsv_t *v;
00860 if (xmms_ipc_msg_get_value_alloc (msg, &v)) {
00861 xmmsv_list_append (list, v);
00862 } else {
00863 goto err;
00864 }
00865 xmmsv_unref (v);
00866 }
00867
00868 *val = list;
00869
00870 return true;
00871
00872 err:
00873 x_internal_error ("Message from server did not parse correctly!");
00874 xmmsv_unref (list);
00875 return false;
00876 }
00877
00878 static bool
00879 xmms_ipc_msg_get_value_alloc (xmms_ipc_msg_t *msg, xmmsv_t **val)
00880 {
00881 int32_t type;
00882
00883 if (!xmms_ipc_msg_get_int32 (msg, &type)) {
00884 return false;
00885 }
00886
00887 return xmms_ipc_msg_get_value_of_type_alloc (msg, type, val);
00888 }
00889
00890 static bool
00891 xmms_ipc_msg_get_value_of_type_alloc (xmms_ipc_msg_t *msg, xmmsv_type_t type,
00892 xmmsv_t **val)
00893 {
00894 int32_t i;
00895 uint32_t len;
00896 char *s;
00897 xmmsv_coll_t *c;
00898 unsigned char *d;
00899
00900 switch (type) {
00901 case XMMSV_TYPE_ERROR:
00902 if (!xmms_ipc_msg_get_error_alloc (msg, &s, &len)) {
00903 return false;
00904 }
00905 *val = xmmsv_new_error (s);
00906 free (s);
00907 break;
00908 case XMMSV_TYPE_INT32:
00909 if (!xmms_ipc_msg_get_int32 (msg, &i)) {
00910 return false;
00911 }
00912 *val = xmmsv_new_int (i);
00913 break;
00914 case XMMSV_TYPE_STRING:
00915 if (!xmms_ipc_msg_get_string_alloc (msg, &s, &len)) {
00916 return false;
00917 }
00918 *val = xmmsv_new_string (s);
00919 free (s);
00920 break;
00921 case XMMSV_TYPE_DICT:
00922 if (!xmmsc_deserialize_dict (msg, val)) {
00923 return false;
00924 }
00925 break;
00926
00927 case XMMSV_TYPE_LIST :
00928 if (!xmmsc_deserialize_list (msg, val)) {
00929 return false;
00930 }
00931 break;
00932
00933 case XMMSV_TYPE_COLL:
00934 if (!xmms_ipc_msg_get_collection_alloc (msg, &c)) {
00935 return false;
00936 }
00937 *val = xmmsv_new_coll (c);
00938 xmmsv_coll_unref (c);
00939 break;
00940
00941 case XMMSV_TYPE_BIN:
00942 if (!xmms_ipc_msg_get_bin_alloc (msg, &d, &len)) {
00943 return false;
00944 }
00945 *val = xmmsv_new_bin (d, len);
00946 free (d);
00947 break;
00948
00949 case XMMSV_TYPE_NONE:
00950 *val = xmmsv_new_none ();
00951 break;
00952 default:
00953 x_internal_error ("Got message of unknown type!");
00954 return false;
00955 }
00956
00957 return true;
00958 }
00959
00960 bool
00961 xmms_ipc_msg_get_value (xmms_ipc_msg_t *msg, xmmsv_t **val)
00962 {
00963 return xmms_ipc_msg_get_value_alloc (msg, val);
00964 }