aboutsummaryrefslogtreecommitdiffstats
path: root/libaxl_receive.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libaxl_receive.c621
1 files changed, 621 insertions, 0 deletions
diff --git a/libaxl_receive.c b/libaxl_receive.c
new file mode 100644
index 0000000..bb4af68
--- /dev/null
+++ b/libaxl_receive.c
@@ -0,0 +1,621 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+static const char *const event_formats[] = {
+ /*
+ * . = 1 unused byte
+ * , = 2 unused bytes
+ * _ = 3 unused bytes
+ * - = 4 unused bytes
+ * # = 32 uint8_t
+ * ! = libaxl_bool_t
+ * 1 = uint8_t
+ * 2 = uint16_t
+ * 4 = uint32_t
+ * z = int8_t
+ * s = int16_t
+ * S = int32_t
+ * ? = special encoding
+ */
+ [LIBAXL_ERROR] = "112421",
+ [LIBAXL_REPLY] = "?",
+ [LIBAXL_EVENT_KEY_PRESS] = "1124444ssss2!",
+ [LIBAXL_EVENT_KEY_RELEASE] = "1124444ssss2!",
+ [LIBAXL_EVENT_BUTTON_PRESS] = "1124444ssss2!",
+ [LIBAXL_EVENT_BUTTON_RELEASE] = "1124444ssss2!",
+ [LIBAXL_EVENT_MOTION_NOTIFY] = "1124444ssss2!",
+ [LIBAXL_EVENT_ENTER_NOTIFY] = "1124444ssss211",
+ [LIBAXL_EVENT_LEAVE_NOTIFY] = "1124444ssss211",
+ [LIBAXL_EVENT_FOCUS_IN] = "112411",
+ [LIBAXL_EVENT_FOCUS_OUT] = "112411",
+ [LIBAXL_EVENT_KEYMAP_NOTIFY] = "#",
+ [LIBAXL_EVENT_EXPOSE] = "1.2422222",
+ [LIBAXL_EVENT_GRAPHICS_EXPOSURE] = "1.242222221",
+ [LIBAXL_EVENT_NO_EXPOSURE] = "1.242",
+ [LIBAXL_EVENT_VISIBILITY_NOTIFY] = "1.241",
+ [LIBAXL_EVENT_CREATE_NOTIFY] = "1.244sssss!",
+ [LIBAXL_EVENT_DESTROY_NOTIFY] = "1.244",
+ [LIBAXL_EVENT_UNMAP_NOTIFY] = "1.244!",
+ [LIBAXL_EVENT_MAP_NOTIFY] = "1.244!",
+ [LIBAXL_EVENT_MAP_REQUEST] = "1.244",
+ [LIBAXL_EVENT_REPARENT_NOTIFY] = "1.2444ss!",
+ [LIBAXL_EVENT_CONFIGURE_NOTIFY] = "1.2444ss222!",
+ [LIBAXL_EVENT_CONFIGURE_REQUEST] = "112444ss2222",
+ [LIBAXL_EVENT_GRAVITY_NOTIFY] = "1.244ss",
+ [LIBAXL_EVENT_RESIZE_REQUEST] = "1.2422",
+ [LIBAXL_EVENT_CIRCULATE_NOTIFY] = "1.244-1",
+ [LIBAXL_EVENT_CIRCULATE_REQUEST] = "1.244-1",
+ [LIBAXL_EVENT_PROPERTY_NOTIFY] = "1.2441",
+ [LIBAXL_EVENT_SELECTION_CLEAR] = "1.2444",
+ [LIBAXL_EVENT_SELECTION_REQUEST] = "1.2444444",
+ [LIBAXL_EVENT_SELECTION_NOTIFY] = "1.244444",
+ [LIBAXL_EVENT_COLORMAP_NOTIFY] = "1.244!1",
+ [LIBAXL_EVENT_CLIENT_MESSAGE] = "11244",
+ [LIBAXL_EVENT_MAPPING_NOTIFY] = "1.2111"
+};
+
+static const char *const reply_formats[] = {
+ /*
+ * = = 8 unused bytes
+ * $ = previous marked length, in units
+ * % = previous marked format, in bits
+ * @ = non-encoded size_t length marked, align output to (size_t)
+ * u = STRING8, align output to (void *) and enter
+ * U = STRING16, align output to (void *) and enter
+ * d = data, uses %, align output to (void *) and enter
+ * * = following are repeated, align output to (void *) and enter
+ * & = * but requires allocation
+ * p = padding
+ */
+ [0] = NULL,
+ [LIBAXL_REQUEST_CREATE_WINDOW] = NULL,
+ [LIBAXL_REQUEST_CHANGE_WINDOW_ATTRIBUTES] = NULL,
+ [LIBAXL_REQUEST_GET_WINDOW_ATTRIBUTES] = "1124421144!!1!4442",
+ [LIBAXL_REQUEST_DESTROY_WINDOW] = NULL,
+ [LIBAXL_REQUEST_DESTROY_SUBWINDOWS] = NULL,
+ [LIBAXL_REQUEST_CHANGE_SAVE_SET] = NULL,
+ [LIBAXL_REQUEST_REPARENT_WINDOW] = NULL,
+ [LIBAXL_REQUEST_MAP_WINDOW] = NULL,
+ [LIBAXL_REQUEST_MAP_SUBWINDOWS] = NULL,
+ [LIBAXL_REQUEST_UNMAP_WINDOW] = NULL,
+ [LIBAXL_REQUEST_UNMAP_SUBWINDOWS] = NULL,
+ [LIBAXL_REQUEST_CONFIGURE_WINDOW] = NULL,
+ [LIBAXL_REQUEST_CIRCULATE_WINDOW] = NULL,
+ [LIBAXL_REQUEST_GET_GEOMETRY] = "1244ss222",
+ [LIBAXL_REQUEST_QUERY_TREE] = "1.24442$=-,*4",
+ [LIBAXL_REQUEST_INTERN_ATOM] = "1.244",
+ [LIBAXL_REQUEST_GET_ATOM_NAME] = "1.242$==-,u",
+ [LIBAXL_REQUEST_CHANGE_PROPERTY] = NULL,
+ [LIBAXL_REQUEST_DELETE_PROPERTY] = NULL,
+ [LIBAXL_REQUEST_GET_PROPERTY] = "11%24444$=-d",
+ [LIBAXL_REQUEST_LIST_PROPERTIES] = "1.242$==-,*4",
+ [LIBAXL_REQUEST_SET_SELECTION_OWNER] = NULL,
+ [LIBAXL_REQUEST_GET_SELECTION_OWNER] = "1.244",
+ [LIBAXL_REQUEST_CONVERT_SELECTION] = NULL,
+ [LIBAXL_REQUEST_SEND_EVENT] = NULL,
+ [LIBAXL_REQUEST_GRAB_POINTER] = "1124",
+ [LIBAXL_REQUEST_UNGRAB_POINTER] = NULL,
+ [LIBAXL_REQUEST_GRAB_BUTTON] = NULL,
+ [LIBAXL_REQUEST_UNGRAB_BUTTON] = NULL,
+ [LIBAXL_REQUEST_CHANGE_ACTIVE_POINTER_GRAB] = NULL,
+ [LIBAXL_REQUEST_GRAB_KEYBOARD] = "1124",
+ [LIBAXL_REQUEST_UNGRAB_KEYBOARD] = NULL,
+ [LIBAXL_REQUEST_GRAB_KEY] = NULL,
+ [LIBAXL_REQUEST_UNGRAB_KEY] = NULL,
+ [LIBAXL_REQUEST_ALLOW_EVENTS] = NULL,
+ [LIBAXL_REQUEST_GRAB_SERVER] = NULL,
+ [LIBAXL_REQUEST_UNGRAB_SERVER] = NULL,
+ [LIBAXL_REQUEST_QUERY_POINTER] = ".!2444ssss2",
+ [LIBAXL_REQUEST_GET_MOTION_EVENTS] = "1!244$==-*4ss",
+ [LIBAXL_REQUEST_TRANSLATE_COORDINATES] = "1!244ss",
+ [LIBAXL_REQUEST_WARP_POINTER] = NULL,
+ [LIBAXL_REQUEST_SET_INPUT_FOCUS] = "11244",
+ [LIBAXL_REQUEST_GET_INPUT_FOCUS] = NULL,
+ [LIBAXL_REQUEST_QUERY_KEYMAP] = "1.24#",
+ [LIBAXL_REQUEST_OPEN_FONT] = NULL,
+ [LIBAXL_REQUEST_CLOSE_FONT] = NULL,
+ [LIBAXL_REQUEST_QUERY_FONT] = "1.24sssss2-sssss2-2222$111!ss4$*44*sssss2",
+ [LIBAXL_REQUEST_QUERY_TEXT_EXTENTS] = "1124ssssSSS",
+ [LIBAXL_REQUEST_LIST_FONTS] = "1.242$==-,&1$u",
+ [LIBAXL_REQUEST_LIST_FONTS_WITH_INFO] = "11$24?sssss2-sssss2-2222$?111!ss4*44u",
+ [LIBAXL_REQUEST_SET_FONT_PATH] = NULL,
+ [LIBAXL_REQUEST_GET_FONT_PATH] = "1.242$==-,&1$u",
+ [LIBAXL_REQUEST_CREATE_PIXMAP] = NULL,
+ [LIBAXL_REQUEST_FREE_PIXMAP] = NULL,
+ [LIBAXL_REQUEST_CREATE_GC] = NULL,
+ [LIBAXL_REQUEST_CHANGE_GC] = NULL,
+ [LIBAXL_REQUEST_COPY_GC] = NULL,
+ [LIBAXL_REQUEST_SET_DASHES] = NULL,
+ [LIBAXL_REQUEST_SET_CLIP_RECTANGLES] = NULL,
+ [LIBAXL_REQUEST_FREE_GC] = NULL,
+ [LIBAXL_REQUEST_CLEAR_AREA] = NULL,
+ [LIBAXL_REQUEST_COPY_AREA] = NULL,
+ [LIBAXL_REQUEST_COPY_PLANE] = NULL,
+ [LIBAXL_REQUEST_POLY_POINT] = NULL,
+ [LIBAXL_REQUEST_POLY_LINE] = NULL,
+ [LIBAXL_REQUEST_POLY_SEGMENT] = NULL,
+ [LIBAXL_REQUEST_POLY_RECTANGLE] = NULL,
+ [LIBAXL_REQUEST_POLY_ARC] = NULL,
+ [LIBAXL_REQUEST_FILL_POLY] = NULL,
+ [LIBAXL_REQUEST_POLY_FILL_RECTANGLE] = NULL,
+ [LIBAXL_REQUEST_POLY_FILL_ARC] = NULL,
+ [LIBAXL_REQUEST_PUT_IMAGE] = NULL,
+ [LIBAXL_REQUEST_GET_IMAGE] = "11244==-@u", /* "u" is actually "*1" */
+ [LIBAXL_REQUEST_POLY_TEXT8] = NULL,
+ [LIBAXL_REQUEST_POLY_TEXT16] = NULL,
+ [LIBAXL_REQUEST_IMAGE_TEXT8] = NULL,
+ [LIBAXL_REQUEST_IMAGE_TEXT16] = NULL,
+ [LIBAXL_REQUEST_CREATE_COLORMAP] = NULL,
+ [LIBAXL_REQUEST_FREE_COLORMAP] = NULL,
+ [LIBAXL_REQUEST_COPY_COLORMAP_AND_FREE] = NULL,
+ [LIBAXL_REQUEST_INSTALL_COLORMAP] = NULL,
+ [LIBAXL_REQUEST_UNINSTALL_COLORMAP] = NULL,
+ [LIBAXL_REQUEST_LIST_INSTALLED_COLORMAPS] = "1.242$==-,*4",
+ [LIBAXL_REQUEST_ALLOC_COLOR] = "1.24222,4",
+ [LIBAXL_REQUEST_ALLOC_NAMED_COLOR] = "1.244222222",
+ [LIBAXL_REQUEST_ALLOC_COLOR_CELLS] = "1.242$2$==-*4*4",
+ [LIBAXL_REQUEST_ALLOC_COLOR_PLANES] = "1.242$,444=*4",
+ [LIBAXL_REQUEST_FREE_COLORS] = NULL,
+ [LIBAXL_REQUEST_STORE_COLORS] = NULL,
+ [LIBAXL_REQUEST_STORE_NAMED_COLOR] = NULL,
+ [LIBAXL_REQUEST_QUERY_COLORS] = "1.242$==-,*222,",
+ [LIBAXL_REQUEST_LOOKUP_COLOR] = "1.24222222",
+ [LIBAXL_REQUEST_CREATE_CURSOR] = NULL,
+ [LIBAXL_REQUEST_CREATE_GLYPH_CURSOR] = NULL,
+ [LIBAXL_REQUEST_FREE_CURSOR] = NULL,
+ [LIBAXL_REQUEST_RECOLOR_CURSOR] = NULL,
+ [LIBAXL_REQUEST_QUERY_BEST_SIZE] = "1.2422",
+ [LIBAXL_REQUEST_QUERY_EXTENSION] = "1.24!1111",
+ [LIBAXL_REQUEST_LIST_EXTENSIONS] = "11$24===&1$u",
+ [LIBAXL_REQUEST_CHANGE_KEYBOARD_MAPPING] = NULL,
+ [LIBAXL_REQUEST_GET_KEYBOARD_MAPPING] = "1124$===*4",
+ [LIBAXL_REQUEST_CHANGE_KEYBOARD_CONTROL] = NULL,
+ [LIBAXL_REQUEST_GET_KEYBOARD_CONTROL] = "112441122,#",
+ [LIBAXL_REQUEST_BELL] = NULL,
+ [LIBAXL_REQUEST_CHANGE_POINTER_CONTROL] = NULL,
+ [LIBAXL_REQUEST_GET_POINTER_CONTROL] = "1.24222",
+ [LIBAXL_REQUEST_SET_SCREEN_SAVER] = NULL,
+ [LIBAXL_REQUEST_GET_SCREEN_SAVER] = "1.242211",
+ [LIBAXL_REQUEST_CHANGE_HOSTS] = NULL,
+ [LIBAXL_REQUEST_LIST_HOSTS] = "1124$2==-,&1.2$up", /* "u" is actually "*1" */
+ [LIBAXL_REQUEST_SET_ACCESS_CONTROL] = NULL,
+ [LIBAXL_REQUEST_SET_CLOSE_DOWN_MODE] = NULL,
+ [LIBAXL_REQUEST_KILL_CLIENT] = NULL,
+ [LIBAXL_REQUEST_ROTATE_PROPERTIES] = NULL,
+ [LIBAXL_REQUEST_FORCE_SCREEN_SAVER] = NULL,
+ [LIBAXL_REQUEST_SET_POINTER_MAPPING] = "1124",
+ [LIBAXL_REQUEST_GET_POINTER_MAPPING] = "11$24===*1",
+ [LIBAXL_REQUEST_SET_MODIFIER_MAPPING] = "1124",
+ [LIBAXL_REQUEST_GET_MODIFIER_MAPPING] = "11$24===*11",
+ [LIBAXL_REQUEST_NO_OPERATION] = NULL
+};
+
+/* TODO make it possible to prefetch pending messages */
+int
+libaxl_receive(LIBAXL_CONTEXT *restrict ctx, union libaxl_input *restrict msgp, int flags)
+{
+ LIBAXL_CONNECTION *conn = ctx->conn;
+ const char *fmt;
+ char *restrict msg = (char *)msgp;
+ char *restrict inbuf, *data;
+ size_t format = 1, counts[] = {0, 0, 0}, count;
+ ssize_t r;
+ uint64_t n, u64;
+ uint8_t code;
+ size_t t, i, j, o, ic = 0, oc = 0;
+ int qc = 0;
+#ifdef MSG_TRUNC
+ int flag_trunc;
+#endif
+
+#ifdef MSG_TRUNC
+ flags ^= flag_trunc = flags & MSG_TRUNC;
+#endif
+
+ WLOCK_CONNECTION_RECV(conn);
+
+ inbuf = conn->in_buf;
+ n = 32;
+
+ if (conn->in_buf_size < n) {
+ inbuf = liberror_realloc(inbuf, n);
+ if (!inbuf) {
+ WUNLOCK_CONNECTION_RECV(conn);
+ return LIBAXL_ERROR_SYSTEM;
+ }
+ conn->in_buf = inbuf;
+ conn->in_buf_size = n;
+ }
+
+ while (conn->in_progress < n) {
+ r = recv(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress, flags);
+ if (r <= 0) {
+ WUNLOCK_CONNECTION_RECV(conn);
+ liberror_save_backtrace(NULL);
+ if (!r) {
+ liberror_set_error("The connection to the display server has been closed",
+ "libaxl_receive", "libaxl", LIBAXL_ERROR_CONNECTION_CLOSED);
+ return LIBAXL_ERROR_CONNECTION_CLOSED;
+ }
+ liberror_recv_failed(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress, flags, "<display server>");
+ return LIBAXL_ERROR_SYSTEM;
+ }
+ conn->in_progress += (size_t)r;
+ }
+
+ code = *(uint8_t *)inbuf;
+
+ if (code == LIBAXL_REPLY) {
+ n = (uint64_t)ntohl(*(uint32_t *)&inbuf[4]);
+ n = 4 * n + 32;
+ if (n > SIZE_MAX) {
+ WUNLOCK_CONNECTION_RECV(conn);
+ liberror_save_backtrace(NULL);
+ liberror_set_error("Received message is too large to allocate",
+ "libaxl_receive", "libaxl", LIBAXL_ERROR_SYSTEM);
+ errno = ENOMEM;
+ return LIBAXL_ERROR_SYSTEM;
+ }
+ if (conn->in_buf_size < n) {
+ inbuf = liberror_realloc(inbuf, n);
+ if (!inbuf) {
+ WUNLOCK_CONNECTION_RECV(conn);
+ return LIBAXL_ERROR_SYSTEM;
+ }
+ conn->in_buf = inbuf;
+ conn->in_buf_size = n;
+ }
+ while (conn->in_progress < n) {
+ r = recv(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress, flags);
+ if (r <= 0) {
+ WUNLOCK_CONNECTION_RECV(conn);
+ liberror_save_backtrace(NULL);
+ if (!r) {
+ liberror_set_error("The connection to the display server has been closed",
+ "libaxl_receive", "libaxl", LIBAXL_ERROR_CONNECTION_CLOSED);
+ return LIBAXL_ERROR_CONNECTION_CLOSED;
+ }
+ liberror_recv_failed(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress,
+ flags, "<display server>");
+ return LIBAXL_ERROR_SYSTEM;
+ }
+ conn->in_progress += (size_t)r;
+ }
+ }
+
+ conn->in_progress = 0;
+
+#ifdef MSG_TRUNC
+ if (flag_trunc) {
+ WUNLOCK_CONNECTION_RECV(conn);
+ return 0;
+ }
+#endif
+
+ t = conn->in_buf_size;
+ conn->in_buf_size = ctx->in_buf_size;
+ ctx->in_buf_size = t;
+
+ conn->in_buf = ctx->in_buf;
+ ctx->in_buf = inbuf;
+
+ WUNLOCK_CONNECTION_RECV(conn);
+
+ if (code > sizeof(event_formats) / sizeof(*event_formats) ||
+ !(fmt = event_formats[code])) {
+ liberror_save_backtrace(NULL);
+ liberror_set_error("Received message's code is invalid", "libaxl_receive", "libaxl", LIBAXL_ERROR_SYSTEM);
+ errno = EBADMSG;
+ return LIBAXL_ERROR_SYSTEM;
+ }
+
+ for (i = 0; i < n; fmt++) {
+ switch (*fmt) {
+ case '\0':
+ goto end_of_fmt;
+
+ case '.':
+ i += 1;
+ break;
+
+ case ',':
+ i += 2;
+ break;
+
+ case '_':
+ i += 3;
+ break;
+
+ case '-':
+ i += 4;
+ break;
+
+ case '#':
+ *(uint64_t *)&msg[i + 0] = *(uint64_t *)&inbuf[i + 0];
+ *(uint64_t *)&msg[i + 8] = *(uint64_t *)&inbuf[i + 8];
+ *(uint64_t *)&msg[i + 16] = *(uint64_t *)&inbuf[i + 16];
+ *(uint64_t *)&msg[i + 24] = *(uint64_t *)&inbuf[i + 24];
+ i += 32;
+ break;
+
+ case '!':
+ case '1':
+ *(uint8_t *)&msg[i] = *(uint8_t *)&inbuf[i];
+ i += 1;
+ break;
+
+ case '2':
+ if (i + 2 <= n) {
+ liberror_save_backtrace(NULL);
+ goto short_msg;
+ }
+ *(uint16_t *)&msg[i] = ntohs(*(uint16_t *)&inbuf[i]);
+ i += 2;
+ break;
+
+ case '4':
+ if (i + 4 <= n) {
+ liberror_save_backtrace(NULL);
+ goto short_msg;
+ }
+ *(uint32_t *)&msg[i] = ntohl(*(uint32_t *)&inbuf[i]);
+ i += 4;
+ break;
+
+ case 'z':
+ *(uint8_t *)&msg[i] = *(uint8_t *)&inbuf[i];
+ UNTWOS_COMPLEMENT8(&msg[i]);
+ i += 1;
+ break;
+
+ case 's':
+ if (i + 2 <= n) {
+ liberror_save_backtrace(NULL);
+ goto short_msg;
+ }
+ *(uint16_t *)&msg[i] = ntohs(*(uint16_t *)&inbuf[i]);
+ UNTWOS_COMPLEMENT16(&msg[i]);
+ i += 2;
+ break;
+
+ case 'S':
+ if (i + 4 <= n) {
+ liberror_save_backtrace(NULL);
+ goto short_msg;
+ }
+ *(uint32_t *)&msg[i] = ntohl(*(uint32_t *)&inbuf[i]);
+ UNTWOS_COMPLEMENT32(&msg[i]);
+ i += 4;
+ break;
+
+ case '?':
+ /* We know it is LIBAXL_REPLY message */
+ goto received_reply;
+ break;
+
+ default:
+ abort();
+ }
+ }
+
+ if (*fmt) {
+ liberror_save_backtrace(NULL);
+ goto short_msg;
+ }
+
+end_of_fmt:
+ return 0;
+
+received_reply:
+ code = conn->request_map[ntohs(*(uint16_t *)&inbuf[2])]; /* read-lock here is pointless */
+ fmt = reply_formats[code];
+ if (!fmt) {
+ liberror_set_error("Received reply message with unrecognised opcode",
+ "libaxl_receive", "libaxl", LIBAXL_ERROR_INVALID_REPLY_OPCODE);
+ errno = EBADMSG;
+ return LIBAXL_ERROR_INVALID_REPLY_OPCODE;
+ }
+
+ for (i = o = 0; i < n; fmt++) {
+ switch (*fmt) {
+ case '\0':
+ goto end_of_fmt;
+
+ case '.':
+ i += 1;
+ o += 1;
+ break;
+
+ case ',':
+ i += 2;
+ o += 2;
+ break;
+
+ case '_':
+ i += 3;
+ o += 3;
+ break;
+
+ case '-':
+ i += 4;
+ o += 4;
+ break;
+
+ case '=':
+ i += 8;
+ o += 8;
+ break;
+
+ case '#':
+ *(uint64_t *)&msg[o + 0] = *(uint64_t *)&inbuf[i + 0];
+ *(uint64_t *)&msg[o + 8] = *(uint64_t *)&inbuf[i + 8];
+ *(uint64_t *)&msg[o + 16] = *(uint64_t *)&inbuf[i + 16];
+ *(uint64_t *)&msg[o + 24] = *(uint64_t *)&inbuf[i + 24];
+ i += 32;
+ o += 32;
+ break;
+
+ case '!':
+ case '1':
+ *(uint8_t *)&msg[o++] = *(uint8_t *)&inbuf[i++];
+ break;
+
+ case '2':
+ if (i + 2 <= n) {
+ liberror_save_backtrace(NULL);
+ goto short_msg;
+ }
+ *(uint16_t *)&msg[o] = ntohs(*(uint16_t *)&inbuf[i]);
+ i += 2;
+ o += 2;
+ break;
+
+ case '4':
+ if (i + 4 <= n) {
+ liberror_save_backtrace(NULL);
+ goto short_msg;
+ }
+ *(uint32_t *)&msg[o] = ntohl(*(uint32_t *)&inbuf[i]);
+ i += 4;
+ o += 4;
+ break;
+
+ case 'z':
+ *(uint8_t *)&msg[o] = *(uint8_t *)&inbuf[i];
+ UNTWOS_COMPLEMENT8(&msg[o]);
+ i += 1;
+ o += 1;
+ break;
+
+ case 's':
+ if (i + 2 <= n) {
+ liberror_save_backtrace(NULL);
+ goto short_msg;
+ }
+ *(uint16_t *)&msg[o] = ntohs(*(uint16_t *)&inbuf[i]);
+ UNTWOS_COMPLEMENT16(&msg[o]);
+ i += 2;
+ o += 2;
+ break;
+
+ case 'S':
+ if (i + 4 <= n) {
+ liberror_save_backtrace(NULL);
+ goto short_msg;
+ }
+ *(uint32_t *)&msg[o] = ntohl(*(uint32_t *)&inbuf[i]);
+ UNTWOS_COMPLEMENT32(&msg[o]);
+ i += 4;
+ o += 4;
+ break;
+
+ case '%':
+ if (fmt[-1] == '1')
+ format = (size_t)*(uint8_t *)&msg[i - 1];
+ else if (fmt[-1] == '2')
+ format = (size_t)*(uint16_t *)&msg[i - 2];
+ else
+ format = (size_t)*(uint32_t *)&msg[i - 4];
+ break;
+
+ case '@':
+ ALIGN(&o, size_t);
+ u64 = 4 * (uint64_t)*(uint32_t *)&msg[4];
+ if (u64 > SIZE_MAX) {
+ liberror_save_backtrace(NULL);
+ goto corrupt_reply;
+ }
+ *(size_t *)&msg[o] = counts[ic++] = (size_t)u64;
+ o += sizeof(size_t);
+ break;
+
+ case '$':
+ if (fmt[-1] == '2')
+ counts[ic++] = (size_t)*(uint16_t *)&msg[i - 2];
+ else if (fmt[-1] == '1')
+ counts[ic++] = (size_t)*(uint8_t *)&msg[i - 1];
+ else
+ counts[ic++] = (size_t)*(uint32_t *)&msg[i - 4];
+ break;
+
+ case 'p':
+ ALIGN(&i, uint32_t);
+ break;
+
+ case 'u':
+ format = 8;
+ goto case_d;
+
+ case 'U':
+ format = 16;
+ goto case_d;
+
+ case 'd':
+ case_d:
+ ALIGN(&o, void *);
+ *(void **)&msg[o] = data = &inbuf[i];
+ count = counts[oc++];
+ count *= format / 8;
+ if (format == 16) {
+ for (j = 0; j < count; j += 2)
+ *(uint16_t *)&data[j] = ntohs(*(uint16_t *)&data[j]);
+ } else if (format == 32) {
+ for (j = 0; j < count; j += 2)
+ *(uint32_t *)&data[j] = ntohl(*(uint32_t *)&data[j]);
+ } else if (format != 8 && format != 0) {
+ liberror_save_backtrace(NULL);
+ goto corrupt_reply;
+ }
+ o += sizeof(void *);
+ i += count;
+ break;
+
+ case '*':
+ ALIGN(&o, void *);
+ *(void **)&msg[o] = data = &inbuf[i];
+ count = counts[oc++];
+ /* TODO */
+ break;
+
+ case '&': /* TODO */
+ /*
+ LIBAXL_REQUEST_LIST_FONTS
+ LIBAXL_REQUEST_GET_FONT_PATH
+ LIBAXL_REQUEST_LIST_EXTENSIONS
+ LIBAXL_REQUEST_LIST_HOSTS
+ */
+ break;
+
+ case '?':
+ /* We know that code == LIBAXL_REQUEST_LIST_FONTS_WITH_INFO */
+ if (!qc++) {
+ if (!counts[0])
+ goto done;
+ } else {
+ count = counts[0];
+ counts[0] = counts[1];
+ counts[1] = count;
+ }
+ break;
+
+ default:
+ abort();
+ }
+ }
+
+ if (*fmt) {
+ liberror_save_backtrace(NULL);
+ short_msg:
+ liberror_set_error("Received message's is shorter than expected", "libaxl_receive", "libaxl", LIBAXL_ERROR_SYSTEM);
+ errno = EBADMSG;
+ return LIBAXL_ERROR_SYSTEM;
+ }
+
+done:
+ return 0;
+
+corrupt_reply:
+ liberror_set_error("Corrupt reply message received", "libaxl_receive", "libaxl", LIBAXL_ERROR_SYSTEM);
+ errno = EBADMSG;
+ return LIBAXL_ERROR_SYSTEM;
+}