XMMS2

src/lib/xmmsipc/msg.c

Go to the documentation of this file.
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 }