pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data, pixman_format_code_t pixman_format, int width, int height, int gross_pixels, int top_down) { int stride; pixman_image_t *surface = NULL; stride = (gross_pixels / height) * (PIXMAN_FORMAT_BPP (pixman_format) / 8); /* pixman requires strides to be 4-byte aligned */ stride = SPICE_ALIGN(stride, 4); if (!top_down) { stride = -stride; } surface = surface_create_stride( #ifdef WIN32 canvas_data->dc, #endif pixman_format, width, height, stride); canvas_data->out_surface = surface; return surface; }
static Pixmap *init_bitmap(size_t input_size, uint8_t *buf) { BMPFileHeader *file_header; uint8_t *pixels; Pixmap *pixmap; uint32_t stride; if (input_size < sizeof(BMPFileHeader)) { ERROR("invalid source file"); return NULL; } file_header = (BMPFileHeader *)buf; if (file_header->magic != 0x4d42) { ERROR("bad bitmap magic"); return NULL; } if (file_header->file_size != input_size) { ERROR("invalid source file"); return NULL; } if (file_header->header.header_size != 40 || file_header->header.plans != 1 || file_header->header.compression != BI_RGB || !file_header->header.width || !file_header->header.height) { ERROR("invalid bitmap header"); return NULL; } if (file_header->header.bpp == 32) { stride = file_header->header.width * sizeof(uint32_t); } else if (file_header->header.bpp == 24) { stride = SPICE_ALIGN(file_header->header.width * 3, 4); } else { ERROR("unsupported bpp"); return NULL; } if (file_header->header.height * stride > file_header->header.image_size) { ERROR("image size is to small"); return NULL; } pixels = buf + file_header->data_offset; if (pixels < (uint8_t *)(file_header + 1) || pixels + file_header->header.image_size > buf + input_size) { ERROR("bad data offset"); return NULL; } if (!(pixmap = (Pixmap *)malloc(sizeof(*pixmap)))) { ERROR("alloc mem failed"); return NULL; } pixmap->width = file_header->header.width; pixmap->height = file_header->header.height; pixmap->stride = stride; pixmap->bpp = file_header->header.bpp; pixmap->data = pixels; return pixmap; }
pixman_image_t * surface_create(pixman_format_code_t format, int width, int height, int top_down) #endif { #ifdef WIN32 /* * Windows xp allow only 10,000 of gdi handlers, considering the fact that * we limit here the number to 5000, we dont use atomic operations to sync * this calculation against the other canvases (in case of multiple * monitors), in worst case there will be little more than 5000 gdi * handlers. */ if (dc && gdi_handlers < 5000) { uint8_t *data; uint8_t *src; struct { BITMAPINFO inf; RGBQUAD palette[255]; } bitmap_info; int nstride; pixman_image_t *surface; PixmanData *pixman_data; HBITMAP bitmap; HANDLE mutex; memset(&bitmap_info, 0, sizeof(bitmap_info)); bitmap_info.inf.bmiHeader.biSize = sizeof(bitmap_info.inf.bmiHeader); bitmap_info.inf.bmiHeader.biWidth = width; bitmap_info.inf.bmiHeader.biHeight = (!top_down) ? height : -height; bitmap_info.inf.bmiHeader.biPlanes = 1; switch (format) { case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: bitmap_info.inf.bmiHeader.biBitCount = 32; nstride = width * 4; break; case PIXMAN_x1r5g5b5: case PIXMAN_r5g6b5: bitmap_info.inf.bmiHeader.biBitCount = 16; nstride = SPICE_ALIGN(width * 2, 4); break; case PIXMAN_a8: bitmap_info.inf.bmiHeader.biBitCount = 8; nstride = SPICE_ALIGN(width, 4); break; case PIXMAN_a1: bitmap_info.inf.bmiHeader.biBitCount = 1; nstride = SPICE_ALIGN(width, 32) / 8; break; default: spice_error("invalid format"); return NULL; } bitmap_info.inf.bmiHeader.biCompression = BI_RGB; mutex = CreateMutex(NULL, 0, NULL); if (!mutex) { spice_error("Unable to CreateMutex"); } bitmap = CreateDIBSection(dc, &bitmap_info.inf, 0, (VOID **)&data, NULL, 0); if (!bitmap) { CloseHandle(mutex); spice_error("Unable to CreateDIBSection"); } if (top_down) { src = data; } else { src = data + nstride * (height - 1); nstride = -nstride; } surface = pixman_image_create_bits(format, width, height, (uint32_t *)src, nstride); if (surface == NULL) { CloseHandle(mutex); DeleteObject(bitmap); spice_error("create surface failed, out of memory"); } pixman_data = pixman_image_add_data(surface); pixman_data->format = format; pixman_data->bitmap = bitmap; pixman_data->mutex = mutex; gdi_handlers++; return surface; } else { #endif if (top_down) { pixman_image_t *surface; PixmanData *data; surface = pixman_image_create_bits(format, width, height, NULL, 0); data = pixman_image_add_data(surface); data->format = format; return surface; } else { // NOTE: we assume here that the lz decoders always decode to RGB32. int stride = 0; switch (format) { case PIXMAN_a8r8g8b8: case PIXMAN_x8r8g8b8: stride = width * 4; break; case PIXMAN_x1r5g5b5: case PIXMAN_r5g6b5: stride = SPICE_ALIGN(width * 2, 4); break; case PIXMAN_a8: stride = SPICE_ALIGN(width, 4); break; case PIXMAN_a1: stride = SPICE_ALIGN(width, 32) / 8; break; default: spice_error("invalid format"); } stride = -stride; return __surface_create_stride(format, width, height, stride); } #ifdef WIN32 } #endif }
static uint8_t * parse_msgc_tunnel_service_add(uint8_t *message_start, uint8_t *message_end, int minor, size_t *size, message_destructor_t *free_message) { SPICE_GNUC_UNUSED uint8_t *pos; uint8_t *start = message_start; uint8_t *data = NULL; size_t mem_size, nw_size; uint8_t *in, *end; SPICE_GNUC_UNUSED intptr_t ptr_size; uint32_t n_ptr=0; PointerInfo ptr_info[2]; size_t name__extra_size; size_t description__extra_size; size_t u__nw_size; uint16_t type__value; SpiceMsgcTunnelAddGenericService *out; uint32_t i; { /* name */ uint32_t name__value; uint32_t name__array__nw_size; uint32_t name__array__mem_size; pos = (start + 14); if (SPICE_UNLIKELY(pos + 4 > message_end)) { goto error; } name__value = read_uint32(pos); if (SPICE_UNLIKELY(message_start + name__value >= message_end)) { goto error; } name__array__nw_size = spice_strnlen((char *)message_start + name__value, message_end - (message_start + name__value)); if (SPICE_UNLIKELY(*(message_start + name__value + name__array__nw_size) != 0)) { goto error; } name__array__mem_size = name__array__nw_size; /* @nocopy, so no extra size */ name__extra_size = 0; } { /* description */ uint32_t description__value; uint32_t description__array__nw_size; uint32_t description__array__mem_size; pos = (start + 18); if (SPICE_UNLIKELY(pos + 4 > message_end)) { goto error; } description__value = read_uint32(pos); if (SPICE_UNLIKELY(message_start + description__value >= message_end)) { goto error; } description__array__nw_size = spice_strnlen((char *)message_start + description__value, message_end - (message_start + description__value)); if (SPICE_UNLIKELY(*(message_start + description__value + description__array__nw_size) != 0)) { goto error; } description__array__mem_size = description__array__nw_size; /* @nocopy, so no extra size */ description__extra_size = 0; } { /* u */ pos = start + 0; if (SPICE_UNLIKELY(pos + 2 > message_end)) { goto error; } type__value = read_uint16(pos); if (type__value == SPICE_TUNNEL_SERVICE_TYPE_IPP) { SPICE_GNUC_UNUSED uint8_t *start2 = (start + 22); size_t u__nw_size; uint16_t type__value; { /* u */ uint32_t u__nelements; pos = start2 + 0; if (SPICE_UNLIKELY(pos + 2 > message_end)) { goto error; } type__value = read_uint16(pos); if (type__value == SPICE_TUNNEL_IP_TYPE_IPv4) { u__nelements = 4; u__nw_size = u__nelements; } else { u__nw_size = 0; } } u__nw_size = 2 + u__nw_size; } else { u__nw_size = 0; } } nw_size = 22 + u__nw_size; mem_size = sizeof(SpiceMsgcTunnelAddGenericService) + name__extra_size + description__extra_size; /* Check if message fits in reported side */ if (start + nw_size > message_end) { return NULL; } /* Validated extents and calculated size */ data = (uint8_t *)malloc(mem_size); if (SPICE_UNLIKELY(data == NULL)) { goto error; } end = data + sizeof(SpiceMsgcTunnelAddGenericService); in = start; out = (SpiceMsgcTunnelAddGenericService *)data; out->type = consume_uint16(&in); out->id = consume_uint32(&in); out->group = consume_uint32(&in); out->port = consume_uint32(&in); /* Reuse data from network message */ out->name = (size_t)(message_start + consume_uint32(&in)); /* Reuse data from network message */ out->description = (size_t)(message_start + consume_uint32(&in)); if (out->type == SPICE_TUNNEL_SERVICE_TYPE_IPP) { out->u.ip.type = consume_uint16(&in); if (out->u.ip.type == SPICE_TUNNEL_IP_TYPE_IPv4) { uint32_t ipv4__nelements; ipv4__nelements = 4; memcpy(out->u.ip.u.ipv4, in, ipv4__nelements); in += ipv4__nelements; } } assert(in <= message_end); for (i = 0; i < n_ptr; i++) { if (ptr_info[i].offset == 0) { *ptr_info[i].dest = NULL; } else { /* Align to 32 bit */ end = (uint8_t *)SPICE_ALIGN((size_t)end, 4); *ptr_info[i].dest = (void *)end; end = ptr_info[i].parse(message_start, message_end, end, &ptr_info[i], minor); if (SPICE_UNLIKELY(end == NULL)) { goto error; } } } assert(end <= data + mem_size); *size = end - data; *free_message = (message_destructor_t) free; return data; error: if (data != NULL) { free(data); } return NULL; }