aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-07 18:29:21 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-07 18:29:21 +0300
commitdcfe11a7588fcd42471159453810abc9b7720a57 (patch)
treec32a77266028e73ca2382b96c96f8438a5fcd621 /vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig
parent2dfed860103c4e4505ac7f25def9fe37da1e1e6a (diff)
build: update libghostty-vt vendor
vendor ghostty 063ac3e and remove the musl libc++ link workaround. expose the new selection formatter and hyperlink uri apis for follow-up rendering work. add manual artifact validation for static linux builds.
Diffstat (limited to 'vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig')
-rw-r--r--vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig114
1 files changed, 61 insertions, 53 deletions
diff --git a/vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig b/vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig
index dfce56e3..aa35fbeb 100644
--- a/vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig
+++ b/vendor/libghostty-vt/src/terminal/kitty/graphics_command.zig
@@ -3,6 +3,7 @@ const assert = @import("../../quirks.zig").inlineAssert;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const simd = @import("../../simd/main.zig");
+const lib = @import("../lib.zig");
const log = std.log.scoped(.kitty_gfx);
@@ -37,6 +38,10 @@ pub const Parser = struct {
/// here instead of a fixed buffer so that we can too.
data: std.ArrayList(u8),
+ /// Maximum bytes the data payload can take. This is to prevent
+ /// malicious input from causing us to allocate too much memory.
+ max_bytes: usize,
+
/// Internal state for parsing.
state: State,
@@ -54,7 +59,7 @@ pub const Parser = struct {
/// Initialize the parser. The allocator given will be used for both
/// temporary data and long-lived values such as the final image blob.
- pub fn init(alloc: Allocator) Parser {
+ pub fn init(alloc: Allocator, max_bytes: usize) Parser {
var arena = ArenaAllocator.init(alloc);
errdefer arena.deinit();
var result: Parser = .{
@@ -63,6 +68,7 @@ pub const Parser = struct {
.kv = .{},
.kv_temp_len = 0,
.kv_current = 0,
+ .max_bytes = max_bytes,
.state = .control_key,
.kv_temp = undefined,
@@ -83,7 +89,7 @@ pub const Parser = struct {
/// Parse a complete command string.
pub fn parseString(alloc: Allocator, data: []const u8) !Command {
- var parser = init(alloc);
+ var parser = init(alloc, 1024 * 1024);
defer parser.deinit();
for (data) |c| try parser.feed(c);
return try parser.complete(alloc);
@@ -136,7 +142,10 @@ pub const Parser = struct {
else => {},
},
- .data => try self.data.append(self.arena.child_allocator, c),
+ .data => {
+ if (self.data.items.len >= self.max_bytes) return error.OutOfMemory;
+ try self.data.append(self.arena.child_allocator, c);
+ },
}
}
@@ -394,39 +403,38 @@ pub const Transmission = struct {
compression: Compression = .none, // o
more_chunks: bool = false, // m
- pub const Format = enum {
- rgb, // 24
- rgba, // 32
- png, // 100
-
+ pub const Format = lib.Enum(lib.target, &.{
+ "rgb", // 24
+ "rgba", // 32
+ "png", // 100
// The following are not supported directly via the protocol
// but they are formats that a png may decode to that we
// support.
- gray_alpha,
- gray,
-
- pub fn bpp(self: Format) u8 {
- return switch (self) {
- .gray => 1,
- .gray_alpha => 2,
- .rgb => 3,
- .rgba => 4,
- .png => unreachable, // Must be validated before
- };
- }
- };
-
- pub const Medium = enum {
- direct, // d
- file, // f
- temporary_file, // t
- shared_memory, // s
- };
-
- pub const Compression = enum {
- none,
- zlib_deflate, // z
- };
+ "gray_alpha",
+ "gray",
+ });
+
+ pub const Medium = lib.Enum(lib.target, &.{
+ "direct", // d
+ "file", // f
+ "temporary_file", // t
+ "shared_memory", // s
+ });
+
+ pub const Compression = lib.Enum(lib.target, &.{
+ "none",
+ "zlib_deflate", // z
+ });
+
+ pub fn formatBpp(format: Format) u8 {
+ return switch (format) {
+ .gray => 1,
+ .gray_alpha => 2,
+ .rgb => 3,
+ .rgba => 4,
+ .png => unreachable, // Must be validated before
+ };
+ }
fn parse(kv: KV) !Transmission {
var result: Transmission = .{};
@@ -964,7 +972,7 @@ pub const CompositionMode = enum {
test "transmission command" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "f=24,s=10,v=20";
@@ -982,7 +990,7 @@ test "transmission command" {
test "transmission ignores 'm' if medium is not direct" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=t,t=t,m=1";
@@ -999,7 +1007,7 @@ test "transmission ignores 'm' if medium is not direct" {
test "transmission respects 'm' if medium is direct" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=t,t=d,m=1";
@@ -1016,7 +1024,7 @@ test "transmission respects 'm' if medium is direct" {
test "query command" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "i=31,s=1,v=1,a=q,t=d,f=24;QUFBQQ";
@@ -1036,7 +1044,7 @@ test "query command" {
test "display command" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=p,U=1,i=31,c=80,r=120";
@@ -1054,7 +1062,7 @@ test "display command" {
test "delete command" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=d,d=p,x=3,y=4";
@@ -1074,7 +1082,7 @@ test "delete command" {
test "no control data" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = ";QUFBQQ";
@@ -1089,7 +1097,7 @@ test "no control data" {
test "ignore unknown keys (long)" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "f=24,s=10,v=20,hello=world";
@@ -1107,7 +1115,7 @@ test "ignore unknown keys (long)" {
test "ignore very long values" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "f=24,s=10,v=2000000000000000000000000000000000000000";
@@ -1125,7 +1133,7 @@ test "ignore very long values" {
test "ensure very large negative values don't get skipped" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=p,i=1,z=-2000000000";
@@ -1142,7 +1150,7 @@ test "ensure very large negative values don't get skipped" {
test "ensure proper overflow error for u32" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=p,i=10000000000";
@@ -1153,7 +1161,7 @@ test "ensure proper overflow error for u32" {
test "ensure proper overflow error for i32" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=p,i=1,z=-9999999999";
@@ -1167,7 +1175,7 @@ test "all i32 values" {
{
// 'z' (usually z-axis values)
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=p,i=1,z=-1";
for (input) |c| try p.feed(c);
@@ -1182,7 +1190,7 @@ test "all i32 values" {
{
// 'H' (relative placement, horizontal offset)
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=p,i=1,H=-1";
for (input) |c| try p.feed(c);
@@ -1197,7 +1205,7 @@ test "all i32 values" {
{
// 'V' (relative placement, vertical offset)
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=p,i=1,V=-1";
for (input) |c| try p.feed(c);
@@ -1254,7 +1262,7 @@ test "response: encode with image ID and number" {
test "delete range command 1" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=d,d=r,x=3,y=4";
@@ -1274,7 +1282,7 @@ test "delete range command 1" {
test "delete range command 2" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=d,d=R,x=5,y=11";
@@ -1294,7 +1302,7 @@ test "delete range command 2" {
test "delete range command 3" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=d,d=R,x=5,y=4";
@@ -1305,7 +1313,7 @@ test "delete range command 3" {
test "delete range command 4" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=d,d=R,x=5";
@@ -1316,7 +1324,7 @@ test "delete range command 4" {
test "delete range command 5" {
const testing = std.testing;
const alloc = testing.allocator;
- var p = Parser.init(alloc);
+ var p = Parser.init(alloc, 1024 * 1024);
defer p.deinit();
const input = "a=d,d=R,y=5";