Allow larger graphics escape code sizes

This commit is contained in:
Kovid Goyal
2023-11-09 07:52:59 +05:30
parent 56abcbf910
commit 409ca6bfab
3 changed files with 23 additions and 17 deletions

View File

@@ -113,11 +113,11 @@ def generate(
if payload_allowed: if payload_allowed:
payload_after_value = "case ';': state = PAYLOAD; break;" payload_after_value = "case ';': state = PAYLOAD; break;"
payload = ', PAYLOAD' payload = ', PAYLOAD'
parr = 'static uint8_t payload[4096];' parr = 'uint8_t *payload = parser_buf;'
payload_case = f''' payload_case = f'''
case PAYLOAD: {{ case PAYLOAD: {{
sz = parser_buf_pos - pos; sz = parser_buf_pos - pos;
g.payload_sz = sizeof(payload); g.payload_sz = MAX(BUF_EXTRA, sz);
if (!base64_decode8(parser_buf + pos, sz, payload, &g.payload_sz)) {{ if (!base64_decode8(parser_buf + pos, sz, payload, &g.payload_sz)) {{
REPORT_ERROR("Failed to parse {command_class} command payload with error: payload size (%zu) too large", sz); return; }} REPORT_ERROR("Failed to parse {command_class} command payload with error: payload size (%zu) too large", sz); return; }}
pos = parser_buf_pos; pos = parser_buf_pos;
@@ -132,7 +132,7 @@ def generate(
return f''' return f'''
#include "base64.h" #include "base64.h"
static inline void static inline void
{function_name}(PS *self, const uint8_t *parser_buf, const size_t parser_buf_pos) {{ {function_name}(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) {{
unsigned int pos = 1; unsigned int pos = 1;
enum PARSER_STATES {{ KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE {payload} }}; enum PARSER_STATES {{ KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE {payload} }};
enum PARSER_STATES state = KEY, value_state = FLAG; enum PARSER_STATES state = KEY, value_state = FLAG;

View File

@@ -3,7 +3,7 @@
#pragma once #pragma once
#include "base64.h" #include "base64.h"
static inline void parse_graphics_code(PS *self, const uint8_t *parser_buf, static inline void parse_graphics_code(PS *self, uint8_t *parser_buf,
const size_t parser_buf_pos) { const size_t parser_buf_pos) {
unsigned int pos = 1; unsigned int pos = 1;
enum PARSER_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE, PAYLOAD }; enum PARSER_STATES { KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE, PAYLOAD };
@@ -14,7 +14,7 @@ static inline void parse_graphics_code(PS *self, const uint8_t *parser_buf,
bool is_negative; bool is_negative;
memset(&g, 0, sizeof(g)); memset(&g, 0, sizeof(g));
size_t sz; size_t sz;
static uint8_t payload[4096]; uint8_t *payload = parser_buf;
enum KEYS { enum KEYS {
action = 'a', action = 'a',
@@ -320,7 +320,7 @@ static inline void parse_graphics_code(PS *self, const uint8_t *parser_buf,
case PAYLOAD: { case PAYLOAD: {
sz = parser_buf_pos - pos; sz = parser_buf_pos - pos;
g.payload_sz = sizeof(payload); g.payload_sz = MAX(BUF_EXTRA, sz);
if (!base64_decode8(parser_buf + pos, sz, payload, &g.payload_sz)) { if (!base64_decode8(parser_buf + pos, sz, payload, &g.payload_sz)) {
REPORT_ERROR("Failed to parse GraphicsCommand command payload with " REPORT_ERROR("Failed to parse GraphicsCommand command payload with "
"error: payload size (%zu) too large", "error: payload size (%zu) too large",

View File

@@ -7,13 +7,12 @@ import tempfile
import time import time
import unittest import unittest
import zlib import zlib
from base64 import standard_b64decode, standard_b64encode
from contextlib import suppress from contextlib import suppress
from dataclasses import dataclass from dataclasses import dataclass
from io import BytesIO from io import BytesIO
from itertools import cycle from itertools import cycle
from kitty.fast_data_types import load_png_data, shm_unlink, shm_write, xor_data from kitty.fast_data_types import base64_decode, base64_encode, load_png_data, shm_unlink, shm_write, xor_data
from . import BaseTest, parse_bytes from . import BaseTest, parse_bytes
@@ -28,7 +27,7 @@ def send_command(screen, cmd, payload=b''):
if payload: if payload:
if isinstance(payload, str): if isinstance(payload, str):
payload = payload.encode('utf-8') payload = payload.encode('utf-8')
payload = standard_b64encode(payload).decode('ascii') payload = base64_encode(payload).decode('ascii')
cmd += ';' + payload cmd += ';' + payload
cmd += '\033\\' cmd += '\033\\'
c = screen.callbacks c = screen.callbacks
@@ -342,20 +341,27 @@ class TestGraphics(BaseTest):
img = g.image_for_client_id(1) img = g.image_for_client_id(1)
self.ae(img['data'], b'abcdefghijklmnop') self.ae(img['data'], b'abcdefghijklmnop')
random_data = byte_block(32 * 1024)
sl(
random_data,
s=1024,
v=8,
expecting_data=random_data
)
# Test compression # Test compression
random_data = byte_block(3 * 1024)
compressed_random_data = zlib.compress(random_data) compressed_random_data = zlib.compress(random_data)
sl( sl(
compressed_random_data, compressed_random_data,
s=24, s=1024,
v=32, v=8,
o='z', o='z',
expecting_data=random_data expecting_data=random_data
) )
# Test chunked + compressed # Test chunked + compressed
b = len(compressed_random_data) // 2 b = len(compressed_random_data) // 2
self.assertIsNone(pl(compressed_random_data[:b], s=24, v=32, o='z', m=1)) self.assertIsNone(pl(compressed_random_data[:b], s=1024, v=8, o='z', m=1))
self.ae(pl(compressed_random_data[b:], m=0), 'OK') self.ae(pl(compressed_random_data[b:], m=0), 'OK')
img = g.image_for_client_id(1) img = g.image_for_client_id(1)
self.ae(img['data'], random_data) self.ae(img['data'], random_data)
@@ -364,10 +370,10 @@ class TestGraphics(BaseTest):
def load_temp(prefix='tty-graphics-protocol-'): def load_temp(prefix='tty-graphics-protocol-'):
f = tempfile.NamedTemporaryFile(prefix=prefix) f = tempfile.NamedTemporaryFile(prefix=prefix)
f.write(random_data), f.flush() f.write(random_data), f.flush()
sl(f.name, s=24, v=32, t='f', expecting_data=random_data) sl(f.name, s=1024, v=8, t='f', expecting_data=random_data)
self.assertTrue(os.path.exists(f.name)) self.assertTrue(os.path.exists(f.name))
f.seek(0), f.truncate(), f.write(compressed_random_data), f.flush() f.seek(0), f.truncate(), f.write(compressed_random_data), f.flush()
sl(f.name, s=24, v=32, t='t', o='z', expecting_data=random_data) sl(f.name, s=1024, v=8, t='t', o='z', expecting_data=random_data)
return f return f
f = load_temp() f = load_temp()
@@ -381,7 +387,7 @@ class TestGraphics(BaseTest):
# Test loading from POSIX SHM # Test loading from POSIX SHM
name = '/kitty-test-shm' name = '/kitty-test-shm'
shm_write(name, random_data) shm_write(name, random_data)
sl(name, s=24, v=32, t='s', expecting_data=random_data) sl(name, s=1024, v=8, t='s', expecting_data=random_data)
self.assertRaises( self.assertRaises(
FileNotFoundError, shm_unlink, name FileNotFoundError, shm_unlink, name
) # check that file was deleted ) # check that file was deleted
@@ -421,7 +427,7 @@ class TestGraphics(BaseTest):
def test_load_png_simple(self): def test_load_png_simple(self):
# 1x1 transparent PNG # 1x1 transparent PNG
png_data = standard_b64decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==') png_data = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==')
expected = b'\x00\xff\xff\x7f' expected = b'\x00\xff\xff\x7f'
self.ae(load_png_data(png_data), (expected, 1, 1)) self.ae(load_png_data(png_data), (expected, 1, 1))
s, g, pl, sl = load_helpers(self) s, g, pl, sl = load_helpers(self)