/* 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.244ss222!", [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 (equivalent to "*1/") * U = STRING16, align output to (void *) and enter (equivalent to "*2/") * d = data, uses %, align output to (void *) and enter * * = following are repeated, align output to (void *) and enter * & = * but requires allocation (there is only support for use once) (choose padding after alignment) * / = end of * or &, for & unless finished realigned output and start over * p = padding, align input to byte-quad */ [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*44/u", [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", [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/", [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 }; static size_t calculate_struct_size(const char *fmt, size_t *alignmentp) { size_t size = 0, i; *alignmentp = 1; for (;; fmt++) { switch (*fmt) { case '?': case '$': case '%': case 'p': break; case '.': case '!': case '1': case 'z': size += 1; break; case ',': case '2': case 's': *alignmentp = MAX(*alignmentp, 2); size += 2; break; case '_': size += 3; break; case '-': case '4': case 'S': *alignmentp = MAX(*alignmentp, 4); size += 4; break; case '=': *alignmentp = MAX(*alignmentp, 4); /* 2 uint32_t, not 1 uint64_t */ size += 8; break; case '#': size += 32; break; case '@': *alignmentp = MAX(*alignmentp, sizeof(size_t)); ALIGN(&size, size_t); size += sizeof(size_t); break; case '*': for (i = 0;; fmt++) { if (*fmt == '*') { i += 1; } else if (*fmt == '/') { if (!--i) break; } else if (!*fmt) { abort(); } } /* fall through */ case 'u': case 'U': case 'd': *alignmentp = MAX(*alignmentp, sizeof(void *)); ALIGN(&size, void *); size += sizeof(void *); break; case '/': return size; default: abort(); } } } /* TODO make it possible to prefetch pending messages */ int libaxl_receive(LIBAXL_CONTEXT *restrict ctx, union libaxl_input *restrict msgp, int flags) { struct { const char *fmt; char *msg; size_t ic, oc, o, count; } stack[3]; size_t si = 0; 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 = 0; ssize_t r; uint64_t n, u64; uint8_t code; size_t t, i, j, o, ic = 0, oc = 0, size, alignment = 1; int qc = 0; #ifdef MSG_TRUNC int flag_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) { 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); WUNLOCK_CONNECTION_RECV(conn); return LIBAXL_ERROR_CONNECTION_CLOSED; } liberror_recv_failed(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress, flags, ""); WUNLOCK_CONNECTION_RECV(conn); return LIBAXL_ERROR_SYSTEM; } conn->in_progress += (size_t)r; } code = *(uint8_t *)inbuf; code &= ~LIBAXL_SYNTHETIC_EVENT_BIT; 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) { 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); WUNLOCK_CONNECTION_RECV(conn); return LIBAXL_ERROR_CONNECTION_CLOSED; } liberror_recv_failed(conn->fd, &inbuf[conn->in_progress], n - conn->in_progress, flags, ""); WUNLOCK_CONNECTION_RECV(conn); 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; 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 == '@' || *fmt == '$' || *fmt == '%' || *fmt == '/'; 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 '*': alignment = 1; ALIGN(&o, void *); *(void **)&msg[o] = data = &inbuf[i]; o += sizeof(void *); stack[si].fmt = fmt; stack[si].msg = msg; stack[si].ic = ic; stack[si].oc = oc + 1; stack[si].o = o; stack[si].count = count; si += 1; count = counts[oc++]; o = 0; msg = data; if (!count) goto jump_to_end_of_repeat; break; case '&': size = calculate_struct_size(&fmt[1], &alignment); ALIGN_VAR(&size, alignment); alignment = size; data = NULL; if (counts[oc]) { size *= counts[oc]; if (size > ctx->aux_buf_size) { data = liberror_realloc(ctx->aux_buf, size); if (!data) return LIBAXL_ERROR_SYSTEM; ctx->aux_buf = data; ctx->aux_buf_size = size; } else { data = ctx->aux_buf; } } ALIGN(&o, void *); *(void **)&msg[o] = data; o += sizeof(void *); stack[si].fmt = fmt; stack[si].msg = msg; stack[si].ic = ic; stack[si].oc = oc + 1; stack[si].o = o; stack[si].count = count; si += 1; count = counts[oc++]; o = 0; msg = data; if (!count) goto jump_to_end_of_repeat; break; case '/': if (--count) { fmt = stack[si - 1].fmt; ALIGN_VAR(&o, alignment); } else { if (0) { jump_to_end_of_repeat: for (j = 0;; fmt++) { if (*fmt == '*' || *fmt == '&') { j += 1; } else if (*fmt == '/') { if (!j--) break; } else if (!*fmt) { abort(); } } } si -= 1; msg = stack[si].msg; ic = stack[si].ic; oc = stack[si].oc; o = stack[si].o; count = stack[si].count; } 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(); } } for (; *fmt && oc < ic && !counts[oc++]; fmt++) { if (*fmt == '*' || *fmt == '&') { ALIGN(&o, void *); *(void **)&msg[o] = NULL; o += sizeof(void *); for (j = 0;; fmt++) { if (*fmt == '*' || *fmt == '&') { j += 1; } else if (*fmt == '/') { if (!--j) break; } else if (!*fmt) { abort(); } } } else if (*fmt == 'u' || *fmt == 'U' || *fmt == 'd') { ALIGN(&o, void *); *(void **)&msg[o] = NULL; o += sizeof(void *); } else { break; } } 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; }