size: 2 KiB

1const std = @import("std");
2const t = std.testing;
3
4pub fn escapeAlloc(arena: std.mem.Allocator, text: []const u8) ![]const u8 {
5 var w = std.Io.Writer.Allocating.init(arena);
6 try escape(&w.writer, text);
7 return w.written();
8}
9
10pub fn escape(out: *std.Io.Writer, text: []const u8) !void {
11 for (text) |char| {
12 switch (char) {
13 '&' => try out.writeAll("&"),
14 '"' => try out.writeAll("""),
15 '\'' => try out.writeAll("'"),
16 '<' => try out.writeAll("&lt;"),
17 '>' => try out.writeAll("&gt;"),
18 else => try out.writeByte(char),
19 }
20 }
21}
22
23test "escape" {
24 var buf: [4096]u8 = undefined;
25 inline for (.{
26 .{
27 "<script>alert(\"jello\")</script>",
28 "&lt;script&gt;alert(&quot;jello&quot;)&lt;/script&gt;",
29 },
30 .{
31 "&\"'<>",
32 "&amp;&quot;&#39;&lt;&gt;",
33 },
34 }) |case| {
35 const input = case[0];
36 const expected = case[1];
37 var w = std.Io.Writer.fixed(&buf);
38 try escape(&w, input);
39 try t.expectEqualStrings(expected, w.buffered());
40 }
41}
42
43pub fn percentEncode(out: *std.Io.Writer, text: []const u8) !void {
44 for (text) |char| {
45 switch (char) {
46 ':' => try out.writeAll("%3A"),
47 '/' => try out.writeAll("%2F"),
48 '?' => try out.writeAll("%3F"),
49 '#' => try out.writeAll("%23"),
50 '[' => try out.writeAll("%5B"),
51 ']' => try out.writeAll("%5D"),
52 '@' => try out.writeAll("%40"),
53 '!' => try out.writeAll("%21"),
54 '$' => try out.writeAll("%24"),
55 '&' => try out.writeAll("%26"),
56 '\'' => try out.writeAll("%27"),
57 '(' => try out.writeAll("%28"),
58 ')' => try out.writeAll("%29"),
59 '*' => try out.writeAll("%2A"),
60 '+' => try out.writeAll("%2B"),
61 ',' => try out.writeAll("%2C"),
62 ';' => try out.writeAll("%3B"),
63 '=' => try out.writeAll("%3D"),
64 '%' => try out.writeAll("%25"),
65 ' ' => try out.writeAll("%20"),
66 else => try out.writeByte(char),
67 }
68 }
69}
70
71pub fn percentEncodeAlloc(arena: std.mem.Allocator, text: []const u8) ![]const u8 {
72 var w = std.Io.Writer.Allocating.init(arena);
73 try percentEncode(&w.writer, text);
74 return w.written();
75}