Fix transmission of chunked compressed data
This commit is contained in:
@@ -150,6 +150,25 @@ err:
|
||||
}
|
||||
|
||||
|
||||
static inline const char*
|
||||
zlib_strerror(int ret) {
|
||||
#define Z(x) case x: return #x;
|
||||
static char buf[128];
|
||||
switch(ret) {
|
||||
case Z_ERRNO:
|
||||
return strerror(errno);
|
||||
default:
|
||||
snprintf(buf, sizeof(buf)/sizeof(buf[0]), "Unknown error: %d", ret);
|
||||
return buf;
|
||||
Z(Z_STREAM_ERROR);
|
||||
Z(Z_DATA_ERROR);
|
||||
Z(Z_MEM_ERROR);
|
||||
Z(Z_BUF_ERROR);
|
||||
Z(Z_VERSION_ERROR);
|
||||
}
|
||||
#undef Z
|
||||
}
|
||||
|
||||
static inline bool
|
||||
inflate_zlib(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufsz) {
|
||||
bool ok = false;
|
||||
@@ -164,13 +183,13 @@ inflate_zlib(GraphicsManager UNUSED *self, Image *img, uint8_t *buf, size_t bufs
|
||||
z.avail_out = img->load_data.data_sz;
|
||||
z.next_out = decompressed;
|
||||
int ret;
|
||||
if ((ret = inflateInit(&z)) != Z_OK) ABRT(ENOMEM, "Failed to initialize inflate with error code: %d", ret);
|
||||
if ((ret = inflate(&z, Z_FINISH)) != Z_STREAM_END) ABRT(EINVAL, "Failed to inflate image data with error code: %d", ret);
|
||||
if ((ret = inflateInit(&z)) != Z_OK) ABRT(ENOMEM, "Failed to initialize inflate with error: %s", zlib_strerror(ret));
|
||||
if ((ret = inflate(&z, Z_FINISH)) != Z_STREAM_END) ABRT(EINVAL, "Failed to inflate image data with error: %s", zlib_strerror(ret));
|
||||
if (z.avail_out) ABRT(EINVAL, "Image data size post inflation does not match expected size");
|
||||
free_load_data(&img->load_data);
|
||||
img->load_data.buf_capacity = img->load_data.data_sz;
|
||||
img->load_data.buf = decompressed;
|
||||
img->load_data.buf_used = img->load_data.data_sz - z.avail_out;
|
||||
img->load_data.buf_used = img->load_data.data_sz;
|
||||
ok = true;
|
||||
err:
|
||||
inflateEnd(&z);
|
||||
@@ -319,8 +338,8 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
|
||||
uint32_t fmt = g->format ? g->format : RGBA;
|
||||
if (tt == 'd' && self->loading_image) init_img = false;
|
||||
if (init_img) {
|
||||
self->last_init_graphics_command = *g;
|
||||
self->loading_image = 0;
|
||||
self->last_init_img_action = g->action;
|
||||
if (g->data_width > 10000 || g->data_height > 10000) ABRT(EINVAL, "Image too large");
|
||||
remove_images(self, add_trim_predicate);
|
||||
img = find_or_create_image(self, g->id, &existing);
|
||||
@@ -363,6 +382,11 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self->last_init_graphics_command.more = g->more;
|
||||
self->last_init_graphics_command.payload_sz = g->payload_sz;
|
||||
g = &self->last_init_graphics_command;
|
||||
tt = g->transmission_type ? g->transmission_type : 'd';
|
||||
fmt = g->format ? g->format : RGBA;
|
||||
img = img_by_internal_id(self, self->loading_image);
|
||||
if (img == NULL) {
|
||||
self->loading_image = 0;
|
||||
@@ -602,8 +626,8 @@ grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint
|
||||
case 't':
|
||||
case 'T':
|
||||
image = handle_add_command(self, g, payload, is_dirty);
|
||||
ret = create_add_response(self, g, image != NULL);
|
||||
if (self->last_init_img_action == 'T') handle_put_command(self, g, c, is_dirty, image);
|
||||
ret = create_add_response(self, &self->last_init_graphics_command, image != NULL);
|
||||
if (self->last_init_graphics_command.action == 'T' && image && image->data_loaded) handle_put_command(self, &self->last_init_graphics_command, c, is_dirty, image);
|
||||
break;
|
||||
case 'p':
|
||||
if (!g->id) {
|
||||
|
||||
@@ -64,7 +64,7 @@ typedef struct {
|
||||
|
||||
index_type lines, columns;
|
||||
size_t image_count, images_capacity, loading_image;
|
||||
char last_init_img_action;
|
||||
GraphicsCommand last_init_graphics_command;
|
||||
Image *images;
|
||||
size_t count, capacity, rp_capacity;
|
||||
ImageRenderData *render_data;
|
||||
|
||||
@@ -648,7 +648,7 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) {
|
||||
state = PAYLOAD;
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("Malformed graphics control block, expecting a comma or semi-colon after a value, found: 0x%x", screen->parser_buf[screen->parser_buf_pos - 1]);
|
||||
REPORT_ERROR("Malformed graphics control block, expecting a comma or semi-colon after a value, found: 0x%x", screen->parser_buf[pos - 1]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -101,6 +101,13 @@ class TestGraphics(BaseTest):
|
||||
expecting_data=random_data
|
||||
)
|
||||
|
||||
# Test chunked + compressed
|
||||
b = len(compressed_random_data) // 2
|
||||
self.assertIsNone(l(compressed_random_data[:b], s=24, v=32, o='z', m=1))
|
||||
self.ae(l(compressed_random_data[b:], m=0), 'OK')
|
||||
img = g.image_for_client_id(1)
|
||||
self.ae(img['data'], random_data)
|
||||
|
||||
# Test loading from file
|
||||
f = tempfile.NamedTemporaryFile()
|
||||
f.write(random_data), f.flush()
|
||||
|
||||
Reference in New Issue
Block a user