size: 2 KiB
const std = @import("std"); const t = std.testing; pub fn escapeAlloc(arena: std.mem.Allocator, text: []const u8) ![]const u8 { var w = std.Io.Writer.Allocating.init(arena); try escape(&w.writer, text); return w.written(); } pub fn escape(out: *std.Io.Writer, text: []const u8) !void { for (text) |char| { switch (char) { '&' => try out.writeAll("&"), '"' => try out.writeAll("""), '\'' => try out.writeAll("'"), '<' => try out.writeAll("<"), '>' => try out.writeAll(">"), else => try out.writeByte(char), } } } test "escape" { var buf: [4096]u8 = undefined; inline for (.{ .{ "<script>alert(\"jello\")</script>", "<script>alert("jello")</script>", }, .{ "&\"'<>", "&"'<>", }, }) |case| { const input = case[0]; const expected = case[1]; var w = std.Io.Writer.fixed(&buf); try escape(&w, input); try t.expectEqualStrings(expected, w.buffered()); } } pub fn percentEncode(out: *std.Io.Writer, text: []const u8) !void { for (text) |char| { switch (char) { ':' => try out.writeAll("%3A"), '/' => try out.writeAll("%2F"), '?' => try out.writeAll("%3F"), '#' => try out.writeAll("%23"), '[' => try out.writeAll("%5B"), ']' => try out.writeAll("%5D"), '@' => try out.writeAll("%40"), '!' => try out.writeAll("%21"), '$' => try out.writeAll("%24"), '&' => try out.writeAll("%26"), '\'' => try out.writeAll("%27"), '(' => try out.writeAll("%28"), ')' => try out.writeAll("%29"), '*' => try out.writeAll("%2A"), '+' => try out.writeAll("%2B"), ',' => try out.writeAll("%2C"), ';' => try out.writeAll("%3B"), '=' => try out.writeAll("%3D"), '%' => try out.writeAll("%25"), ' ' => try out.writeAll("%20"), else => try out.writeByte(char), } } } pub fn percentEncodeAlloc(arena: std.mem.Allocator, text: []const u8) ![]const u8 { var w = std.Io.Writer.Allocating.init(arena); try percentEncode(&w.writer, text); return w.written(); }