]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/xml: fix to allow xml declaration with EncodeToken
authorJason Del Ponte <delpontej@gmail.com>
Tue, 13 May 2014 03:35:56 +0000 (23:35 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 13 May 2014 03:35:56 +0000 (23:35 -0400)
This changes allows the first token encoded to be a xml declaration. A ProcInst with target of xml. Any other ProcInst after that with a target of xml will fail

Fixes #7380.

LGTM=rsc
R=golang-codereviews, rsc
CC=golang-codereviews
https://golang.org/cl/72410043

src/pkg/encoding/xml/marshal.go
src/pkg/encoding/xml/marshal_test.go

index d9522e0b39f718c0a24dfadfdd9a5ade616cd2f6..8c6342013d330484aca25b65f967d0b3f3c47658 100644 (file)
@@ -184,10 +184,12 @@ var (
 // EncodeToken does not call Flush, because usually it is part of a larger operation
 // such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
 // during those), and those will call Flush when finished.
-//
 // Callers that create an Encoder and then invoke EncodeToken directly, without
 // using Encode or EncodeElement, need to call Flush when finished to ensure
 // that the XML is written to the underlying writer.
+//
+// EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token
+// in the stream.
 func (enc *Encoder) EncodeToken(t Token) error {
        p := &enc.p
        switch t := t.(type) {
@@ -210,7 +212,12 @@ func (enc *Encoder) EncodeToken(t Token) error {
                p.WriteString("-->")
                return p.cachedWriteError()
        case ProcInst:
-               if t.Target == "xml" || !isNameString(t.Target) {
+               // First token to be encoded which is also a ProcInst with target of xml
+               // is the xml declaration.  The only ProcInst where target of xml is allowed.
+               if t.Target == "xml" && p.Buffered() != 0 {
+                       return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
+               }
+               if !isNameString(t.Target) {
                        return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
                }
                if bytes.Contains(t.Inst, endProcInst) {
index ecb9998dacbfb0520822a1bb8f676e7c8b2bd027..638158397b8e48721273b4ec1d5fee8161450ca3 100644 (file)
@@ -1203,7 +1203,7 @@ var encodeTokenTests = []struct {
        {Comment("foo"), "<!--foo-->", true},
        {Comment("foo-->"), "", false},
        {ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
-       {ProcInst{"xml", []byte("Instruction")}, "", false},
+       {ProcInst{"", []byte("Instruction")}, "", false},
        {ProcInst{"Target", []byte("Instruction?>")}, "", false},
        {Directive("foo"), "<!foo>", true},
        {Directive("foo>"), "", false},
@@ -1230,3 +1230,37 @@ func TestEncodeToken(t *testing.T) {
                }
        }
 }
+
+func TestProcInstEncodeToken(t *testing.T) {
+       var buf bytes.Buffer
+       enc := NewEncoder(&buf)
+
+       if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
+               t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
+       }
+
+       if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
+               t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
+       }
+
+       if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
+               t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
+       }
+}
+
+func TestDecodeEncode(t *testing.T) {
+       var in, out bytes.Buffer
+       in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
+<?Target Instruction?>
+<root>
+</root>        
+`)
+       dec := NewDecoder(&in)
+       enc := NewEncoder(&out)
+       for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
+               err = enc.EncodeToken(tok)
+               if err != nil {
+                       t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %d", tok, err)
+               }
+       }
+}