XMMS2
|
00001 /* XMMS2 - X Music Multiplexer System 00002 * Copyright (C) 2003-2009 XMMS2 Team 00003 * 00004 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 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 * Try to write message to transport. If full message isn't written 00194 * the message will keep track of the amount of data written and not 00195 * write already written data next time. 00196 * 00197 * @returns TRUE if full message was written, FALSE otherwise. 00198 * disconnected is set if transport was disconnected 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 * Try to read message from transport into msg. 00242 * 00243 * @returns TRUE if message is fully read. 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 /* Realloc data portion */ 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 /* return the offset that which we placed this value. 00333 * If this logic is changed, make sure to update 00334 * the return value of xmms_ipc_msg_put_value_data for 00335 * NONE xmmsv's, too. 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 /* push type */ 00421 internal_ipc_msg_put_uint32 (msg, xmmsv_coll_get_type (coll)); 00422 00423 /* attribute counter and values */ 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; /* no unref needed. */ 00433 00434 /* idlist counter and content */ 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 /* operands counter and objects */ 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 /* FIXME: what to do if value fetching fails? */ 00484 /* FIXME: return -1 unsigned int?? */ 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 /* just like the other _put_* functions, we 00526 * return the offset that which we placed this value. 00527 * See xmms_ipc_msg_put_data(). 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 /* store a dummy value, store the real count once it's known */ 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 /* overwrite with real size */ 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 /* store a dummy value, store the real count once it's known */ 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 /* overwrite with real size */ 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 /* currently, an error is just a string, so reuse that */ 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 /* Get the type and create the collection */ 00726 if (!xmms_ipc_msg_get_uint32 (msg, &type)) { 00727 return false; 00728 } 00729 00730 *coll = xmmsv_coll_new (type); 00731 00732 /* Get the list of attributes */ 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 /* Get the idlist */ 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 /* Get the operands */ 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 }