diff --git a/src/browser/dump.zig b/src/browser/dump.zig index 74fea1d0..cd32b824 100644 --- a/src/browser/dump.zig +++ b/src/browser/dump.zig @@ -46,7 +46,8 @@ pub fn writeNode(node: *parser.Node, writer: anytype) anyerror!void { try writer.writeAll(" "); try writer.writeAll(try parser.attributeGetName(attr)); try writer.writeAll("=\""); - try writer.writeAll(try parser.attributeGetValue(attr) orelse ""); + const attribute_value = try parser.attributeGetValue(attr) orelse ""; + try writeEscapedAttributeValue(writer, attribute_value); try writer.writeAll("\""); i += 1; } @@ -67,7 +68,7 @@ pub fn writeNode(node: *parser.Node, writer: anytype) anyerror!void { }, .text => { const v = try parser.nodeValue(node) orelse return; - try writer.writeAll(v); + try writeEscapedTextNode(writer, v); }, .cdata_section => { const v = try parser.nodeValue(node) orelse return; @@ -119,18 +120,85 @@ fn isVoid(elem: *parser.Element) !bool { }; } +fn writeEscapedTextNode(writer: anytype, value: []const u8) !void { + var v = value; + while (v.len > 0) { + const index = std.mem.indexOfAnyPos(u8, v, 0, &.{'&', '<', '>'}) orelse { + return writer.writeAll(v); + }; + try writer.writeAll(v[0..index]); + switch (v[index]) { + '&' => try writer.writeAll("&"), + '<' => try writer.writeAll("<"), + '>' => try writer.writeAll(">"), + else => unreachable, + } + v = v[index+1..]; + } +} + +fn writeEscapedAttributeValue(writer: anytype, value: []const u8) !void { + var v = value; + while (v.len > 0) { + const index = std.mem.indexOfAnyPos(u8, v, 0, &.{'&', '<', '>', '"'}) orelse { + return writer.writeAll(v); + }; + try writer.writeAll(v[0..index]); + switch (v[index]) { + '&' => try writer.writeAll("&"), + '<' => try writer.writeAll("<"), + '>' => try writer.writeAll(">"), + '"' => try writer.writeAll("""), + else => unreachable, + } + v = v[index+1..]; + } +} + +const testing = std.testing; test "dump.writeHTML" { - const out = try std.fs.openFileAbsolute("/dev/null", .{ .mode = .write_only }); - defer out.close(); + try testWriteHTML( + "
< > &
", + "< > &
" + ); + + try testWriteHTML( + "wat?
", + "wat?
" + ); + + try testWriteFullHTML( + \\ + \\