Skip to content

Commit

Permalink
resolve indentint issues
Browse files Browse the repository at this point in the history
Does not indent the first value after plist.
Indents and un-indents self closing bools.
  • Loading branch information
groob committed Apr 25, 2020
1 parent 0f631f2 commit fa697fc
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 63 deletions.
1 change: 1 addition & 0 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
59 changes: 40 additions & 19 deletions encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package plist

import (
"bytes"
"io/ioutil"
"testing"
"time"
)
Expand Down Expand Up @@ -79,23 +80,35 @@ var dictRef = `<?xml version="1.0" encoding="UTF-8"?>
var indentRef = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>band-size</key>
<integer>8388608</integer>
<key>bundle-backingstore-version</key>
<integer>1</integer>
<key>diskimage-bundle-type</key>
<string>com.apple.diskimage.sparsebundle</string>
<key>size</key>
<integer>4398046511104</integer>
<key>useless</key>
<dict>
<key>unused-string</key>
<string>unused</string>
</dict>
</dict>
<dict>
<key>Boolean</key>
<true/>
<key>BooleanList</key>
<array>
<true/>
<false/>
</array>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>Strings</key>
<array>
<string>a</string>
<string>b</string>
</array>
<key>band-size</key>
<integer>8388608</integer>
<key>bundle-backingstore-version</key>
<integer>1</integer>
<key>diskimage-bundle-type</key>
<string>com.apple.diskimage.sparsebundle</string>
<key>size</key>
<integer>4398046511104</integer>
<key>useless</key>
<dict>
<key>unused-string</key>
<string>unused</string>
</dict>
</dict>
</plist>
`

Expand Down Expand Up @@ -202,21 +215,29 @@ 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,
Size: 4 * 1048576 * 1024 * 1024,
DiskImageBundleType: "com.apple.diskimage.sparsebundle",
BackingStoreVersion: 1,
Unused: testStruct{"unused"},
Boolean: true,
BooleanList: []bool{true, false},
Strings: []string{"a", "b"},
}
b, err := MarshalIndent(sparseBundleHeader, " ")
b, err := MarshalIndent(sparseBundleHeader, " ")
if err != nil {
t.Fatal(err)
}
out := string(b)
if out != indentRef {
t.Errorf("MarshalIndent(%v) = \n%v, \nwant\n %v", sparseBundleHeader, out, indentRef)
ioutil.WriteFile("out", b, 0777)
ioutil.WriteFile("want", []byte(indentRef), 0777)
t.Errorf("MarshalIndent(%v) = \n%v, \nwant\n%v", sparseBundleHeader, out, indentRef)
}
}

Expand Down
95 changes: 51 additions & 44 deletions xml_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,52 +11,47 @@ import (
)

const xmlDOCTYPE = `<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">`
const plistStart = `<plist version="1.0">`
const plistEnd = `</plist>`

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
// <plist> 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 {
Expand Down Expand Up @@ -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
Expand All @@ -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()
}
Expand All @@ -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)
Expand Down Expand Up @@ -214,11 +218,14 @@ func (e *xmlEncoder) writeBoolValue(pval *plistValue) error {
// EncodeElement results in <true></true> instead of <true/>
// 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 {
Expand Down

0 comments on commit fa697fc

Please sign in to comment.