aboutsummaryrefslogtreecommitdiff
path: root/src/dom
diff options
context:
space:
mode:
Diffstat (limited to 'src/dom')
-rw-r--r--src/dom/Element.zig6
-rw-r--r--src/dom/html.zig47
2 files changed, 51 insertions, 2 deletions
diff --git a/src/dom/Element.zig b/src/dom/Element.zig
index ed7611c..1922a41 100644
--- a/src/dom/Element.zig
+++ b/src/dom/Element.zig
@@ -1,6 +1,7 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const eql = std.mem.eql;
+const html = @import("html.zig");
pub const Kind = enum {
void,
@@ -92,8 +93,9 @@ fn renderAttribute(self: *Self, alloc: Allocator) !std.ArrayList(u8) {
while (iter.next()) |it| : (i += 1) {
try acc.appendSlice(alloc, it.key_ptr.*);
try acc.appendSlice(alloc, "=\"");
- // MISSING ESCAPING!!!
- try acc.appendSlice(alloc, it.value_ptr.*);
+ const escape = try html.escape(alloc, it.value_ptr.*);
+ defer alloc.free(escape);
+ try acc.appendSlice(alloc, escape);
try acc.append(alloc, '"');
if (i < iter.len - 1) try acc.append(alloc, ' ');
}
diff --git a/src/dom/html.zig b/src/dom/html.zig
new file mode 100644
index 0000000..bf62fbb
--- /dev/null
+++ b/src/dom/html.zig
@@ -0,0 +1,47 @@
+const std = @import("std");
+const eql = std.mem.eql;
+
+pub fn escape(gpa: std.mem.Allocator, v: []const u8) ![]const u8 {
+ var acc = try std.ArrayList(u8).initCapacity(gpa, v.len);
+ errdefer acc.deinit(gpa);
+ const view = try std.unicode.Utf8View.init(v);
+ var iter = view.iterator();
+ while (iter.nextCodepointSlice()) |rune| {
+ if (eql(u8, rune, "&")) {
+ try acc.appendSlice(gpa, "&amp;");
+ } else if (eql(u8, rune, "'")) {
+ try acc.appendSlice(gpa, "&#39;");
+ } else if (eql(u8, rune, "<")) {
+ try acc.appendSlice(gpa, "&lt;");
+ } else if (eql(u8, rune, ">")) {
+ try acc.appendSlice(gpa, "&gt;");
+ } else if (eql(u8, rune, "\"")) {
+ try acc.appendSlice(gpa, "&#34;");
+ } else {
+ try acc.appendSlice(gpa, rune);
+ }
+ }
+ return acc.toOwnedSlice(gpa);
+}
+
+fn doTest(alloc: std.mem.Allocator, el: []const u8, exp: []const u8) !void {
+ const got = try escape(alloc, el);
+ defer alloc.free(got);
+ std.testing.expect(eql(u8, got, exp)) catch |err| {
+ std.debug.print("{s}\n", .{got});
+ return err;
+ };
+}
+
+test "escaping html" {
+ var arena = std.heap.DebugAllocator(.{}).init;
+ defer _ = arena.deinit();
+ const alloc = arena.allocator();
+
+ try doTest(alloc, "hello world", "hello world");
+ try doTest(alloc, "hello&world", "hello&amp;world");
+ try doTest(alloc, "hello'world", "hello&#39;world");
+ try doTest(alloc, "hello<world", "hello&lt;world");
+ try doTest(alloc, "hello>world", "hello&gt;world");
+ try doTest(alloc, "hello\"world", "hello&#34;world");
+}