From b00f7310f3d9b38a4989ff89a2c60865ac106b1c Mon Sep 17 00:00:00 2001 From: Chris Dollin Date: Mon, 28 Feb 2011 14:09:04 -0500 Subject: [PATCH] xml: permit nested directives Return with nested directives as one big token. Fixes #1549. R=niemeyer, rsc CC=golang-dev https://golang.org/cl/4216050 --- src/pkg/xml/xml.go | 23 +++++++++++++++++++-- src/pkg/xml/xml_test.go | 46 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/pkg/xml/xml.go b/src/pkg/xml/xml.go index 417b4edfde..691c13a118 100644 --- a/src/pkg/xml/xml.go +++ b/src/pkg/xml/xml.go @@ -541,17 +541,36 @@ func (p *Parser) RawToken() (Token, os.Error) { } // Probably a directive: , , etc. - // We don't care, but accumulate for caller. + // We don't care, but accumulate for caller. Quoted angle + // brackets do not count for nesting. p.buf.Reset() p.buf.WriteByte(b) + inquote := uint8(0) + depth := 0 for { if b, ok = p.mustgetc(); !ok { return nil, p.err } - if b == '>' { + if inquote == 0 && b == '>' && depth == 0 { break } p.buf.WriteByte(b) + switch { + case b == inquote: + inquote = 0 + + case inquote != 0: + // in quotes, no special action + + case b == '\'' || b == '"': + inquote = b + + case b == '>' && inquote == 0: + depth-- + + case b == '<' && inquote == 0: + depth++ + } } return Directive(p.buf.Bytes()), nil } diff --git a/src/pkg/xml/xml_test.go b/src/pkg/xml/xml_test.go index 317ecabd90..887bc3d140 100644 --- a/src/pkg/xml/xml_test.go +++ b/src/pkg/xml/xml_test.go @@ -185,6 +185,52 @@ func TestRawToken(t *testing.T) { } } +// Ensure that directives (specifically !DOCTYPE) include the complete +// text of any nested directives, noting that < and > do not change +// nesting depth if they are in single or double quotes. + +var nestedDirectivesInput = ` +]> +">]> +]> +'>]> +]> +'>]> +]> +` + +var nestedDirectivesTokens = []Token{ + CharData([]byte("\n")), + Directive([]byte(`DOCTYPE []`)), + CharData([]byte("\n")), + Directive([]byte(`DOCTYPE [">]`)), + CharData([]byte("\n")), + Directive([]byte(`DOCTYPE []`)), + CharData([]byte("\n")), + Directive([]byte(`DOCTYPE ['>]`)), + CharData([]byte("\n")), + Directive([]byte(`DOCTYPE []`)), + CharData([]byte("\n")), + Directive([]byte(`DOCTYPE ['>]`)), + CharData([]byte("\n")), + Directive([]byte(`DOCTYPE []`)), + CharData([]byte("\n")), +} + +func TestNestedDirectives(t *testing.T) { + p := NewParser(StringReader(nestedDirectivesInput)) + + for i, want := range nestedDirectivesTokens { + have, err := p.Token() + if err != nil { + t.Fatalf("token %d: unexpected error: %s", i, err) + } + if !reflect.DeepEqual(have, want) { + t.Errorf("token %d = %#v want %#v", i, have, want) + } + } +} + func TestToken(t *testing.T) { p := NewParser(StringReader(testInput))