diff --git a/encode.go b/encode.go index 78eb981..508b16c 100644 --- a/encode.go +++ b/encode.go @@ -51,6 +51,7 @@ func (e *Encoder) Encode(v interface{}) error { } enc := newXMLEncoder(e.w) + enc.indent = e.indent enc.Indent("", e.indent) return enc.generateDocument(pval) } diff --git a/encode_test.go b/encode_test.go index 2210abf..7d99f55 100644 --- a/encode_test.go +++ b/encode_test.go @@ -79,39 +79,63 @@ var dictRef = ` var indentRef = ` + + Boolean + + BooleanList + + + + + CFBundleInfoDictionaryVersion + 6.0 + Strings + + a + b + + band-size + 8388608 + bundle-backingstore-version + 1 + diskimage-bundle-type + com.apple.diskimage.sparsebundle + size + 4398046511104 + useless - CFBundleInfoDictionaryVersion - 6.0 - band-size - 8388608 - bundle-backingstore-version - 1 - diskimage-bundle-type - com.apple.diskimage.sparsebundle - size - 4398046511104 - useless - - unused-string - unused - + unused-string + unused + ` var indentRefOmit = ` - - CFBundleInfoDictionaryVersion - 6.0 - bundle-backingstore-version - 1 - diskimage-bundle-type - com.apple.diskimage.sparsebundle - size - 4398046511104 - + + Boolean + + BooleanList + + + + + CFBundleInfoDictionaryVersion + 6.0 + Strings + + a + b + + bundle-backingstore-version + 1 + diskimage-bundle-type + com.apple.diskimage.sparsebundle + size + 4398046511104 + ` @@ -180,11 +204,11 @@ func TestNewLineString(t *testing.T) { var ok = ` - - Content - foo + + Content + foo bar - + ` out := string(b) @@ -203,6 +227,9 @@ func TestIndent(t *testing.T) { DiskImageBundleType string `plist:"diskimage-bundle-type"` Size uint64 `plist:"size"` Unused testStruct `plist:"useless"` + Boolean bool + BooleanList []bool + Strings []string }{ InfoDictionaryVersion: "6.0", BandSize: 8388608, @@ -210,6 +237,9 @@ func TestIndent(t *testing.T) { DiskImageBundleType: "com.apple.diskimage.sparsebundle", BackingStoreVersion: 1, Unused: testStruct{UnusedString: "unused"}, + Boolean: true, + BooleanList: []bool{true, false}, + Strings: []string{"a", "b"}, } b, err := MarshalIndent(sparseBundleHeader, " ") if err != nil { @@ -217,7 +247,7 @@ func TestIndent(t *testing.T) { } out := string(b) if out != indentRef { - t.Errorf("MarshalIndent(%v) = \n%v, \nwant\n %v", sparseBundleHeader, out, indentRef) + t.Errorf("MarshalIndent(%v) = \n%v, \nwant\n%v", sparseBundleHeader, out, indentRef) } } @@ -230,6 +260,9 @@ func TestOmitNotEmpty(t *testing.T) { DiskImageBundleType string `plist:"diskimage-bundle-type"` Size uint64 `plist:"size"` Unused testStruct `plist:"useless"` + Boolean bool + BooleanList []bool + Strings []string }{ InfoDictionaryVersion: "6.0", BandSize: 8388608, @@ -237,6 +270,9 @@ func TestOmitNotEmpty(t *testing.T) { DiskImageBundleType: "com.apple.diskimage.sparsebundle", BackingStoreVersion: 1, Unused: testStruct{UnusedString: "unused"}, + Boolean: true, + BooleanList: []bool{true, false}, + Strings: []string{"a", "b"}, } b, err := MarshalIndent(sparseBundleHeader, " ") if err != nil { @@ -244,7 +280,7 @@ func TestOmitNotEmpty(t *testing.T) { } out := string(b) if out != indentRef { - t.Errorf("MarshalIndent(%v) = \n%v, \nwant\n %v", sparseBundleHeader, out, indentRef) + t.Errorf("MarshalIndent(%v) = \n%v, \nwant\n %v", sparseBundleHeader, out, indentRefOmit) } } @@ -257,11 +293,17 @@ func TestOmitIsEmpty(t *testing.T) { DiskImageBundleType string `plist:"diskimage-bundle-type"` Size uint64 `plist:"size"` Unused testStruct `plist:"useless,omitempty"` + Boolean bool + BooleanList []bool + Strings []string }{ InfoDictionaryVersion: "6.0", Size: 4 * 1048576 * 1024 * 1024, DiskImageBundleType: "com.apple.diskimage.sparsebundle", BackingStoreVersion: 1, + Boolean: true, + BooleanList: []bool{true, false}, + Strings: []string{"a", "b"}, } b, err := MarshalIndent(sparseBundleHeader, " ") if err != nil { diff --git a/xml_writer.go b/xml_writer.go index 1058acd..199e7a8 100644 --- a/xml_writer.go +++ b/xml_writer.go @@ -11,52 +11,47 @@ import ( ) const xmlDOCTYPE = `` +const plistStart = `` +const plistEnd = `` type xmlEncoder struct { - writer io.Writer + indent string + indentCount int + err error + writer io.Writer *xml.Encoder } +func (e *xmlEncoder) write(buf []byte) { + if e.err != nil { + return + } + _, e.err = e.writer.Write(buf) +} + func newXMLEncoder(w io.Writer) *xmlEncoder { - return &xmlEncoder{w, xml.NewEncoder(w)} + return &xmlEncoder{writer: w, Encoder: xml.NewEncoder(w)} } func (e *xmlEncoder) generateDocument(pval *plistValue) error { - // xml version=1.0 - _, err := e.writer.Write([]byte(xml.Header)) - if err != nil { - return err - } - - //!DOCTYPE plist - _, err = e.writer.Write([]byte(xmlDOCTYPE)) - if err != nil { - return err + e.write([]byte(xml.Header)) + e.write([]byte(xmlDOCTYPE)) + e.write([]byte("\n")) + e.write([]byte(plistStart)) + if e.indent != "" { + e.write([]byte("\n")) } - // newline after doctype - // tag starts on new line - _, err = e.writer.Write([]byte("\n")) - if err != nil { + if err := e.writePlistValue(pval); err != nil { return err } - tokenFunc := func(pval *plistValue) error { - if err := e.writePlistValue(pval); err != nil { - return err - } - return nil - } - err = e.writeElement("plist", pval, tokenFunc) - if err != nil { - return err + if e.indent != "" { + e.write([]byte("\n")) } - // newline at the end of a plist document - _, err = e.writer.Write([]byte("\n")) - if err != nil { - return err - } - return nil + e.write([]byte(plistEnd)) + e.write([]byte("\n")) + return e.err } func (e *xmlEncoder) writePlistValue(pval *plistValue) error { @@ -108,15 +103,11 @@ func (e *xmlEncoder) writeElement(name string, pval *plistValue, valFunc func(*p Name: xml.Name{ Space: "", Local: name, - }} - - if name == "plist" { - startElement.Attr = []xml.Attr{{ - Name: xml.Name{ - Space: "", - Local: "version"}, - Value: "1.0"}, - } + }, + } + + if name == "dict" || name == "array" { + e.indentCount++ } // Encode xml.StartElement token @@ -139,6 +130,10 @@ func (e *xmlEncoder) writeElement(name string, pval *plistValue, valFunc func(*p return err } + if name == "dict" || name == "array" { + e.indentCount-- + } + // flush return e.Flush() } @@ -147,11 +142,20 @@ func (e *xmlEncoder) writeArrayValue(pval *plistValue) error { tokenFunc := func(pval *plistValue) error { encodedValue := pval.value values := encodedValue.([]*plistValue) + wroteBool := false for _, v := range values { + if !wroteBool { + wroteBool = v.kind == Boolean + } if err := e.writePlistValue(v); err != nil { return err } } + + if e.indent != "" && wroteBool { + e.writer.Write([]byte("\n")) + e.writer.Write([]byte(e.indent)) + } return nil } return e.writeElement("array", pval, tokenFunc) @@ -214,11 +218,14 @@ func (e *xmlEncoder) writeBoolValue(pval *plistValue) error { // EncodeElement results in instead of // use writer to write self closing tags b := pval.value.(bool) - _, err := e.writer.Write([]byte(fmt.Sprintf("<%t/>", b))) - if err != nil { - return err + if e.indent != "" { + e.write([]byte("\n")) + for i := 0; i < e.indentCount; i++ { + e.write([]byte(e.indent)) + } } - return nil + e.write([]byte(fmt.Sprintf("<%t/>", b))) + return e.err } func (e *xmlEncoder) writeIntegerValue(pval *plistValue) error {